# Update admin quorum threshold
Source: https://developers.fireblocks.com/api-reference/admin-quorum/update-admin-quorum-threshold
https://docs.fireblocks.com/api/v1/swagger.yaml put /admin_quorum
Update admin quorum threshold
# Create API Key
Source: https://developers.fireblocks.com/api-reference/api-user/create-api-key
https://docs.fireblocks.com/api/v1/swagger.yaml post /management/api_users
Create a new API key in your workspace.
Learn more about Fireblocks API Keys management in the following [guide](https://developers.fireblocks.com/docs/manage-api-keys).
Endpoint Permission: Admin, Non-Signing Admin.
# Get API Keys
Source: https://developers.fireblocks.com/api-reference/api-user/get-api-keys
https://docs.fireblocks.com/api/v1/swagger.yaml get /management/api_users
List all API keys in your workspace.
- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.
Endpoint Permission: Admin, Non-Signing Admin.
# Get audit logs
Source: https://developers.fireblocks.com/api-reference/audit-logs/get-audit-logs
https://docs.fireblocks.com/api/v1/swagger.yaml get /management/audit_logs
Get Audit logs for the last Day/Week.
- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.
Endpoint Permission: Admin, Non-Signing Admin.
# Get a Blockchain by ID
Source: https://developers.fireblocks.com/api-reference/blockchains-&-assets/get-a-blockchain-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /blockchains/{id}
Returns a blockchain by ID or legacyID.
# Get an asset
Source: https://developers.fireblocks.com/api-reference/blockchains-&-assets/get-an-asset
https://docs.fireblocks.com/api/v1/swagger.yaml get /assets/{id}
Returns an asset by ID or legacyID.
**Note**:
- We will continue displaying and supporting the legacy ID (API ID). Since not all Fireblocks services fully support the new Assets UUID, please use only the legacy ID until further notice.
# List assets
Source: https://developers.fireblocks.com/api-reference/blockchains-&-assets/list-assets
https://docs.fireblocks.com/api/v1/swagger.yaml get /assets
Retrieves a paginated list of all assets supported by Fireblocks in your workspace
**Note:** We will continue to support and display the legacy ID (API ID). Since not all Fireblocks services fully support the new Assets UUID, please use only the legacy ID until further notice.
# List assets (Legacy)
Source: https://developers.fireblocks.com/api-reference/blockchains-&-assets/list-assets-legacy
https://docs.fireblocks.com/api/v1/swagger.yaml get /supported_assets
**This legacy endpoint has not been deprecated but it should not be used in your operations. Instead, use the new [List assets](https://developers.fireblocks.com/reference/listassets) endpoint for better performance and to retrieve more detailed asset information.**
Retrieves all assets supported by Fireblocks in your workspace.
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor.
# List blockchains
Source: https://developers.fireblocks.com/api-reference/blockchains-&-assets/list-blockchains
https://docs.fireblocks.com/api/v1/swagger.yaml get /blockchains
Returns all blockchains supported by Fireblocks.
# Register an asset
Source: https://developers.fireblocks.com/api-reference/blockchains-&-assets/register-an-asset
https://docs.fireblocks.com/api/v1/swagger.yaml post /assets
Register a new asset to a workspace and return the newly created asset's details. Currently supported chains are:
- EVM based chains
- Stellar
- Algorand
- TRON
- NEAR
- Solana
- Sui
- TON
# Set asset price
Source: https://developers.fireblocks.com/api-reference/blockchains-&-assets/set-asset-price
https://docs.fireblocks.com/api/v1/swagger.yaml post /assets/prices/{id}
Set asset price for the given asset id. Returns the asset price response.
# Update the user’s metadata for an asset
Source: https://developers.fireblocks.com/api-reference/blockchains-&-assets/update-the-user’s-metadata-for-an-asset
https://docs.fireblocks.com/api/v1/swagger.yaml patch /assets/{id}
Update the user’s metadata for an asset.
Endpoint Permission: Owner, Admin, Non-Signing Admin, NCW Admin, Signer, Editor.
# Get AML Screening Policy Configuration
Source: https://developers.fireblocks.com/api-reference/compliance-screening-configuration/get-aml-screening-policy-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/aml/policy_configuration
Retrieves the configuration for Travel Rule screening policy.
# Get Travel Rule Screening Policy Configuration
Source: https://developers.fireblocks.com/api-reference/compliance-screening-configuration/get-travel-rule-screening-policy-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/travel_rule/policy_configuration
Retrieves the configuration for Travel Rule screening policy.
# Activate BYORK Light
Source: https://developers.fireblocks.com/api-reference/compliance/activate-byork-light
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/byork/config/activate
Activates BYORK Light for the authenticated tenant (sets config.active to true). Once activated, BYORK screening applies to matching transactions. Requires BYORK Light to be enabled for the tenant (contact your CSM to enable).
# Add vault accounts to the address registry opt-out list
Source: https://developers.fireblocks.com/api-reference/compliance/add-vault-accounts-to-the-address-registry-opt-out-list
https://docs.fireblocks.com/api/v1/swagger.yaml post /address_registry/vaults
Adds one or more vault account ids to the workspace opt-out list for the address registry.
# AML - View Post-Screening Policy
Source: https://developers.fireblocks.com/api-reference/compliance/aml--view-post-screening-policy
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/aml/post_screening_policy
Get the post-screening policy for AML.
# AML - View Screening Policy
Source: https://developers.fireblocks.com/api-reference/compliance/aml--view-screening-policy
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/aml/screening_policy
Get the screening policy for AML.
# Assign vault accounts to a legal entity
Source: https://developers.fireblocks.com/api-reference/compliance/assign-vault-accounts-to-a-legal-entity
https://docs.fireblocks.com/api/v1/swagger.yaml post /legal_entities/{legalEntityId}/vaults
Assigns one or more vault accounts to a specific legal entity registration. Explicitly mapped vault accounts take precedence over the workspace default legal entity.
Endpoint Permission: Admin, Non-Signing Admin.
# Calling the "Bypass Screening Policy" API endpoint triggers a new transaction, with the API user as the initiator, bypassing the screening policy check
Source: https://developers.fireblocks.com/api-reference/compliance/calling-the-"bypass-screening-policy"-api-endpoint-triggers-a-new-transaction-with-the-api-user-as-the-initiator-bypassing-the-screening-policy-check
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/transaction/{txId}/bypass_screening_policy
This endpoint is restricted to Admin API users and is only applicable to outgoing transactions.
# Create a counterparty group
Source: https://developers.fireblocks.com/api-reference/compliance/create-a-counterparty-group
https://docs.fireblocks.com/api/v1/swagger.yaml post /counterparty_groups
Creates a new counterparty group.
**Endpoint Permissions:** Admin, Non-Signing Admin.
# Deactivate BYORK Light
Source: https://developers.fireblocks.com/api-reference/compliance/deactivate-byork-light
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/byork/config/deactivate
Deactivates BYORK Light for the authenticated tenant (sets config.active to false). Once deactivated, BYORK screening no longer applies until activated again. Requires BYORK Light to be enabled for the tenant (contact your CSM to enable).
# Delete a counterparty group
Source: https://developers.fireblocks.com/api-reference/compliance/delete-a-counterparty-group
https://docs.fireblocks.com/api/v1/swagger.yaml delete /counterparty_groups/{groupId}
Permanently deletes a counterparty group.
**Endpoint Permissions:** Admin, Non-Signing Admin.
# Get a counterparty group
Source: https://developers.fireblocks.com/api-reference/compliance/get-a-counterparty-group
https://docs.fireblocks.com/api/v1/swagger.yaml get /counterparty_groups/{groupId}
Returns the details of a specific counterparty group.
**Endpoint Permissions:** Admin, Non-Signing Admin, Viewer.
# Get a legal entity
Source: https://developers.fireblocks.com/api-reference/compliance/get-a-legal-entity
https://docs.fireblocks.com/api/v1/swagger.yaml get /legal_entities/{legalEntityId}
Returns details of a specific legal entity registration, including GLEIF data when available.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get address registry participation status for the authenticated workspace
Source: https://developers.fireblocks.com/api-reference/compliance/get-address-registry-participation-status-for-the-authenticated-workspace
https://docs.fireblocks.com/api/v1/swagger.yaml get /address_registry/tenant
Returns whether the workspace is `OPTED_IN` or `OPTED_OUT` of the address registry.
# Get BYORK Light configuration
Source: https://developers.fireblocks.com/api-reference/compliance/get-byork-light-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/byork/config
Retrieves BYORK Light configuration for the authenticated tenant (timeouts, active flag, allowed timeout ranges). Returns default config when none exists. Requires BYORK Light to be enabled for the tenant.
# Get BYORK Light verdict
Source: https://developers.fireblocks.com/api-reference/compliance/get-byork-light-verdict
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/byork/verdict
Returns the current BYORK verdict and status for a transaction. Status can be PRE_ACCEPTED, PENDING, RECEIVED (verdict is final but processing not yet complete), or COMPLETED. Requires BYORK Light to be enabled for the tenant. Returns 404 if no BYORK verdict is found for the transaction.
# Get whether a vault account is opted out of the address registry
Source: https://developers.fireblocks.com/api-reference/compliance/get-whether-a-vault-account-is-opted-out-of-the-address-registry
https://docs.fireblocks.com/api/v1/swagger.yaml get /address_registry/vaults/{vaultAccountId}
Returns whether this vault account is on the workspace opt-out list (`optedOut` true or false). List, add, and clear-all are available on `/v1/address_registry/vaults`; this path reads or removes one vault.
# List counterparty groups
Source: https://developers.fireblocks.com/api-reference/compliance/list-counterparty-groups
https://docs.fireblocks.com/api/v1/swagger.yaml get /counterparty_groups
Returns a paginated list of counterparty groups.
**Endpoint Permissions:** Admin, Non-Signing Admin, Viewer.
# List legal entities (Paginated)
Source: https://developers.fireblocks.com/api-reference/compliance/list-legal-entities-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /legal_entities
Returns legal entity registrations for the workspace with cursor-based pagination.
If query parameter vaultAccountId is used it returns the legal entity registration associated with a specific vault account. If no explicit mapping exists for the vault, the workspace default legal entity is returned. Returns an empty response if neither a vault mapping nor a default legal entity is configured.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# List vault accounts for a legal entity (Paginated)
Source: https://developers.fireblocks.com/api-reference/compliance/list-vault-accounts-for-a-legal-entity-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /legal_entities/{legalEntityId}/vaults
Returns vault account IDs explicitly assigned to a specific legal entity registration, with cursor-based pagination.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# List vault-level address registry opt-outs (paginated)
Source: https://developers.fireblocks.com/api-reference/compliance/list-vault-level-address-registry-opt-outs-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /address_registry/vaults
Lists vault accounts that are opted out of the address registry for this workspace. Pagination uses `next` and `prev` cursors from the response. If `pageSize` is omitted, **50** items are returned per page; allowed range is **1–100** per request.
# Look up legal entity by blockchain address
Source: https://developers.fireblocks.com/api-reference/compliance/look-up-legal-entity-by-blockchain-address
https://docs.fireblocks.com/api/v1/swagger.yaml get /address_registry/legal_entities/{address}
Returns legal entity information for the given blockchain address (verification status, LEI, Travel Rule providers, contact email, and related fields — see response schema). URL-encode `{address}` when required.
# Opt the workspace in to the address registry
Source: https://developers.fireblocks.com/api-reference/compliance/opt-the-workspace-in-to-the-address-registry
https://docs.fireblocks.com/api/v1/swagger.yaml post /address_registry/tenant
Opts the workspace in. No request body. Response uses the same JSON shape as GET; status is OPTED_IN.
# Opt the workspace out of the address registry
Source: https://developers.fireblocks.com/api-reference/compliance/opt-the-workspace-out-of-the-address-registry
https://docs.fireblocks.com/api/v1/swagger.yaml delete /address_registry/tenant
Opts the workspace out. No request body. Response uses the same JSON shape as GET; status is OPTED_OUT.
# Provides all the compliance details for the given screened transaction.
Source: https://developers.fireblocks.com/api-reference/compliance/provides-all-the-compliance-details-for-the-given-screened-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/transaction/{txId}
Provides all the compliance details for the given screened transaction.
# Register a new legal entity
Source: https://developers.fireblocks.com/api-reference/compliance/register-a-new-legal-entity
https://docs.fireblocks.com/api/v1/swagger.yaml post /legal_entities
Registers a new legal entity for the workspace using its LEI (Legal Entity Identifier) code. The LEI is validated against the GLEIF registry. Each workspace can register multiple legal entities.
Endpoint Permission: Admin, Non-Signing Admin.
# Remove a single vault account from the address registry opt-out list
Source: https://developers.fireblocks.com/api-reference/compliance/remove-a-single-vault-account-from-the-address-registry-opt-out-list
https://docs.fireblocks.com/api/v1/swagger.yaml delete /address_registry/vaults/{vaultAccountId}
Removes this vault account id from the workspace opt-out list if it is present; otherwise the call still succeeds. Response body matches GET (`optedOut` is `false` after success). To clear the whole list, use `DELETE /v1/address_registry/vaults`.
# Remove all vault-level address registry opt-outs for the workspace
Source: https://developers.fireblocks.com/api-reference/compliance/remove-all-vault-level-address-registry-opt-outs-for-the-workspace
https://docs.fireblocks.com/api/v1/swagger.yaml delete /address_registry/vaults
Removes all vault accounts from the workspace opt-out list.
# Set AML Verdict (BYORK Super Light)
Source: https://developers.fireblocks.com/api-reference/compliance/set-aml-verdict-byork-super-light
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/aml/verdict/manual
Set AML verdict for incoming transactions when **BYORK Super Light** (Manual Screening Verdict) is enabled. This endpoint is for Super Light only. For **BYORK Light**, use POST /screening/byork/verdict instead. When Super Light is retired, this endpoint will be deprecated; use the BYORK Light verdict API for new integrations.
# Set BYORK Light timeouts
Source: https://developers.fireblocks.com/api-reference/compliance/set-byork-light-timeouts
https://docs.fireblocks.com/api/v1/swagger.yaml put /screening/byork/config/timeouts
Updates timeout values for BYORK wait-for-response (incoming and/or outgoing). At least one of incomingTimeoutSeconds or outgoingTimeoutSeconds is required. Values must be within the ranges returned in GET config (timeoutRangeIncoming for incomingTimeoutSeconds, timeoutRangeOutgoing for outgoingTimeoutSeconds). Requires BYORK Light to be enabled for the tenant (contact your CSM to enable).
# Set BYORK Light verdict
Source: https://developers.fireblocks.com/api-reference/compliance/set-byork-light-verdict
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/byork/verdict
Submit verdict (ACCEPT or REJECT) for a transaction in the BYORK Light flow. If the transaction is awaiting your decision, the verdict is applied immediately (response status COMPLETED). If processing has not yet reached that point, the verdict is stored and applied when it does (response status PRE_ACCEPTED). Requires BYORK Light to be enabled for the tenant.
# Tenant - Screening Configuration
Source: https://developers.fireblocks.com/api-reference/compliance/tenant--screening-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml put /screening/configurations
Update tenant screening configuration.
# Travel Rule - View Post-Screening Policy
Source: https://developers.fireblocks.com/api-reference/compliance/travel-rule--view-post-screening-policy
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/travel_rule/post_screening_policy
Get the post-screening policy for Travel Rule.
# Travel Rule - View Screening Policy
Source: https://developers.fireblocks.com/api-reference/compliance/travel-rule--view-screening-policy
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/travel_rule/screening_policy
Get the screening policy for Travel Rule.
# Update a counterparty group
Source: https://developers.fireblocks.com/api-reference/compliance/update-a-counterparty-group
https://docs.fireblocks.com/api/v1/swagger.yaml patch /counterparty_groups/{groupId}
Updates an existing counterparty group.
**Endpoint Permissions:** Admin, Non-Signing Admin.
# Update AML Configuration
Source: https://developers.fireblocks.com/api-reference/compliance/update-aml-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml put /screening/aml/policy_configuration
Updates bypass screening, inbound delay, or outbound delay configurations for AML.
# Update legal entity
Source: https://developers.fireblocks.com/api-reference/compliance/update-legal-entity
https://docs.fireblocks.com/api/v1/swagger.yaml put /legal_entities/{legalEntityId}
Updates the status of a legal entity registration. Setting isDefault to true marks the registration as the workspace default, which is applied to vault accounts that have no explicit legal entity mapping.
Endpoint Permission: Admin, Non-Signing Admin.
# Update Travel Rule Configuration
Source: https://developers.fireblocks.com/api-reference/compliance/update-travel-rule-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml put /screening/travel_rule/policy_configuration
Updates bypass screening, inbound delay, or outbound delay configurations for Travel Rule.
# Disconnect connected account
Source: https://developers.fireblocks.com/api-reference/connected-accounts-beta/disconnect-connected-account
https://docs.fireblocks.com/api/v1/swagger.yaml delete /connected_accounts/{accountId}
Disconnect a connected account by ID.
**Note**:
- This endpoint is currently in beta and might be subject to changes.
# Get balances for an account
Source: https://developers.fireblocks.com/api-reference/connected-accounts-beta/get-balances-for-an-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /connected_accounts/{accountId}/balances
Retrieve current asset balances for a specific connected account as a flat list (one row per `assetId`, `balanceType`).
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get connected account
Source: https://developers.fireblocks.com/api-reference/connected-accounts-beta/get-connected-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /connected_accounts/{accountId}
Retrieve detailed information about a specific connected account by ID.
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get connected accounts
Source: https://developers.fireblocks.com/api-reference/connected-accounts-beta/get-connected-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml get /connected_accounts
Returns all connected accounts.
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get exchange rates for an account
Source: https://developers.fireblocks.com/api-reference/connected-accounts-beta/get-exchange-rates-for-an-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /connected_accounts/{accountId}/rates
Retrieve current exchange rates for converting between specific assets in a connected account.
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get supported trading pairs for an account
Source: https://developers.fireblocks.com/api-reference/connected-accounts-beta/get-supported-trading-pairs-for-an-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /connected_accounts/{accountId}/manifest/capabilities/trading/pairs
Retrieve all asset trading pairs supported by a specific connected account, including the pair type (`quote`, `market`, `onOffRamp`).
**Note:** This endpoint is currently in beta and might be subject to changes.
# Rename Connected Account
Source: https://developers.fireblocks.com/api-reference/connected-accounts-beta/rename-connected-account
https://docs.fireblocks.com/api/v1/swagger.yaml post /connected_accounts/{accountId}/rename
Rename a connected account by account ID.
**Note:** This endpoint is currently in beta and might be subject to changes.
# Create console user
Source: https://developers.fireblocks.com/api-reference/console-user/create-console-user
https://docs.fireblocks.com/api/v1/swagger.yaml post /management/users
Create console users in your workspace
- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.
Learn more about Fireblocks Users management in the following [guide](https://developers.fireblocks.com/docs/manage-users).
Endpoint Permission: Admin, Non-Signing Admin.
# Get console users
Source: https://developers.fireblocks.com/api-reference/console-user/get-console-users
https://docs.fireblocks.com/api/v1/swagger.yaml get /management/users
Get console users for your workspace.
- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.
Endpoint Permission: Admin, Non-Signing Admin.
# Call a read function on a deployed contract
Source: https://developers.fireblocks.com/api-reference/contract-interactions/call-a-read-function-on-a-deployed-contract
https://docs.fireblocks.com/api/v1/swagger.yaml post /contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions/read
Call a read function on a deployed contract by blockchain native asset id and contract address
# Call a write function on a deployed contract
Source: https://developers.fireblocks.com/api-reference/contract-interactions/call-a-write-function-on-a-deployed-contract
https://docs.fireblocks.com/api/v1/swagger.yaml post /contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions/write
Call a write function on a deployed contract by blockchain native asset id and contract address. This creates an onchain transaction, thus it is an async operation. It returns a transaction id that can be polled for status check
# Decode a function call data, error, or event log
Source: https://developers.fireblocks.com/api-reference/contract-interactions/decode-a-function-call-data-error-or-event-log
https://docs.fireblocks.com/api/v1/swagger.yaml post /contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/decode
Decode a function call data, error, or event log from a deployed contract by blockchain native asset id and contract address.
# Get contract address by transaction hash
Source: https://developers.fireblocks.com/api-reference/contract-interactions/get-contract-address-by-transaction-hash
https://docs.fireblocks.com/api/v1/swagger.yaml get /contract_interactions/base_asset_id/{baseAssetId}/tx_hash/{txHash}
Retrieve the contract address by blockchain native asset ID and transaction hash
# Get transaction receipt
Source: https://developers.fireblocks.com/api-reference/contract-interactions/get-transaction-receipt
https://docs.fireblocks.com/api/v1/swagger.yaml get /contract_interactions/base_asset_id/{baseAssetId}/tx_hash/{txHash}/receipt
Retrieve the transaction receipt by blockchain native asset ID and transaction hash
> **Note** > This functionality is exclusively available for EVM (Ethereum Virtual Machine) compatible chains.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, and Viewer.
# Return deployed contract's ABI
Source: https://developers.fireblocks.com/api-reference/contract-interactions/return-deployed-contracts-abi
https://docs.fireblocks.com/api/v1/swagger.yaml get /contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions
Return deployed contract's ABI by blockchain native asset id and contract address.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, and Viewer.
# Delete a contract template by id
Source: https://developers.fireblocks.com/api-reference/contract-templates/delete-a-contract-template-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml delete /tokenization/templates/{contractTemplateId}
Delete a contract by id. allowed only for private contract templates. Notice: it is irreversible!
# Deploy contract
Source: https://developers.fireblocks.com/api-reference/contract-templates/deploy-contract
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/templates/{contractTemplateId}/deploy
Deploy a new contract by contract template id. If you wish to deploy a token (ERC20, ERC721 etc), and create asset please use POST /tokenization
# Get supported blockchains for the template
Source: https://developers.fireblocks.com/api-reference/contract-templates/get-supported-blockchains-for-the-template
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/templates/{contractTemplateId}/supported_blockchains
Get supported blockchains for the template
# List all contract templates
Source: https://developers.fireblocks.com/api-reference/contract-templates/list-all-contract-templates
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/templates
Return minimal representation of all the contract templates available for the workspace.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Return contract template by id
Source: https://developers.fireblocks.com/api-reference/contract-templates/return-contract-template-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/templates/{contractTemplateId}
Return detailed information about the contract template
# Return contract template's constructor
Source: https://developers.fireblocks.com/api-reference/contract-templates/return-contract-templates-constructor
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/templates/{contractTemplateId}/constructor
Return contract template's constructor ABI
# Return contract template's function
Source: https://developers.fireblocks.com/api-reference/contract-templates/return-contract-templates-function
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/templates/{contractTemplateId}/function
Return contract template`s function ABI by signature
# Upload contract template
Source: https://developers.fireblocks.com/api-reference/contract-templates/upload-contract-template
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/templates
Upload a new contract template. This contract template will be available for the workspace
# Add a contract
Source: https://developers.fireblocks.com/api-reference/contracts/add-a-contract
https://docs.fireblocks.com/api/v1/swagger.yaml post /contracts
Adds a contract to the workspace whitelist. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Add an asset to a whitelisted contract
Source: https://developers.fireblocks.com/api-reference/contracts/add-an-asset-to-a-whitelisted-contract
https://docs.fireblocks.com/api/v1/swagger.yaml post /contracts/{contractId}/{assetId}
Adds an asset to a whitelisted contract. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Delete a contract
Source: https://developers.fireblocks.com/api-reference/contracts/delete-a-contract
https://docs.fireblocks.com/api/v1/swagger.yaml delete /contracts/{contractId}
Deletes a contract by ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Delete an asset from a whitelisted contract
Source: https://developers.fireblocks.com/api-reference/contracts/delete-an-asset-from-a-whitelisted-contract
https://docs.fireblocks.com/api/v1/swagger.yaml delete /contracts/{contractId}/{assetId}
Deletes a whitelisted contract asset by ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Find a Specific Whitelisted Contract
Source: https://developers.fireblocks.com/api-reference/contracts/find-a-specific-whitelisted-contract
https://docs.fireblocks.com/api/v1/swagger.yaml get /contracts/{contractId}
Returns a whitelisted contract by Fireblocks Contract ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Find a whitelisted contract's asset
Source: https://developers.fireblocks.com/api-reference/contracts/find-a-whitelisted-contracts-asset
https://docs.fireblocks.com/api/v1/swagger.yaml get /contracts/{contractId}/{assetId}
Returns a whitelisted contract's asset by ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# List Whitelisted Contracts
Source: https://developers.fireblocks.com/api-reference/contracts/list-whitelisted-contracts
https://docs.fireblocks.com/api/v1/swagger.yaml get /contracts
Gets a list of whitelisted contracts. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Add cosigner
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/add-cosigner
https://docs.fireblocks.com/api/v1/swagger.yaml post /cosigners
Add a new cosigner. The cosigner will be pending pairing until the API key is manually paired
Endpoint Permission: Admin and Non-Signing Admin.
# Get all API keys
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/get-all-api-keys
https://docs.fireblocks.com/api/v1/swagger.yaml get /cosigners/{cosignerId}/api_keys
Get all cosigner paired API keys (paginated).
**Note:** These endpoints are currently in beta and might be subject to changes.
Endpoint Permission: Admin and Non-Signing Admin.
# Get all cosigners
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/get-all-cosigners
https://docs.fireblocks.com/api/v1/swagger.yaml get /cosigners
Get all workspace cosigners (paginated).
**Note:** These endpoints are currently in beta and might be subject to changes.
Endpoint Permission: Admin and Non-Signing Admin.
# Get API key
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/get-api-key
https://docs.fireblocks.com/api/v1/swagger.yaml get /cosigners/{cosignerId}/api_keys/{apiKeyId}
Get an API key by ID.
**Note:** These endpoints are currently in beta and might be subject to changes.
Endpoint Permission: Admin and Non-Signing Admin.
# Get cosigner
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/get-cosigner
https://docs.fireblocks.com/api/v1/swagger.yaml get /cosigners/{cosignerId}
Get a cosigner by ID.
**Note:** These endpoints are currently in beta and might be subject to changes.
Endpoint Permission: Admin and Non-Signing Admin.
# Get request status
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/get-request-status
https://docs.fireblocks.com/api/v1/swagger.yaml get /cosigners/{cosignerId}/api_keys/{apiKeyId}/{requestId}
Get the status of an asynchronous request
Endpoint Permission: Admin and Non-Signing Admin.
# Pair API key
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/pair-api-key
https://docs.fireblocks.com/api/v1/swagger.yaml put /cosigners/{cosignerId}/api_keys/{apiKeyId}
Pair an API key to a cosigner
Endpoint Permission: Admin and Non-Signing Admin.
# Rename cosigner
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/rename-cosigner
https://docs.fireblocks.com/api/v1/swagger.yaml patch /cosigners/{cosignerId}
Rename a cosigner by ID.
**Note:** These endpoints are currently in beta and might be subject to changes.
Endpoint Permission: Admin and Non-Signing Admin.
# Unpair API key
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/unpair-api-key
https://docs.fireblocks.com/api/v1/swagger.yaml delete /cosigners/{cosignerId}/api_keys/{apiKeyId}
Unpair an API key from a cosigner
Endpoint Permission: Admin and Non-Signing Admin.
# Update API key callback handler
Source: https://developers.fireblocks.com/api-reference/cosigners-beta/update-api-key-callback-handler
https://docs.fireblocks.com/api/v1/swagger.yaml patch /cosigners/{cosignerId}/api_keys/{apiKeyId}
Update the callback handler of an API key
Endpoint Permission: Admin and Non-Signing Admin.
# Fetch the contract ABI
Source: https://developers.fireblocks.com/api-reference/deployed-contracts/fetch-the-contract-abi
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/contracts/fetch_abi
Fetch the ABI. If not found fetch the ABI from the block explorer
# List deployed contracts data
Source: https://developers.fireblocks.com/api-reference/deployed-contracts/list-deployed-contracts-data
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/contracts
Return a filtered lean representation of the deployed contracts data on all blockchains (paginated)
# Return deployed contract data
Source: https://developers.fireblocks.com/api-reference/deployed-contracts/return-deployed-contract-data
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/contracts/{assetId}/{contractAddress}
Return deployed contract data by blockchain native asset id and contract address
# Return deployed contract data by id
Source: https://developers.fireblocks.com/api-reference/deployed-contracts/return-deployed-contract-data-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/contracts/{id}
Return deployed contract data by id
# Save contract ABI
Source: https://developers.fireblocks.com/api-reference/deployed-contracts/save-contract-abi
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/contracts/abi
Save contract ABI for the tenant
# Approve earn provider terms of service
Source: https://developers.fireblocks.com/api-reference/earn-beta/approve-earn-provider-terms-of-service
https://docs.fireblocks.com/api/v1/swagger.yaml post /earn/providers/{providerId}/approve_terms_of_service
Approves the lending provider's terms of service for this workspace. When
`isTermsApprovalRequired` is true on the provider (see list providers),
call this once before creating or executing earn actions with that provider.
After success, `GET /earn/providers` reflects `isTermsOfServiceApproved`.
**Note:** This endpoint is currently in beta and might be subject to changes.
# Create and execute a lending action (deposit or withdraw)
Source: https://developers.fireblocks.com/api-reference/earn-beta/create-and-execute-a-lending-action-deposit-or-withdraw
https://docs.fireblocks.com/api/v1/swagger.yaml post /earn/actions
Creates and runs a sequence of on-chain steps for either a deposit into or a withdrawal from an earn
vault/market. Specify the operation with `action` in the request body (`DEPOSIT` or `WITHDRAW`).
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get a single earn lending action
Source: https://developers.fireblocks.com/api-reference/earn-beta/get-a-single-earn-lending-action
https://docs.fireblocks.com/api/v1/swagger.yaml get /earn/actions/{id}
Returns one lending action by its action sequence id (tenant-scoped).
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get list of earn opportunities
Source: https://developers.fireblocks.com/api-reference/earn-beta/get-list-of-earn-opportunities
https://docs.fireblocks.com/api/v1/swagger.yaml get /earn/opportunities
Get list of earn opportunities (vaults).
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get list of earn positions
Source: https://developers.fireblocks.com/api-reference/earn-beta/get-list-of-earn-positions
https://docs.fireblocks.com/api/v1/swagger.yaml get /earn/positions
Get list of earn positions for accounts tracked for this workspace.
Optional query parameters filter by chain, provider, and pagination.
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get list of earn providers
Source: https://developers.fireblocks.com/api-reference/earn-beta/get-list-of-earn-providers
https://docs.fireblocks.com/api/v1/swagger.yaml get /earn/providers
Get list of earn providers.
**Note:** This endpoint is currently in beta and might be subject to changes.
# List earn lending actions
Source: https://developers.fireblocks.com/api-reference/earn-beta/list-earn-lending-actions
https://docs.fireblocks.com/api/v1/swagger.yaml get /earn/actions
Returns a paginated list of lending actions (deposits and withdrawals) for the authenticated tenant.
**Note:** This endpoint is currently in beta and might be subject to changes.
# Add asset to account
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/add-asset-to-account
https://docs.fireblocks.com/api/v1/swagger.yaml post /ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}
Get the addresses of a specific asset, under a specific account, under a specific Non Custodial Wallet
# Assign a wallet
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/assign-a-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /ncw/wallets/{walletId}/assign
Assign a specific Non Custodial Wallet to a user
# Create a new account
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/create-a-new-account
https://docs.fireblocks.com/api/v1/swagger.yaml post /ncw/wallets/{walletId}/accounts
Create a new account under a specific Non Custodial Wallet
# Create a new wallet
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/create-a-new-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /ncw/wallets
Create new Non Custodial Wallet
# Get a account
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-a-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/accounts/{accountId}
Get a specific account under a specific Non Custodial Wallet
# Get a wallet
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-a-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}
Get a wallet
# Get device key setup state
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-device-key-setup-state
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/devices/{deviceId}/setup_status
Get the state of the specific device setup key under a specific Non Custodial Wallet
# Get Embedded Wallet Device
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-embedded-wallet-device
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/devices/{deviceId}
Get specific device for a specific s Wallet
# Get registered devices - paginated
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-registered-devices--paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/devices_paginated
Get a paginated list of registered devices for a specific Non Custodial Wallet
# Get the public key for a derivation path
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-the-public-key-for-a-derivation-path
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/public_key_info
Gets the public key information based on derivation path and signing algorithm within a Non-Custodial Wallet
# Get the public key of an asset
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-the-public-key-of-an-asset
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/{change}/{addressIndex}/public_key_info
Gets the public key of an asset associated with a specific account within a Non-Custodial Wallet
# Get the public key of an asset
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-the-public-key-of-an-asset-1
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/{walletId}/accounts/{accountId}/{assetId}/{change}/{addressIndex}/public_key_info
Gets the public key of an asset associated with a specific account within a Non-Custodial Wallet
# Get wallet key setup state
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-wallet-key-setup-state
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/setup_status
Get the key setup state for a specific Non Custodial Wallet, including required algorithms and device setup status
# Get wallet Latest Backup details
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/get-wallet-latest-backup-details
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/backup/latest
Get wallet Latest Backup details, including the deviceId, and backup time
# List wallets
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/list-wallets
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets
Get all Non Custodial Wallets
# Refresh asset balance
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/refresh-asset-balance
https://docs.fireblocks.com/api/v1/swagger.yaml put /ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/balance
Refresh the balance of an asset in a specific account
# Retrieve asset
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/retrieve-asset
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}
Get asset under a specific account, under a specific Non Custodial Wallet
# Retrieve asset addresses
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/retrieve-asset-addresses
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/addresses
Get the addresses of a specific asset, under a specific account, under a specific Non Custodial Wallet
# Retrieve asset balance
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/retrieve-asset-balance
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/balance
Get balance for specific asset, under a specific account
# Retrieve assets
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/retrieve-assets
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/{walletId}/accounts/{accountId}/assets
Retrieve assets for a specific account under a specific Non Custodial Wallet
# Retrieve supported assets
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/retrieve-supported-assets
https://docs.fireblocks.com/api/v1/swagger.yaml get /ncw/wallets/supported_assets
Get all the available supported assets for the Non-Custodial Wallet
# Update device status
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/update-device-status
https://docs.fireblocks.com/api/v1/swagger.yaml patch /ncw/wallets/{walletId}/devices/{deviceId}/status
Update the enabled/disabled status of a specific device for a Non Custodial Wallet
# Update wallet status
Source: https://developers.fireblocks.com/api-reference/embedded-wallets/update-wallet-status
https://docs.fireblocks.com/api/v1/swagger.yaml patch /ncw/wallets/{walletId}/status
Update the enabled/disabled status of a specific Non Custodial Wallet
# Add an exchange account
Source: https://developers.fireblocks.com/api-reference/exchange-accounts/add-an-exchange-account
https://docs.fireblocks.com/api/v1/swagger.yaml post /exchange_accounts
Add an exchange account to exchanges.
Note: This endpoint currently only supports the following exchanges `INDEPENDENT_RESERVE`,`BIT`, `BITHUMB`, `BITSO`, `CRYPTOCOM`, `BYBIT_V2`, `WHITEBIT`, `HITBTC`, `GEMINI`, `HUOBI`, `GATEIO`, `COINHAKO`, `BULLISH`, `BITGET`, and `LUNO`
To add an exchange account, please use the following [guide](https://developers.fireblocks.com/docs/add-an-exchange-account).
# Convert exchange account funds
Source: https://developers.fireblocks.com/api-reference/exchange-accounts/convert-exchange-account-funds
https://docs.fireblocks.com/api/v1/swagger.yaml post /exchange_accounts/{exchangeAccountId}/convert
Convert exchange account funds from the source asset to the destination asset. Coinbase (USD to USDC, USDC to USD) and Bitso (MXN to USD) are supported conversions.
Learn more about Fireblocks Exchange Connectivity in the following [guide](https://developers.fireblocks.com/docs/connect-to-exchanges-and-fiat-providers).
Endpoint Permission: Admin, Non-Signing Admin.
# Get a specific exchange account
Source: https://developers.fireblocks.com/api-reference/exchange-accounts/get-a-specific-exchange-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /exchange_accounts/{exchangeAccountId}
Returns an exchange account by ID.
Endpoint Permission: Admin, Non-Signing Admin.
# Get an asset for an exchange account
Source: https://developers.fireblocks.com/api-reference/exchange-accounts/get-an-asset-for-an-exchange-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /exchange_accounts/{exchangeAccountId}/{assetId}
Returns an asset for an exchange account.
Endpoint Permission: Admin, Non-Signing Admin.
# Get public key to encrypt exchange credentials
Source: https://developers.fireblocks.com/api-reference/exchange-accounts/get-public-key-to-encrypt-exchange-credentials
https://docs.fireblocks.com/api/v1/swagger.yaml get /exchange_accounts/credentials_public_key
Return public key
# Internal transfer for exchange accounts
Source: https://developers.fireblocks.com/api-reference/exchange-accounts/internal-transfer-for-exchange-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml post /exchange_accounts/{exchangeAccountId}/internal_transfer
Transfers funds between trading accounts under the same exchange account.
Learn more about Fireblocks Exchange Connectivity in the following [guide](https://developers.fireblocks.com/docs/connect-to-exchanges-and-fiat-providers).
Endpoint Permission: Admin, Non-Signing Admin.
# List connected exchange accounts
Source: https://developers.fireblocks.com/api-reference/exchange-accounts/list-connected-exchange-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml get /exchange_accounts/paged
Returns a list of the connected exchange accounts in your workspace. Endpoint Permission: Admin, Non-Signing Admin.
# List exchange accounts
Source: https://developers.fireblocks.com/api-reference/exchange-accounts/list-exchange-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml get /exchange_accounts
DEPRECATED - Please use the `/exchange_accounts/paged` endpoint.
Endpoint Permission: Admin, Non-Signing Admin.
# Add an asset to an external wallet.
Source: https://developers.fireblocks.com/api-reference/external-wallets/add-an-asset-to-an-external-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /external_wallets/{walletId}/{assetId}
Adds an asset to an existing external wallet. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create an external wallet
Source: https://developers.fireblocks.com/api-reference/external-wallets/create-an-external-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /external_wallets
Creates a new external wallet with the requested name.
External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties.
- You cannot see the balance of the external wallet.
- You cannot initiate transactions from an external wallet as the source via Fireblocks.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Delete an asset from an external wallet
Source: https://developers.fireblocks.com/api-reference/external-wallets/delete-an-asset-from-an-external-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml delete /external_wallets/{walletId}/{assetId}
Deletes an external wallet asset by ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Delete an external wallet
Source: https://developers.fireblocks.com/api-reference/external-wallets/delete-an-external-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml delete /external_wallets/{walletId}
Deletes an external wallet by ID. External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Find an external wallet
Source: https://developers.fireblocks.com/api-reference/external-wallets/find-an-external-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml get /external_wallets/{walletId}
Returns an external wallet by ID. External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get an asset from an external wallet
Source: https://developers.fireblocks.com/api-reference/external-wallets/get-an-asset-from-an-external-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml get /external_wallets/{walletId}/{assetId}
Returns an external wallet by wallet ID and asset ID. External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# List external wallets
Source: https://developers.fireblocks.com/api-reference/external-wallets/list-external-wallets
https://docs.fireblocks.com/api/v1/swagger.yaml get /external_wallets
Gets a list of external wallets under the workspace.
External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties.
- You cannot see the balance of the external wallet.
- You cannot initiate transactions from an external wallet as the source via Fireblocks.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Set an AML customer reference ID for an external wallet
Source: https://developers.fireblocks.com/api-reference/external-wallets/set-an-aml-customer-reference-id-for-an-external-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /external_wallets/{walletId}/set_customer_ref_id
Sets an AML/KYT customer reference ID for the specific external wallet. External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Deposit funds from DDA
Source: https://developers.fireblocks.com/api-reference/fiat-accounts/deposit-funds-from-dda
https://docs.fireblocks.com/api/v1/swagger.yaml post /fiat_accounts/{accountId}/deposit_from_linked_dda
Deposits funds from the linked DDA.
# Find a specific fiat account
Source: https://developers.fireblocks.com/api-reference/fiat-accounts/find-a-specific-fiat-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /fiat_accounts/{accountId}
Returns a fiat account by ID.
Endpoint Permission: Admin, Non-Signing Admin.
# List fiat accounts
Source: https://developers.fireblocks.com/api-reference/fiat-accounts/list-fiat-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml get /fiat_accounts
Returns all fiat accounts.
Endpoint Permission: Admin, Non-Signing Admin.
# Redeem funds to DDA
Source: https://developers.fireblocks.com/api-reference/fiat-accounts/redeem-funds-to-dda
https://docs.fireblocks.com/api/v1/swagger.yaml post /fiat_accounts/{accountId}/redeem_to_linked_dda
Redeems funds to the linked DDA.
# Edit gas station settings
Source: https://developers.fireblocks.com/api-reference/gas-stations/edit-gas-station-settings
https://docs.fireblocks.com/api/v1/swagger.yaml put /gas_station/configuration
Configures gas station settings for ETH.
Learn more about the Fireblocks Gas Station in the following [guide](https://developers.fireblocks.com/docs/work-with-gas-station).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Edit gas station settings for an asset
Source: https://developers.fireblocks.com/api-reference/gas-stations/edit-gas-station-settings-for-an-asset
https://docs.fireblocks.com/api/v1/swagger.yaml put /gas_station/configuration/{assetId}
Configures gas station settings for a requested asset.
Learn more about the Fireblocks Gas Station in the following [guide](https://developers.fireblocks.com/docs/work-with-gas-station).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Get gas station settings
Source: https://developers.fireblocks.com/api-reference/gas-stations/get-gas-station-settings
https://docs.fireblocks.com/api/v1/swagger.yaml get /gas_station
Returns gas station settings and ETH balance.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Get gas station settings by asset
Source: https://developers.fireblocks.com/api-reference/gas-stations/get-gas-station-settings-by-asset
https://docs.fireblocks.com/api/v1/swagger.yaml get /gas_station/{assetId}
Returns gas station settings and balances for a requested asset.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Add an asset to an internal wallet
Source: https://developers.fireblocks.com/api-reference/internal-wallets/add-an-asset-to-an-internal-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /internal_wallets/{walletId}/{assetId}
Adds an asset to an existing internal wallet.
# Create an internal wallet
Source: https://developers.fireblocks.com/api-reference/internal-wallets/create-an-internal-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /internal_wallets
Creates a new internal wallet with the requested name.
Learn more about Whitelisted Internal Addresses [here](https://developers.fireblocks.com/docs/whitelist-addresses#internal-wallets)
# Delete a whitelisted address
Source: https://developers.fireblocks.com/api-reference/internal-wallets/delete-a-whitelisted-address
https://docs.fireblocks.com/api/v1/swagger.yaml delete /internal_wallets/{walletId}/{assetId}
Deletes a whitelisted address (for an asset) from an internal wallet.
# Delete an internal wallet
Source: https://developers.fireblocks.com/api-reference/internal-wallets/delete-an-internal-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml delete /internal_wallets/{walletId}
Deletes an internal wallet by ID.
# Get an asset from an internal wallet
Source: https://developers.fireblocks.com/api-reference/internal-wallets/get-an-asset-from-an-internal-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml get /internal_wallets/{walletId}/{assetId}
Returns information for an asset in an internal wallet.
# Get assets for internal wallet
Source: https://developers.fireblocks.com/api-reference/internal-wallets/get-assets-for-internal-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml get /internal_wallets/{walletId}
Returns information for an internal wallet.
# List assets in an internal wallet (Paginated)
Source: https://developers.fireblocks.com/api-reference/internal-wallets/list-assets-in-an-internal-wallet-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /internal_wallets/{walletId}/assets
Returns a paginated response of assets in an internal wallet.
# List internal wallets
Source: https://developers.fireblocks.com/api-reference/internal-wallets/list-internal-wallets
https://docs.fireblocks.com/api/v1/swagger.yaml get /internal_wallets
Gets a list of internal wallets.
# Set an AML/KYT customer reference ID for internal wallet
Source: https://developers.fireblocks.com/api-reference/internal-wallets/set-an-amlkyt-customer-reference-id-for-internal-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /internal_wallets/{walletId}/set_customer_ref_id
Sets an AML/KYT customer reference ID for the specific internal wallet.
# Add a new signing key
Source: https://developers.fireblocks.com/api-reference/key-link-beta/add-a-new-signing-key
https://docs.fireblocks.com/api/v1/swagger.yaml post /key_link/signing_keys
Adds a new signing key to the workspace. The added key will be linked to the specific Fireblocks agent user ID. The same user will receive the proof of ownership message to be signed, and upon successful proof, the key will become enabled.
# Add a new validation key
Source: https://developers.fireblocks.com/api-reference/key-link-beta/add-a-new-validation-key
https://docs.fireblocks.com/api/v1/swagger.yaml post /key_link/validation_keys
Adds a new validation key used to validate signing keys. The new validation key will undergo an approval process by the workspace quorum.
# Disables a validation key
Source: https://developers.fireblocks.com/api-reference/key-link-beta/disables-a-validation-key
https://docs.fireblocks.com/api/v1/swagger.yaml patch /key_link/validation_keys/{keyId}
Allows disabling validation key even if it has not expired yet. It is not allowed to enable the validation key back. Another key has to be used for future validations.
# Get a signing key by `keyId`
Source: https://developers.fireblocks.com/api-reference/key-link-beta/get-a-signing-key-by-`keyid`
https://docs.fireblocks.com/api/v1/swagger.yaml get /key_link/signing_keys/{keyId}
Returns a signing key if it exists, identified by the specified `keyId`.
# Get a validation key by `keyId`
Source: https://developers.fireblocks.com/api-reference/key-link-beta/get-a-validation-key-by-`keyid`
https://docs.fireblocks.com/api/v1/swagger.yaml get /key_link/validation_keys/{keyId}
Returns a validation key if it exists, identified by the specified `keyId`.
# Get list of registered validation keys
Source: https://developers.fireblocks.com/api-reference/key-link-beta/get-list-of-registered-validation-keys
https://docs.fireblocks.com/api/v1/swagger.yaml get /key_link/validation_keys
Returns the list of validation keys in the workspace
# Get list of signing keys
Source: https://developers.fireblocks.com/api-reference/key-link-beta/get-list-of-signing-keys
https://docs.fireblocks.com/api/v1/swagger.yaml get /key_link/signing_keys
Returns the list of signing keys in the workspace
# Modify the signing keyId
Source: https://developers.fireblocks.com/api-reference/key-link-beta/modify-the-signing-keyid
https://docs.fireblocks.com/api/v1/swagger.yaml patch /key_link/signing_keys/{keyId}
Allows assigning the signing key to a vault account, if it hasn't been assigned to any other vault accounts yet.
# Set agent user id
Source: https://developers.fireblocks.com/api-reference/key-link-beta/set-agent-user-id
https://docs.fireblocks.com/api/v1/swagger.yaml patch /key_link/signing_keys/{keyId}/agent_user_id
Can modify existing signing key id if the key is not enabled. The change done in background and will be visible once applied. If key is already enabled (after proof of ownership) the user cannot be changed.
# Get list of mpc keys
Source: https://developers.fireblocks.com/api-reference/keys-beta/get-list-of-mpc-keys
https://docs.fireblocks.com/api/v1/swagger.yaml get /keys/mpc/list
Returns a list of MPC signing keys of the workspace. For each key, the list of players associated with it is attached.
**Note:**
This endpoint is currently in beta and might be subject to changes.
# Get list of mpc keys by `userId`
Source: https://developers.fireblocks.com/api-reference/keys-beta/get-list-of-mpc-keys-by-`userid`
https://docs.fireblocks.com/api/v1/swagger.yaml get /keys/mpc/list/{userId}
Returns a list of MPC signing keys of a specific user. For each key, the list of players associated with it is attached.
**Note:**
This endpoint is currently in beta and might be subject to changes.
# Create a new network connection
Source: https://developers.fireblocks.com/api-reference/network-connections/create-a-new-network-connection
https://docs.fireblocks.com/api/v1/swagger.yaml post /network_connections
Initiates a new network connection.
**Note:** This API call is subject to Flexible Routing Schemes.
Your routing policy defines how your transactions are routed.
You can choose 1 of the 3 different schemes mentioned below for each asset type:
- **None**; Defines the profile routing to no destination for that asset type. Incoming transactions to asset types routed to `None` will fail.
- **Custom**; Route to an account that you choose. If you remove the account, incoming transactions will fail until you choose another one.
- **Default**; Use the routing specified by the network profile the connection is connected to. This scheme is also referred to as "Profile Routing"
Default Workspace Presets:
- Network Profile Crypto → **Custom**
- Network Profile FIAT → **None**
- Network Connection Crypto → **Default**
- Network Connection FIAT → **Default**
Supported asset groups for routing police can be found at `/network_ids/routing_policy_asset_groups`
- **Note**: By default, Custom routing scheme uses (`dstId` = `0`, `dstType` = `VAULT`).
# Creates a new Network ID
Source: https://developers.fireblocks.com/api-reference/network-connections/creates-a-new-network-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /network_ids
Create a new Network ID.
# Delete a network connection by ID
Source: https://developers.fireblocks.com/api-reference/network-connections/delete-a-network-connection-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml delete /network_connections/{connectionId}
Deletes an existing network connection specified by its connection ID.
# Delete specific network ID.
Source: https://developers.fireblocks.com/api-reference/network-connections/delete-specific-network-id
https://docs.fireblocks.com/api/v1/swagger.yaml delete /network_ids/{networkId}
Deletes a network by its ID.
# Get a network connection
Source: https://developers.fireblocks.com/api-reference/network-connections/get-a-network-connection
https://docs.fireblocks.com/api/v1/swagger.yaml get /network_connections/{connectionId}
Gets a network connection by ID.
# Get all network IDs
Source: https://developers.fireblocks.com/api-reference/network-connections/get-all-network-ids
https://docs.fireblocks.com/api/v1/swagger.yaml get /network_ids
Retrieves a list of all local and discoverable remote network IDs.
# Get both local IDs and discoverable remote IDs
Source: https://developers.fireblocks.com/api-reference/network-connections/get-both-local-ids-and-discoverable-remote-ids
https://docs.fireblocks.com/api/v1/swagger.yaml get /network_ids/search
Retrieves a list of all local and discoverable remote network IDs. Can be filtered.
# List network connections
Source: https://developers.fireblocks.com/api-reference/network-connections/list-network-connections
https://docs.fireblocks.com/api/v1/swagger.yaml get /network_connections
Returns all network connections.
**Note:** This API call is subject to Flexible Routing Schemes.
Your routing policy defines how your transactions are routed.
You can choose 1 of the 3 different schemes mentioned below for each asset type:
- **None**; Defines the profile routing to no destination for that asset type. Incoming transactions to asset types routed to `None` will fail.
- **Custom**; Route to an account that you choose. If you remove the account, incoming transactions will fail until you choose another one.
- **Default**; Use the routing specified by the network profile the connection is connected to. This scheme is also referred to as "Profile Routing"
Default Workspace Presets:
- Network Profile Crypto → **Custom**
- Network Profile FIAT → **None**
- Network Connection Crypto → **Default**
- Network Connection FIAT → **Default**
# Retrieve third-party network routing validation
Source: https://developers.fireblocks.com/api-reference/network-connections/retrieve-third-party-network-routing-validation
https://docs.fireblocks.com/api/v1/swagger.yaml get /network_connections/{connectionId}/is_third_party_routing/{assetType}
The Fireblocks Network allows for flexibility around incoming deposits. A receiver can receive network deposits to locations other than Fireblocks. This endpoint validates whether future transactions are routed to the displayed recipient or to a 3rd party.
# Return all enabled routing policy asset groups
Source: https://developers.fireblocks.com/api-reference/network-connections/return-all-enabled-routing-policy-asset-groups
https://docs.fireblocks.com/api/v1/swagger.yaml get /network_ids/routing_policy_asset_groups
Returns all enabled routing policy asset groups
# Return specific network ID.
Source: https://developers.fireblocks.com/api-reference/network-connections/return-specific-network-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /network_ids/{networkId}
Returns specific network ID.
# Update network connection routing policy.
Source: https://developers.fireblocks.com/api-reference/network-connections/update-network-connection-routing-policy
https://docs.fireblocks.com/api/v1/swagger.yaml patch /network_connections/{connectionId}/set_routing_policy
Updates an existing network connection's routing policy.
# Update network id routing policy.
Source: https://developers.fireblocks.com/api-reference/network-connections/update-network-id-routing-policy
https://docs.fireblocks.com/api/v1/swagger.yaml patch /network_ids/{networkId}/set_routing_policy
Updates the routing policy of a specified network ID.
# Update network ID's discoverability.
Source: https://developers.fireblocks.com/api-reference/network-connections/update-network-ids-discoverability
https://docs.fireblocks.com/api/v1/swagger.yaml patch /network_ids/{networkId}/set_discoverability
Update whether or not the network ID is discoverable by others.
# Update network ID's name.
Source: https://developers.fireblocks.com/api-reference/network-connections/update-network-ids-name
https://docs.fireblocks.com/api/v1/swagger.yaml patch /network_ids/{networkId}/set_name
Updates name of a specified network ID.
# List all distinct owned tokens (paginated)
Source: https://developers.fireblocks.com/api-reference/nfts/list-all-distinct-owned-tokens-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /nfts/ownership/assets
Returns all owned distinct tokens (for your tenant) and their data in your workspace.
# List all owned tokens (paginated)
Source: https://developers.fireblocks.com/api-reference/nfts/list-all-owned-tokens-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /nfts/ownership/tokens
Returns all tokens and their data in your workspace.
# List owned collections (paginated)
Source: https://developers.fireblocks.com/api-reference/nfts/list-owned-collections-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /nfts/ownership/collections
Returns all collections in your workspace
# List token data by ID
Source: https://developers.fireblocks.com/api-reference/nfts/list-token-data-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /nfts/tokens/{id}
Returns the requested token data.
# List tokens by IDs
Source: https://developers.fireblocks.com/api-reference/nfts/list-tokens-by-ids
https://docs.fireblocks.com/api/v1/swagger.yaml get /nfts/tokens
Returns the requested tokens data.
# Refresh token metadata
Source: https://developers.fireblocks.com/api-reference/nfts/refresh-token-metadata
https://docs.fireblocks.com/api/v1/swagger.yaml put /nfts/tokens/{id}
Updates the latest token metadata.
# Refresh vault account tokens
Source: https://developers.fireblocks.com/api-reference/nfts/refresh-vault-account-tokens
https://docs.fireblocks.com/api/v1/swagger.yaml put /nfts/ownership/tokens
Updates all tokens and balances per blockchain and vault account.
Learn more about Fireblocks NFT management in the following [guide](https://developers.fireblocks.com/reference/deploy-an-nft-collection).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Update token ownership status
Source: https://developers.fireblocks.com/api-reference/nfts/update-token-ownership-status
https://docs.fireblocks.com/api/v1/swagger.yaml put /nfts/ownership/tokens/{id}/status
Updates token status for a tenant, in all tenant vaults.
# Update tokens ownership spam property
Source: https://developers.fireblocks.com/api-reference/nfts/update-tokens-ownership-spam-property
https://docs.fireblocks.com/api/v1/swagger.yaml put /nfts/ownership/tokens/spam
Updates tokens spam property for a tenant's token ownerships, in all tenant vaults.
# Update tokens ownership status
Source: https://developers.fireblocks.com/api-reference/nfts/update-tokens-ownership-status
https://docs.fireblocks.com/api/v1/swagger.yaml put /nfts/ownership/tokens/status
Updates tokens status for a tenant, in all tenant vaults.
# Add Collateral
Source: https://developers.fireblocks.com/api-reference/off-exchanges/add-collateral
https://docs.fireblocks.com/api/v1/swagger.yaml post /off_exchange/add
Add collateral and create deposit request.
Learn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create Settlement for a Trader
Source: https://developers.fireblocks.com/api-reference/off-exchanges/create-settlement-for-a-trader
https://docs.fireblocks.com/api/v1/swagger.yaml post /off_exchange/settlements/trader
Create settlement for a trader.
Learn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Find a specific collateral exchange account
Source: https://developers.fireblocks.com/api-reference/off-exchanges/find-a-specific-collateral-exchange-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /off_exchange/collateral_accounts/{mainExchangeAccountId}
Returns a collateral account by mainExchangeAccountId.
Learn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Get Settlements Transactions
Source: https://developers.fireblocks.com/api-reference/off-exchanges/get-settlements-transactions
https://docs.fireblocks.com/api/v1/swagger.yaml get /off_exchange/settlements/transactions
Get settlements transactions from exchange.
Learn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Remove Collateral
Source: https://developers.fireblocks.com/api-reference/off-exchanges/remove-collateral
https://docs.fireblocks.com/api/v1/swagger.yaml post /off_exchange/remove
Remove collateral, create withdraw request.
Learn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Fetch onchain transactions for a contract
Source: https://developers.fireblocks.com/api-reference/onchain-data/fetch-onchain-transactions-for-a-contract
https://docs.fireblocks.com/api/v1/swagger.yaml get /onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/transactions
Returns a paginated list of onchain transactions for the specified contract address and base asset ID, optionally filtered by date range.
# Get historical balance data for a specific account in a contract
Source: https://developers.fireblocks.com/api-reference/onchain-data/get-historical-balance-data-for-a-specific-account-in-a-contract
https://docs.fireblocks.com/api/v1/swagger.yaml get /onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/account_address/{accountAddress}/balance_history
Returns the paginated balance history of the specified account in a contract with optional date range and interval filtering.
# Get historical total supply data for a contract
Source: https://developers.fireblocks.com/api-reference/onchain-data/get-historical-total-supply-data-for-a-contract
https://docs.fireblocks.com/api/v1/swagger.yaml get /onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/total_supply
Returns the paginated total supply history of the specified contract with optional date range and interval filtering.
# Get latest balances for all addresses holding tokens from a contract
Source: https://developers.fireblocks.com/api-reference/onchain-data/get-latest-balances-for-all-addresses-holding-tokens-from-a-contract
https://docs.fireblocks.com/api/v1/swagger.yaml get /onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/balances
Returns the latest balance for each unique address with support for numeric balance sorting. The `prev` cursor is reserved for future support.
# Get summary for the token contract
Source: https://developers.fireblocks.com/api-reference/onchain-data/get-summary-for-the-token-contract
https://docs.fireblocks.com/api/v1/swagger.yaml get /onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/summary
Returns the total number of unique addresses holding balances and the total supply for the specified contract.
# Get the current state of addresses in an access registry
Source: https://developers.fireblocks.com/api-reference/onchain-data/get-the-current-state-of-addresses-in-an-access-registry
https://docs.fireblocks.com/api/v1/swagger.yaml get /onchain_data/base_asset_id/{baseAssetId}/access_registry_address/{accessRegistryAddress}/list
Returns the current state of addresses in the specified access registry. Only addresses that are currently active (added but not removed) are included.
# List of active roles for a given contract address and base asset ID
Source: https://developers.fireblocks.com/api-reference/onchain-data/list-of-active-roles-for-a-given-contract-address-and-base-asset-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/roles
Returns a list of currently active roles for the specified baseAssetId and contractAddress.
# Summary of access registry state
Source: https://developers.fireblocks.com/api-reference/onchain-data/summary-of-access-registry-state
https://docs.fireblocks.com/api/v1/swagger.yaml get /onchain_data/base_asset_id/{baseAssetId}/access_registry_address/{accessRegistryAddress}/summary
Returns a summary of the current state of the access registry for the specified baseAssetId and accessRegistryAddress.
# Enable or disable transactions to OTA
Source: https://developers.fireblocks.com/api-reference/ota-beta/enable-or-disable-transactions-to-ota
https://docs.fireblocks.com/api/v1/swagger.yaml put /management/ota
Enable or disable transactions to One Time Addresses (Non Whitelisted addresses).
Learn more about [One Time Addresses](https://support.fireblocks.io/hc/en-us/articles/4409104568338-One-Time-Address-OTA-feature)
# Returns current OTA status
Source: https://developers.fireblocks.com/api-reference/ota-beta/returns-current-ota-status
https://docs.fireblocks.com/api/v1/swagger.yaml get /management/ota
Returns current OTA status
# Create payment flow configuration
Source: https://developers.fireblocks.com/api-reference/payments--flows/create-payment-flow-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml post /payments/workflow_config
Generate a new configuration ID to be used for initiating executions in subsequent phases. This configuration should include the operations you intend to incorporate into the workflow, such as TRANSFER, CONVERT, and DISBURSE, in addition to your pre-screening preferences, which are disabled by default.
# Create workflow execution
Source: https://developers.fireblocks.com/api-reference/payments--flows/create-workflow-execution
https://docs.fireblocks.com/api/v1/swagger.yaml post /payments/workflow_execution
Validate the "workflow-config" previously created by utilizing the unique "configId". This step requires the mandatory field amount, and allows for modifications to other fields defined via the "workflow-config" endpoint, including pre-screening preferences. A response containing the "workflowExecutionId" and detailing the validation status will be provided. Execution is ready when the "workflow-execution" status is READY_FOR_LAUNCH, at which point it can be initiated with "POST /workflow-execution/{workflowExecutionId}/actions/execute".
# Delete workflow configuration
Source: https://developers.fireblocks.com/api-reference/payments--flows/delete-workflow-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml delete /payments/workflow_config/{configId}
Delete a configuration using the specified "configId".
# Execute the payments workflow
Source: https://developers.fireblocks.com/api-reference/payments--flows/execute-the-payments-workflow
https://docs.fireblocks.com/api/v1/swagger.yaml post /payments/workflow_execution/{workflowExecutionId}/actions/execute
Launch the execution of a pre-configured workflow, identified by "workflowExecutionId", once it reaches the READY_FOR_LAUNCH state. The workflow undergoes several phases during execution - EXECUTION_IN_PROGRESS - Marks the start of the workflow execution. EXECUTION_COMPLETED or EXECUTION_FAILED - Indicates the execution has reached a final state.
# Get workflow execution details
Source: https://developers.fireblocks.com/api-reference/payments--flows/get-workflow-execution-details
https://docs.fireblocks.com/api/v1/swagger.yaml get /payments/workflow_execution/{workflowExecutionId}
Retrieve details of a previously initiated workflow execution by specifying the "workflowExecutionId"
# Retrieve workflow configuration
Source: https://developers.fireblocks.com/api-reference/payments--flows/retrieve-workflow-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml get /payments/workflow_config/{configId}
Retrieve a previously created workflow configuration using the specified "configId".
# Create a payout instruction set
Source: https://developers.fireblocks.com/api-reference/payments--payout/create-a-payout-instruction-set
https://docs.fireblocks.com/api/v1/swagger.yaml post /payments/payout
**Note:** The reference content in this section documents the Payments
Engine endpoint. The Payments Engine endpoints include APIs available only
for customers with Payments Engine enabled on their accounts.
These endpoints are currently in beta and might be subject to
changes.
If you want to learn more about Fireblocks Payments Engine, please
contact your Fireblocks Customer Success Manager or email
CSM@fireblocks.com.
**Create a payout instruction set.**
A payout instruction set is a set of instructions for distributing payments
from a single payment account to a list of payee accounts.
The instruction set defines:
- the payment account and its account type (vault, exchange, or fiat).
- the account type (vault account, exchange account, whitelisted address,
network connection, fiat account, or merchant account), the amount, and the
asset of payment for each payee account.
Learn more about Fireblocks Payments - Payouts in the following
[guide](https://developers.fireblocks.com/docs/create-payouts).
Endpoint Permission: Admin, Non-Signing Admin.
# Execute a payout instruction set
Source: https://developers.fireblocks.com/api-reference/payments--payout/execute-a-payout-instruction-set
https://docs.fireblocks.com/api/v1/swagger.yaml post /payments/payout/{payoutId}/actions/execute
**Note:** The reference content in this section documents the Payments
Engine endpoint. The Payments Engine endpoints include APIs available only
for customers with Payments Engine enabled on their accounts.
These endpoints are currently in beta and might be subject to
changes.
If you want to learn more about Fireblocks Payments Engine, please
contact your Fireblocks Customer Success Manager or email
CSM@fireblocks.com.
**Execute a payout instruction set.**
The instruction set will be verified and executed.
**Source locking**
If you are executing a payout instruction set from a payment account with an
already active payout the active payout will complete before the new payout
instruction set can be executed.
You cannot execute the same payout instruction set more than once.
# Get the status of a payout instruction set
Source: https://developers.fireblocks.com/api-reference/payments--payout/get-the-status-of-a-payout-instruction-set
https://docs.fireblocks.com/api/v1/swagger.yaml get /payments/payout/{payoutId}
**Note:** The reference content in this section documents the Payments Engine endpoint. The Payments Engine endpoints include APIs available only for customers with Payments Engine enabled on their accounts.
These endpoints are currently in beta and might be subject to changes.
If you want to learn more about Fireblocks Payments Engine, please contact your Fireblocks Customer Success Manager or email CSM@fireblocks.com.
Endpoint Permission: Admin, Non-Signing Admin.
# Get the active draft
Source: https://developers.fireblocks.com/api-reference/policy-editor-beta/get-the-active-draft
https://docs.fireblocks.com/api/v1/swagger.yaml get /tap/draft
Legacy Endpoint – Returns the active draft and its validation.
**Note:**
- This endpoint will remain available for the foreseeable future and is not deprecated. - The `getDraft` endpoint under policy/paths provides policy type-specific operations and improved functionality. - These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
# Get the active policy and its validation
Source: https://developers.fireblocks.com/api-reference/policy-editor-beta/get-the-active-policy-and-its-validation
https://docs.fireblocks.com/api/v1/swagger.yaml get /tap/active_policy
Legacy Endpoint – Returns the active policy and its validation.
**Note:**
- This endpoint will remain available for the foreseeable future and is not deprecated. - The `getActivePolicy` endpoint under policy/paths provides policy type-specific operations and improved functionality. - These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
# Send publish request for a certain draft id
Source: https://developers.fireblocks.com/api-reference/policy-editor-beta/send-publish-request-for-a-certain-draft-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /tap/draft
Legacy Endpoint – Send publish request of certain draft id and returns the response.
**Note:**
- This endpoint will remain available for the foreseeable future and is not deprecated. - The `publishDraft` endpoint under policy/paths provides improved functionality and better performance. - These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
# Send publish request for a set of policy rules
Source: https://developers.fireblocks.com/api-reference/policy-editor-beta/send-publish-request-for-a-set-of-policy-rules
https://docs.fireblocks.com/api/v1/swagger.yaml post /tap/publish
Send publish request of set of policy rules and returns the response.
**Note:** These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
# Update the draft with a new set of rules
Source: https://developers.fireblocks.com/api-reference/policy-editor-beta/update-the-draft-with-a-new-set-of-rules
https://docs.fireblocks.com/api/v1/swagger.yaml put /tap/draft
Legacy Endpoint – Update the draft and return its validation.
**Note:**
- This endpoint will remain available for the foreseeable future and is not deprecated. - The `updateDraft` endpoint under policy/paths provides policy type-specific operations and improved functionality. - These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
# Get the active draft by policy type
Source: https://developers.fireblocks.com/api-reference/policy-editor-v2-beta/get-the-active-draft-by-policy-type
https://docs.fireblocks.com/api/v1/swagger.yaml get /policy/draft
Returns the active draft and its validation for a specific policy type.
**Note:** These endpoints are currently in beta and might be subject to changes.
# Get the active policy and its validation by policy type
Source: https://developers.fireblocks.com/api-reference/policy-editor-v2-beta/get-the-active-policy-and-its-validation-by-policy-type
https://docs.fireblocks.com/api/v1/swagger.yaml get /policy/active_policy
Returns the active policy and its validation for a specific policy type.
**Note:** This endpoint is currently in beta and subject to change. If you want to participate in the Policies beta, contact your Fireblocks Customer Success Manager or send an email to csm@fireblocks.com.
Endpoint Permissions: Owner, Admin, Non-Signing Admin.
# Send publish request for a certain draft id
Source: https://developers.fireblocks.com/api-reference/policy-editor-v2-beta/send-publish-request-for-a-certain-draft-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /policy/draft
Send publish request of certain draft id and returns the response.
**Note:** These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks Policy Editor, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
# Update the draft with a new set of rules by policy types
Source: https://developers.fireblocks.com/api-reference/policy-editor-v2-beta/update-the-draft-with-a-new-set-of-rules-by-policy-types
https://docs.fireblocks.com/api/v1/swagger.yaml put /policy/draft
Update the draft and return its validation for specific policy types.
**Note:** These endpoints are currently in beta and might be subject to changes.
# Resets device
Source: https://developers.fireblocks.com/api-reference/reset-device/resets-device
https://docs.fireblocks.com/api/v1/swagger.yaml post /management/users/{id}/reset_device
Resets mobile device for given console user, that user will need to do mobile onboarding again.
- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.
Endpoint Permission: Admin, Non-Signing Admin.
# Add external ref. ID
Source: https://developers.fireblocks.com/api-reference/smart-transfer/add-external-ref-id
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart-transfers/{ticketId}/external-id
Set external id Smart Transfer ticket. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Cancel Ticket
Source: https://developers.fireblocks.com/api-reference/smart-transfer/cancel-ticket
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart-transfers/{ticketId}/cancel
Cancel Smart Transfer ticket. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create leg (term)
Source: https://developers.fireblocks.com/api-reference/smart-transfer/create-leg-term
https://docs.fireblocks.com/api/v1/swagger.yaml post /smart-transfers/{ticketId}/terms
Creates new smart transfer ticket term (when the ticket status is DRAFT). Learn more about Fireblocks Smart Transfers in the following [guide](https://developers.fireblocks.com/docs/execute-smart-transfers). Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create Ticket
Source: https://developers.fireblocks.com/api-reference/smart-transfer/create-ticket
https://docs.fireblocks.com/api/v1/swagger.yaml post /smart-transfers
Creates a new Smart Transfer ticket. Learn more about Fireblocks Smart Transfers [here](https://developers.fireblocks.com/docs/execute-smart-transfers).
**Note:** The `DVP` value is in Early Access and should only be used if Fireblocks has enabled it in your workspace. Contact your Customer Success Manager for more information.
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor.
# Define funding source
Source: https://developers.fireblocks.com/api-reference/smart-transfer/define-funding-source
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart-transfers/{ticketId}/terms/{termId}/fund
Set funding source for ticket term (in case of ASYNC tickets, this will execute transfer immediately). Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Delete ticket leg (term)
Source: https://developers.fireblocks.com/api-reference/smart-transfer/delete-ticket-leg-term
https://docs.fireblocks.com/api/v1/swagger.yaml delete /smart-transfers/{ticketId}/terms/{termId}
Delete ticket term when ticket is in DRAFT status
# Find Ticket
Source: https://developers.fireblocks.com/api-reference/smart-transfer/find-ticket
https://docs.fireblocks.com/api/v1/swagger.yaml get /smart-transfers
Find tickets by their title or ticker. You can also query all tickets without filters by not providing any input parameters.
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Fund dvp ticket
Source: https://developers.fireblocks.com/api-reference/smart-transfer/fund-dvp-ticket
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart_transfers/{ticketId}/dvp/fund
Create or fulfill dvp ticket order
# Fund ticket manually
Source: https://developers.fireblocks.com/api-reference/smart-transfer/fund-ticket-manually
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart-transfers/{ticketId}/fulfill
Manually fulfill ticket, in case when all terms (legs) are funded manually. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Get Smart Transfer ticket term
Source: https://developers.fireblocks.com/api-reference/smart-transfer/get-smart-transfer-ticket-term
https://docs.fireblocks.com/api/v1/swagger.yaml get /smart-transfers/{ticketId}/terms/{termId}
Find a specific term of a specific Smart Transfer ticket. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get smart transfers statistic
Source: https://developers.fireblocks.com/api-reference/smart-transfer/get-smart-transfers-statistic
https://docs.fireblocks.com/api/v1/swagger.yaml get /smart_transfers/statistic
Get smart transfer statistic
# Get user group
Source: https://developers.fireblocks.com/api-reference/smart-transfer/get-user-group
https://docs.fireblocks.com/api/v1/swagger.yaml get /smart-transfers/settings/user-groups
Get Smart Transfer user groups.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Manually add term transaction
Source: https://developers.fireblocks.com/api-reference/smart-transfer/manually-add-term-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart-transfers/{ticketId}/terms/{termId}/manually-fund
Manually set ticket term transaction.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Search Ticket by ID
Source: https://developers.fireblocks.com/api-reference/smart-transfer/search-ticket-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /smart-transfers/{ticketId}
Find Smart Transfer ticket by id. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Set expiration
Source: https://developers.fireblocks.com/api-reference/smart-transfer/set-expiration
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart-transfers/{ticketId}/expires-in
Set expiration date on Smart Transfer ticket. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Set funding source and approval
Source: https://developers.fireblocks.com/api-reference/smart-transfer/set-funding-source-and-approval
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart_transfers/{ticketId}/terms/{termId}/dvp/approve
Set funding source for ticket term and creating approving transaction for contract to transfer asset
# Set user group
Source: https://developers.fireblocks.com/api-reference/smart-transfer/set-user-group
https://docs.fireblocks.com/api/v1/swagger.yaml post /smart-transfers/settings/user-groups
Set Smart Transfers user group to receive email notifications for Smart Transfers.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Submit ticket
Source: https://developers.fireblocks.com/api-reference/smart-transfer/submit-ticket
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart-transfers/{ticketId}/submit
Submit Smart Transfer ticket - change status into ready for approval if auto approval is not turned on, or OPEN if auto approval is on. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Update ticket leg (term)
Source: https://developers.fireblocks.com/api-reference/smart-transfer/update-ticket-leg-term
https://docs.fireblocks.com/api/v1/swagger.yaml put /smart-transfers/{ticketId}/terms/{termId}
Update ticket term (when ticket status is DRAFT)
# Approve provider terms of service
Source: https://developers.fireblocks.com/api-reference/staking/approve-provider-terms-of-service
https://docs.fireblocks.com/api/v1/swagger.yaml post /staking/providers/{providerId}/approveTermsOfService
Approves the provider's terms of service. Must be called once before performing any staking operation with this provider.
# Claim accrued rewards
Source: https://developers.fireblocks.com/api-reference/staking/claim-accrued-rewards
https://docs.fireblocks.com/api/v1/swagger.yaml post /staking/chains/{chainDescriptor}/claim_rewards
Claims available staking rewards for the specified chain and vault. Supported chains: Solana and Polygon (POL/Matic). Behavior depends on protocol reward distribution.
# Consolidate staking positions (ETH validator consolidation)
Source: https://developers.fireblocks.com/api-reference/staking/consolidate-staking-positions-eth-validator-consolidation
https://docs.fireblocks.com/api/v1/swagger.yaml post /staking/chains/{chainDescriptor}/consolidate
Consolidates the source staking position into the destination, merging the balance into the destination and closing the source position once complete. Both positions must be from the same vault account (i.e. same withdrawal credentials). On chain, this translates into a consolidation transaction, where the source validator is consolidated into the destination validator. Supported chains: Ethereum (ETH) only.
Endpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Approver, Editor.
**Note:** This endpoint is currently in beta and might be subject to changes.
# Get chain-level staking parameters
Source: https://developers.fireblocks.com/api-reference/staking/get-chain-level-staking-parameters
https://docs.fireblocks.com/api/v1/swagger.yaml get /staking/chains/{chainDescriptor}/chainInfo
Returns chain-specific staking information such as epoch/slot cadence, lockup or unbonding periods, fee/reward mechanics, and other operational constraints.
# Get position details
Source: https://developers.fireblocks.com/api-reference/staking/get-position-details
https://docs.fireblocks.com/api/v1/swagger.yaml get /staking/positions/{id}
Returns full details for a single staking position: amounts, rewards, status, chain, and vault.
# Get positions summary
Source: https://developers.fireblocks.com/api-reference/staking/get-positions-summary
https://docs.fireblocks.com/api/v1/swagger.yaml get /staking/positions/summary
Returns an aggregated cross-vault summary: active/inactive counts, total staked, and total rewards per chain.
# Get positions summary by vault
Source: https://developers.fireblocks.com/api-reference/staking/get-positions-summary-by-vault
https://docs.fireblocks.com/api/v1/swagger.yaml get /staking/positions/summary/vaults
Returns per-vault aggregates: status breakdown, total staked, and total rewards per chain.
# Initiate or add to existing stake
Source: https://developers.fireblocks.com/api-reference/staking/initiate-or-add-to-existing-stake
https://docs.fireblocks.com/api/v1/swagger.yaml post /staking/chains/{chainDescriptor}/stake
Creates a new staking position and returns its unique ID. For Ethereum compounding validator (EIP-7251): when the 'id' of an existing compounding validator position is provided, adds to that position; otherwise creates a new position. For Ethereum legacy validator: creates a new position regardless of existing delegations. For Cosmos chains and Ethereum liquid staking (Lido): automatically add to existing positions for the same validator provider and same vault account if one exists, otherwise create a new position. For Solana and Polygon (MATIC/POL): always create new positions regardless of existing delegations.
# Initiate unstake
Source: https://developers.fireblocks.com/api-reference/staking/initiate-unstake
https://docs.fireblocks.com/api/v1/swagger.yaml post /staking/chains/{chainDescriptor}/unstake
Submits a chain-specific unstake request.
# List staking positions
Source: https://developers.fireblocks.com/api-reference/staking/list-staking-positions
https://docs.fireblocks.com/api/v1/swagger.yaml get /staking/positions
Returns all staking positions with core details: amounts, rewards, status, chain, and vault.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# List staking positions (Paginated)
Source: https://developers.fireblocks.com/api-reference/staking/list-staking-positions-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /staking/positions_paginated
Returns staking positions with core details: amounts, rewards, status, chain, and vault. It supports cursor-based pagination for efficient data retrieval. This endpoint always returns a paginated response with {data, next} structure.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# List staking providers
Source: https://developers.fireblocks.com/api-reference/staking/list-staking-providers
https://docs.fireblocks.com/api/v1/swagger.yaml get /staking/providers
Returns all available staking providers with metadata such as name, ID, and supported chains.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# List supported staking chains
Source: https://developers.fireblocks.com/api-reference/staking/list-supported-staking-chains
https://docs.fireblocks.com/api/v1/swagger.yaml get /staking/chains
Returns an alphabetical list of blockchains supported for staking by the current workspace context.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Merge staking positions
Source: https://developers.fireblocks.com/api-reference/staking/merge-staking-positions
https://docs.fireblocks.com/api/v1/swagger.yaml post /staking/chains/{chainDescriptor}/merge
Merges the source stake account into the destination, consolidating the balance into the destination and closing the source account once complete. Both accounts must be from the same validator provider and of same vault account.. Supported chains: Solana (SOL).
Endpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Approver, Editor.
# Split a staking position
Source: https://developers.fireblocks.com/api-reference/staking/split-a-staking-position
https://docs.fireblocks.com/api/v1/swagger.yaml post /staking/chains/{chainDescriptor}/split
Splits a staking position by creating a new stake account with the requested amount, while keeping the original account with the remaining balance. Supported chains: Solana (SOL).
# Withdraw staked funds
Source: https://developers.fireblocks.com/api-reference/staking/withdraw-staked-funds
https://docs.fireblocks.com/api/v1/swagger.yaml post /staking/chains/{chainDescriptor}/withdraw
Withdraws funds that have completed the unbonding period. Typically requires the position to be deactivated first (unstake → unbond → withdraw). Amount and timing vary by chain protocol.
Partial withdrawal is supported for ETH compounding validators (EIP-7251/Pectra) and Cosmos chains via the optional 'amount' field. For ETH compounding validators, the remaining balance must be at least 32 ETH after the withdrawal. For all other chains, omitting 'amount' withdraws the entire available balance.
# Cancel an approval request by id
Source: https://developers.fireblocks.com/api-reference/tags/cancel-an-approval-request-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /tags/approval_requests/{id}/cancel
Cancel an approval request by id. Can only cancel requests in PENDING status. Returns 202 Accepted when the cancellation is processed.
# Create a new tag
Source: https://developers.fireblocks.com/api-reference/tags/create-a-new-tag
https://docs.fireblocks.com/api/v1/swagger.yaml post /tags
Create a new tag.
Endpoint Permissions: For protected tags: ADMIN,NON_SIGNING_ADMIN,OWNER. For non protected tags: ADMIN,NON_SIGNING_ADMIN,OWNER,SIGNER,EDITOR,APPROVER.
# Delete a tag
Source: https://developers.fireblocks.com/api-reference/tags/delete-a-tag
https://docs.fireblocks.com/api/v1/swagger.yaml delete /tags/{tagId}
Delete the specified tag.
Endpoint Permission: For protected tags: Owner, Admin, Non-Signing Admin. For non protected tags: Owner, Admin, Non-Signing Admin, Signer, Editor, Approver.
# Get a tag
Source: https://developers.fireblocks.com/api-reference/tags/get-a-tag
https://docs.fireblocks.com/api/v1/swagger.yaml get /tags/{tagId}
Retrieve an existing tag by ID.
# Get an approval request by id
Source: https://developers.fireblocks.com/api-reference/tags/get-an-approval-request-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /tags/approval_requests/{id}
Get an approval request by id
# Get list of tags
Source: https://developers.fireblocks.com/api-reference/tags/get-list-of-tags
https://docs.fireblocks.com/api/v1/swagger.yaml get /tags
Retrieve a paged list of all tags according to filters.
# Update a tag
Source: https://developers.fireblocks.com/api-reference/tags/update-a-tag
https://docs.fireblocks.com/api/v1/swagger.yaml patch /tags/{tagId}
Update an existing specified tag.
Endpoint Permission: For protected tags: Owner, Admin, Non-Signing Admin. For non protected tags: Owner, Admin, Non-Signing Admin, Signer, Editor, Approver.
# Burn tokens
Source: https://developers.fireblocks.com/api-reference/tokenization/burn-tokens
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/collections/{id}/tokens/burn
Burn tokens in a collection
# Create a new collection
Source: https://developers.fireblocks.com/api-reference/tokenization/create-a-new-collection
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/collections
Create a new collection and link it as a token.
Endpoint Permission: Owner, Admin, Non-Signing Admin, Signer, and Editor.
# Delete a collection link
Source: https://developers.fireblocks.com/api-reference/tokenization/delete-a-collection-link
https://docs.fireblocks.com/api/v1/swagger.yaml delete /tokenization/collections/{id}
Delete a collection link
# Deploy LayerZero adapters
Source: https://developers.fireblocks.com/api-reference/tokenization/deploy-layerzero-adapters
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/multichain/bridge/layerzero
Deploy LayerZero adapters for multichain token bridging functionality. This endpoint creates adapter contracts that enable cross-chain token transfers.
# Get a collection by id
Source: https://developers.fireblocks.com/api-reference/tokenization/get-a-collection-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/collections/{id}
Get a collection by id
# Get collection token details
Source: https://developers.fireblocks.com/api-reference/tokenization/get-collection-token-details
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/collections/{id}/tokens/{tokenId}
Get collection token details by id
# Get collections
Source: https://developers.fireblocks.com/api-reference/tokenization/get-collections
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/collections
Get collections (paginated).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get deterministic address for contract deployment
Source: https://developers.fireblocks.com/api-reference/tokenization/get-deterministic-address-for-contract-deployment
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/multichain/deterministic_address
Get a deterministic address for contract deployment. The address is derived from the contract's bytecode and provided salt. This endpoint is used to get the address of a contract that will be deployed in the future.
# Get LayerZero DVN configuration
Source: https://developers.fireblocks.com/api-reference/tokenization/get-layerzero-dvn-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/multichain/bridge/layerzero/config/{adapterTokenLinkId}/dvns
Retrieve the DVN (Data Verification Network) configuration for a specific adapter. Returns DVN configurations for channels between the source adapter and its peers.
# Get LayerZero peers
Source: https://developers.fireblocks.com/api-reference/tokenization/get-layerzero-peers
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/multichain/bridge/layerzero/config/{adapterTokenLinkId}/peers
Retrieve the LayerZero peers configured for a specific adapter. Returns information about peer relationships for cross-chain communication.
# Get the total count of linked tokens
Source: https://developers.fireblocks.com/api-reference/tokenization/get-the-total-count-of-linked-tokens
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/tokens/count
Get the total count of linked tokens
# Issue a new token
Source: https://developers.fireblocks.com/api-reference/tokenization/issue-a-new-token
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/tokens
Facilitates the creation of a new token, supporting both EVM-based and Stellar/Ripple platforms. For EVM, it deploys the corresponding contract template to the blockchain and links the token to the workspace. For Stellar/Ripple, it links a newly created token directly to the workspace without deploying a contract. Returns the token link with status "PENDING" until the token is deployed or "SUCCESS" if no deployment is needed.
Endpoint Permission: Owner, Admin, Non-Signing Admin, Signer, and Editor.
# Issue a token on one or more blockchains
Source: https://developers.fireblocks.com/api-reference/tokenization/issue-a-token-on-one-or-more-blockchains
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/multichain/tokens
Facilitates the creation of a new token on one or more blockchains.
# Link a contract
Source: https://developers.fireblocks.com/api-reference/tokenization/link-a-contract
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/tokens/link
Link an a contract
# List all linked tokens
Source: https://developers.fireblocks.com/api-reference/tokenization/list-all-linked-tokens
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/tokens
Return all linked tokens (paginated)
# Mint tokens
Source: https://developers.fireblocks.com/api-reference/tokenization/mint-tokens
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/collections/{id}/tokens/mint
Mint tokens and upload metadata
# Reissue a multichain token
Source: https://developers.fireblocks.com/api-reference/tokenization/reissue-a-multichain-token
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/multichain/reissue/token/{tokenLinkId}
Reissue a multichain token. This endpoint allows you to reissue a token on one or more blockchains. The token must be initially issued using the issueTokenMultiChain endpoint.
# Remove LayerZero adapters
Source: https://developers.fireblocks.com/api-reference/tokenization/remove-layerzero-adapters
https://docs.fireblocks.com/api/v1/swagger.yaml delete /tokenization/multichain/bridge/layerzero
Remove LayerZero adapters by deactivating and unlinking them. This endpoint revokes roles and deactivates the specified adapter contracts.
# Remove LayerZero peers
Source: https://developers.fireblocks.com/api-reference/tokenization/remove-layerzero-peers
https://docs.fireblocks.com/api/v1/swagger.yaml delete /tokenization/multichain/bridge/layerzero/config/peers
Remove LayerZero peers to disconnect adapter contracts. This endpoint removes peer relationships between LayerZero adapters.
# Return a linked token
Source: https://developers.fireblocks.com/api-reference/tokenization/return-a-linked-token
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/tokens/{id}
Return a linked token, with its status and metadata.
# Set LayerZero DVN configuration
Source: https://developers.fireblocks.com/api-reference/tokenization/set-layerzero-dvn-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/multichain/bridge/layerzero/config/dvns
Configure DVN settings for LayerZero adapters. This endpoint sets up the DVN configuration for message verification between source and destination adapters.
# Set LayerZero peers
Source: https://developers.fireblocks.com/api-reference/tokenization/set-layerzero-peers
https://docs.fireblocks.com/api/v1/swagger.yaml post /tokenization/multichain/bridge/layerzero/config/peers
Set LayerZero peers to establish connections between adapter contracts. This endpoint creates peer relationships that enable cross-chain communication. It sets the destination adapter as a peer of the source adapter. If `bidirectional` is true, it also sets the source adapter as a peer of the destination adapter(s).
# Unlink a token
Source: https://developers.fireblocks.com/api-reference/tokenization/unlink-a-token
https://docs.fireblocks.com/api/v1/swagger.yaml delete /tokenization/tokens/{id}
Unlink a token. The token will be unlinked from the workspace. The token will not be deleted on chain nor the refId, only the link to the workspace will be removed.
# Validate LayerZero channel configuration
Source: https://developers.fireblocks.com/api-reference/tokenization/validate-layerzero-channel-configuration
https://docs.fireblocks.com/api/v1/swagger.yaml get /tokenization/multichain/bridge/layerzero/validate
Validate the LayerZero channel configuration between adapters. This endpoint checks if the channel configuration is correct and returns any validation errors.
# Create a quote
Source: https://developers.fireblocks.com/api-reference/trading-beta/create-a-quote
https://docs.fireblocks.com/api/v1/swagger.yaml post /trading/quotes
Generate a time-limited quote for asset conversion, providing exchange rate and amount calculations.
Note: These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
Endpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Editor.
For detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).
# Create an order
Source: https://developers.fireblocks.com/api-reference/trading-beta/create-an-order
https://docs.fireblocks.com/api/v1/swagger.yaml post /trading/orders
Create an order to buy or sell an asset. If no source is given, an external source will be use.
Note: These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
Endpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Editor.
For detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).
# Get order details
Source: https://developers.fireblocks.com/api-reference/trading-beta/get-order-details
https://docs.fireblocks.com/api/v1/swagger.yaml get /trading/orders/{orderId}
Retrieve detailed information about a specific order by its ID.
Note:These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
Endpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
For detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).
# Get orders
Source: https://developers.fireblocks.com/api-reference/trading-beta/get-orders
https://docs.fireblocks.com/api/v1/swagger.yaml get /trading/orders
Retrieve a paginated list of orders with optional filtering by account, provider, status, and time range.
Note:These endpoints are currently in beta and might be subject to changes.
If you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
Endpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
For detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).
# Get providers
Source: https://developers.fireblocks.com/api-reference/trading-beta/get-providers
https://docs.fireblocks.com/api/v1/swagger.yaml get /trading/providers
Retrieve a list of all available external providers supporting trading activities through the platform.
**Note:** These endpoints are currently in beta and might be subject to changes. If you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
**Endpoint Permission:** Owner, Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
For detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).
# Get trading provider by ID
Source: https://developers.fireblocks.com/api-reference/trading-beta/get-trading-provider-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /trading/providers/{providerId}
Retrieve a single provider by ID.
**Note:** These endpoints are currently in beta and might be subject to changes. If you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.
**Endpoint Permission:** Owner, Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
For detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).
# Cancel a transaction
Source: https://developers.fireblocks.com/api-reference/transactions/cancel-a-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml post /transactions/{txId}/cancel
Cancels a transaction by Fireblocks Transaction ID.
Can be used only for transactions that did not get to the BROADCASTING state.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create a new transaction
Source: https://developers.fireblocks.com/api-reference/transactions/create-a-new-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml post /transactions
Creates a new transaction. This endpoint can be used for regular Transfers, Contract Calls, Raw & Typed message signing. - For Transfers, the required parameters are: `assetId`, `source`, `destination` and `amount`. - For Contract Calls, the required parameters are: `operation.CONTRACT_CALL`, `assetId` (Base Asset), `source`,
# Drop ETH (EVM) transaction by ID
Source: https://developers.fireblocks.com/api-reference/transactions/drop-eth-evm-transaction-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /transactions/{txId}/drop
Drops a stuck ETH (EVM) transaction and creates a replacement transaction with 0 amount.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Estimate the required fee for an asset
Source: https://developers.fireblocks.com/api-reference/transactions/estimate-the-required-fee-for-an-asset
https://docs.fireblocks.com/api/v1/swagger.yaml get /estimate_network_fee
Gets the estimated required fee for an asset.
Fireblocks fetches, calculates and caches the result every 30 seconds.
Customers should query this API while taking the caching interval into consideration.
Notes:
- The `networkFee` parameter is the `gasPrice` with a given delta added, multiplied by the gasLimit plus the delta. - The estimation provided depends on the asset type.
- For UTXO-based assets, the response contains the `feePerByte` parameter
- For ETH-based and all EVM based assets, the response will contain `gasPrice` parameter. This is calculated by adding the `baseFee` to the `actualPriority` based on the latest 12 blocks. The response for ETH-based contains the `baseFee`, `gasPrice`, and `priorityFee` parameters.
- For ADA-based assets, the response will contain the parameter `networkFee` and `feePerByte` parameters.
- For XRP and XLM, the response will contain the transaction fee.
- For other assets, the response will contain the `networkFee` parameter.
Learn more about Fireblocks Fee Management in the following [guide](https://developers.fireblocks.com/reference/estimate-transaction-fee).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Estimate transaction fee
Source: https://developers.fireblocks.com/api-reference/transactions/estimate-transaction-fee
https://docs.fireblocks.com/api/v1/swagger.yaml post /transactions/estimate_fee
Estimates the transaction fee for a specific transaction request.
This endpoint simulates a transaction which means that the system will expect to have the requested asset and balance in the specified wallet.
**Note**: Supports all Fireblocks assets except ZCash (ZEC).
The PROGRAM_CALL operation is not supported by this endpoint — fee estimation for Solana program calls is not available.
Learn more about Fireblocks Fee Management in the following [guide](https://developers.fireblocks.com/reference/estimate-transaction-fee).
Endpoint Permission: Admin, Signer, Approver, Editor.
# Freeze a transaction
Source: https://developers.fireblocks.com/api-reference/transactions/freeze-a-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml post /transactions/{txId}/freeze
Freezes a transaction by ID.
Usually used for AML integrations when the incoming funds should be quarantined.
For account based assets - the entire amount of the transaction is frozen
For UTXO based assets - all UTXOs of the specified transaction are frozen
Endpoint Permission: Admin, Non-Signing Admin.
# Get a specific transaction by external transaction ID
Source: https://developers.fireblocks.com/api-reference/transactions/get-a-specific-transaction-by-external-transaction-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /transactions/external_tx_id/{externalTxId}
Returns transaction by external transaction ID.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get a specific transaction by Fireblocks transaction ID
Source: https://developers.fireblocks.com/api-reference/transactions/get-a-specific-transaction-by-fireblocks-transaction-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /transactions/{txId}
Get a specific transaction data by Fireblocks Transaction ID
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get transaction history
Source: https://developers.fireblocks.com/api-reference/transactions/get-transaction-history
https://docs.fireblocks.com/api/v1/swagger.yaml get /transactions
Get the transaction history for your workspace.
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Set confirmation threshold by Fireblocks Transaction ID
Source: https://developers.fireblocks.com/api-reference/transactions/set-confirmation-threshold-by-fireblocks-transaction-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /transactions/{txId}/set_confirmation_threshold
Overrides the required number of confirmations for transaction completion Fireblocks Transaction ID.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Set confirmation threshold by transaction hash
Source: https://developers.fireblocks.com/api-reference/transactions/set-confirmation-threshold-by-transaction-hash
https://docs.fireblocks.com/api/v1/swagger.yaml post /txHash/{txHash}/set_confirmation_threshold
Overrides the required number of confirmations for transaction completion by transaction hash.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Unfreeze a transaction
Source: https://developers.fireblocks.com/api-reference/transactions/unfreeze-a-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml post /transactions/{txId}/unfreeze
Unfreezes a transaction by Fireblocks Transaction ID and makes the transaction available again.
Endpoint Permission: Admin, Non-Signing Admin.
# Validate destination address
Source: https://developers.fireblocks.com/api-reference/transactions/validate-destination-address
https://docs.fireblocks.com/api/v1/swagger.yaml get /transactions/validate_address/{assetId}/{address}
Checks if an address is valid and active (for XRP, DOT, XLM, and EOS).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Add jsonDidKey to VASP details
Source: https://developers.fireblocks.com/api-reference/travel-rule/add-jsondidkey-to-vasp-details
https://docs.fireblocks.com/api/v1/swagger.yaml put /screening/travel_rule/vasp/update
Update VASP Details.
Updates a VASP with the provided parameters. Use this endpoint to add your public jsonDIDkey generated by Notabene.
# Assign VASP to vault
Source: https://developers.fireblocks.com/api-reference/travel-rule/assign-vasp-to-vault
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/travel_rule/vault/{vaultAccountId}/vasp
Sets the VASP Did for a specific vault. Pass empty string to remove existing one.
# Create Trust Network Proof of Address
Source: https://developers.fireblocks.com/api-reference/travel-rule/create-trust-network-proof-of-address
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/travel_rule/providers/trust/proof_of_address
Creates a cryptographic proof of address ownership for TRUST network.
# Get All VASPs
Source: https://developers.fireblocks.com/api-reference/travel-rule/get-all-vasps
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/travel_rule/vasp
Get All VASPs.
Returns a list of VASPs. VASPs can be searched and sorted.
# Get assigned VASP to vault
Source: https://developers.fireblocks.com/api-reference/travel-rule/get-assigned-vasp-to-vault
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/travel_rule/vault/{vaultAccountId}/vasp
Get assigned VASP Did for a specific vault. Returns empty string vaspDid value in response if none assigned.
# Get VASP details
Source: https://developers.fireblocks.com/api-reference/travel-rule/get-vasp-details
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/travel_rule/vasp/{did}
Get VASP Details.
Returns information about a VASP that has the specified DID.
# Retrieve Trust Network Proof of Address Signature
Source: https://developers.fireblocks.com/api-reference/travel-rule/retrieve-trust-network-proof-of-address-signature
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/travel_rule/providers/trust/proof_of_address/{transactionId}
Retrieves the TRUST-compatible encoded signature for a proof of address transaction. Send this signature directly to TRUST for verification.
# Validate Full Travel Rule Transaction
Source: https://developers.fireblocks.com/api-reference/travel-rule/validate-full-travel-rule-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/travel_rule/transaction/validate/full
Validate Full Travel Rule transactions.
Checks for all required information on the originator and beneficiary VASPs.
# Validate Travel Rule Transaction
Source: https://developers.fireblocks.com/api-reference/travel-rule/validate-travel-rule-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/travel_rule/transaction/validate
Validate Travel Rule transactions.
Checks what beneficiary VASP details are required by your jurisdiction and the beneficiary's jurisdiction.
**Deprecation Notice** This endpoint will be deprecated soon in favor of the [validate full](https://developers.fireblocks.com/reference/validatefulltravelruletransaction) endpoint. Please update your integrations to use the [validate full](https://developers.fireblocks.com/reference/validatefulltravelruletransaction) endpoint to ensure compatibility with future releases.
Checks what beneficiary VASP details are required by your jurisdiction and the beneficiary's jurisdiction.
Learn more about Fireblocks Travel Rule management in the following [guide](https://developers.fireblocks.com/docs/define-travel-rule-policies).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Assess Travel Rule requirement
Source: https://developers.fireblocks.com/api-reference/trlink/assess-travel-rule-requirement
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers/integration/{customerIntegrationId}/trm/assess
Assesses travel rule requirement for a transaction by validating stored credentials and determining whether Travel Rule compliance is required based on amount, jurisdiction, and partner thresholds.
# Cancel Travel Rule Message
Source: https://developers.fireblocks.com/api-reference/trlink/cancel-travel-rule-message
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/cancel
Cancels a travel rule message. The TRM status will be updated to cancelled and the partner will be notified.
# Connect customer integration
Source: https://developers.fireblocks.com/api-reference/trlink/connect-customer-integration
https://docs.fireblocks.com/api/v1/swagger.yaml put /screening/trlink/customers/integration/{customerIntegrationId}
Connects a customer integration by providing API credentials. Stores encrypted credentials and enables the integration for use.
# Create customer
Source: https://developers.fireblocks.com/api-reference/trlink/create-customer
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers
Creates a new customer (legal entity/VASP) for TRSupport Travel Rule compliance operations. The customer represents your organization in the Travel Rule network and contains IVMS101-compliant identity information.
# Create customer integration
Source: https://developers.fireblocks.com/api-reference/trlink/create-customer-integration
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers/integration
Creates a new TRSupport integration for a customer. This establishes a connection placeholder between a customer and a Travel Rule partner. Use the connect endpoint to provide credentials after creation. You may optionally supply `customerIntegrationId` in the request body when your tenant is enabled for client-provided integration ids.
# Create Travel Rule Message
Source: https://developers.fireblocks.com/api-reference/trlink/create-travel-rule-message
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers/integration/{customerIntegrationId}/trm
Creates a new travel rule message with IVMS101-compliant PII data. Encrypts sensitive originator and beneficiary information before sending to partner.
# Delete customer
Source: https://developers.fireblocks.com/api-reference/trlink/delete-customer
https://docs.fireblocks.com/api/v1/swagger.yaml delete /screening/trlink/customers/{customerId}
Deletes a customer and all associated integrations. This action cannot be undone.
# Disconnect customer integration
Source: https://developers.fireblocks.com/api-reference/trlink/disconnect-customer-integration
https://docs.fireblocks.com/api/v1/swagger.yaml delete /screening/trlink/customers/integration/{customerIntegrationId}
Disconnects the integration for the authenticated workspace (tenant): removes stored credentials and deletes this tenant's integration record. The operation is scoped to the caller's tenant; it does not remove partner-side state for other workspaces that reuse the same logical customer integration. The record cannot be recovered after delete.
# Get all customers
Source: https://developers.fireblocks.com/api-reference/trlink/get-all-customers
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers
Retrieves all customers associated with the authenticated tenant. Returns a list of legal entities configured for Travel Rule compliance.
# Get customer by ID
Source: https://developers.fireblocks.com/api-reference/trlink/get-customer-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/{customerId}
Retrieves detailed information about a specific customer by their unique identifier.
# Get customer integration by ID
Source: https://developers.fireblocks.com/api-reference/trlink/get-customer-integration-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/{customerId}/integrations/{customerIntegrationId}
Retrieves detailed information about a specific customer integration.
# Get customer integrations
Source: https://developers.fireblocks.com/api-reference/trlink/get-customer-integrations
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/{customerId}/integrations
Retrieves all TRSupport integrations for a specific customer. Returns a list of partner integrations configured for Travel Rule compliance.
# Get public key for PII encryption
Source: https://developers.fireblocks.com/api-reference/trlink/get-public-key-for-pii-encryption
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/integration/{customerIntegrationId}/public_key
Retrieves the partner's public key in JWK format for encrypting PII data in Travel Rule Messages. Use this key to encrypt sensitive originator and beneficiary information before sending Travel Rule messages.
# Get required actions for a TRM
Source: https://developers.fireblocks.com/api-reference/trlink/get-required-actions-for-a-trm
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/required_actions
Retrieves the list of required actions (e.g., PII fields) needed to process the Travel Rule Message.
# Get supported asset by ID
Source: https://developers.fireblocks.com/api-reference/trlink/get-supported-asset-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/integration/{customerIntegrationId}/assets/{assetId}
Retrieves detailed information about a specific asset by its Fireblocks asset ID. Returns the transformed Fireblocks asset data, raw partner response, and support status.
# Get TRLink policy
Source: https://developers.fireblocks.com/api-reference/trlink/get-trlink-policy
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/policy
Retrieves the complete TRSupport policy for the authenticated tenant, including pre-screening rules, post-screening rules, and missing TRM rules. Pre-screening rules determine whether transactions should be screened. Post-screening rules determine actions based on screening results. Missing TRM rules handle cases when screening data is unavailable.
# Get TRM by ID
Source: https://developers.fireblocks.com/api-reference/trlink/get-trm-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}
Retrieves a Travel Rule Message by its unique identifier from the partner provider. Returns full TRM details including status, IVMS101 data, and transaction information.
# Get VASP by ID
Source: https://developers.fireblocks.com/api-reference/trlink/get-vasp-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/integration/{customerIntegrationId}/vasps/{vaspId}
Retrieves detailed information about a specific VASP by its unique identifier. Returns VASP details including public key if available.
# List available TRSupport partners
Source: https://developers.fireblocks.com/api-reference/trlink/list-available-trsupport-partners
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/partners
Retrieves a list of all available Travel Rule Support integration partners. Partners provide Travel Rule compliance services such as VASP discovery, TRM exchange, and PII encryption.
# List supported assets
Source: https://developers.fireblocks.com/api-reference/trlink/list-supported-assets
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/integration/{customerIntegrationId}/assets
Retrieves a paginated list of assets supported by the partner integration. Includes a flag indicating whether the partner can handle assets not explicitly listed. Supports cursor-based pagination.
# List VASPs
Source: https://developers.fireblocks.com/api-reference/trlink/list-vasps
https://docs.fireblocks.com/api/v1/swagger.yaml get /screening/trlink/customers/integration/{customerIntegrationId}/vasps
Retrieves a paginated list of VASPs (Virtual Asset Service Providers) available through the partner integration. Supports cursor-based pagination.
# Manual decision for missing TRM
Source: https://developers.fireblocks.com/api-reference/trlink/manual-decision-for-missing-trm
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers/integration/{customerIntegrationId}/transactions/{txId}/manual_decision
Accept or reject destinations stuck in NoTRM step without waiting for TRP webhook or policy timeout.
# Redirect Travel Rule Message
Source: https://developers.fireblocks.com/api-reference/trlink/redirect-travel-rule-message
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/redirect
Redirects a Travel Rule Message to a subsidiary VASP. This operation requires the partner to support nested VASPs functionality.
# Resolve action for a TRM
Source: https://developers.fireblocks.com/api-reference/trlink/resolve-action-for-a-trm
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/resolve_action
Submits required data (e.g., beneficiary PII) to resolve a pending Travel Rule Message action.
# Set destination travel rule message ID
Source: https://developers.fireblocks.com/api-reference/trlink/set-destination-travel-rule-message-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/transaction/{txId}/destination/travel_rule_message_id
Associates a Travel Rule Message ID with a specific destination in a multi-destination Fireblocks transaction. Matches destinations by amount and peer path.
# Set transaction travel rule message ID
Source: https://developers.fireblocks.com/api-reference/trlink/set-transaction-travel-rule-message-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/transaction/{txId}/travel_rule_message_id
Associates a Travel Rule Message ID with a Fireblocks transaction. This links the TRM compliance data to the blockchain transaction.
# Test connection
Source: https://developers.fireblocks.com/api-reference/trlink/test-connection
https://docs.fireblocks.com/api/v1/swagger.yaml post /screening/trlink/customers/integration/{customerIntegrationId}/test_connection
Tests the connection to a customer integration by validating stored credentials and attempting communication with the Travel Rule partner. Returns connection status and any error messages.
# Update customer
Source: https://developers.fireblocks.com/api-reference/trlink/update-customer
https://docs.fireblocks.com/api/v1/swagger.yaml put /screening/trlink/customers/{customerId}
Updates an existing customer's information. All fields are optional - only provided fields will be updated.
# Create user group
Source: https://developers.fireblocks.com/api-reference/user-groups-beta/create-user-group
https://docs.fireblocks.com/api/v1/swagger.yaml post /management/user_groups
Create a new user group. Users with the Viewer role cannot be added to groups.
Endpoint Permission: Admin, Non-Signing Admin.
# Delete user group
Source: https://developers.fireblocks.com/api-reference/user-groups-beta/delete-user-group
https://docs.fireblocks.com/api/v1/swagger.yaml delete /management/user_groups/{groupId}
Delete a user group by ID.
**Note**:
- This endpoint is now in Beta, disabled for general availability at this time.
- Please note that this endpoint is available only for API keys with Admin permissions.
# Get user group
Source: https://developers.fireblocks.com/api-reference/user-groups-beta/get-user-group
https://docs.fireblocks.com/api/v1/swagger.yaml get /management/user_groups/{groupId}
Get a user group by ID.
**Note**:
- This endpoint is now in Beta, disabled for general availability at this time.
- Please note that this endpoint is available only for API keys with Admin permissions.
# List user groups
Source: https://developers.fireblocks.com/api-reference/user-groups-beta/list-user-groups
https://docs.fireblocks.com/api/v1/swagger.yaml get /management/user_groups
Get all user groups in your workspace
- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.
Endpoint Permission: Admin, Non-Signing Admin.
# Update user group
Source: https://developers.fireblocks.com/api-reference/user-groups-beta/update-user-group
https://docs.fireblocks.com/api/v1/swagger.yaml put /management/user_groups/{groupId}
Update a user group by ID.
**Note**:
- This endpoint is now in Beta, disabled for general availability at this time.
- Please note that this endpoint is available only for API keys with Admin permissions.
# List users
Source: https://developers.fireblocks.com/api-reference/users/list-users
https://docs.fireblocks.com/api/v1/swagger.yaml get /users
List all users for the workspace.
Please note that this endpoint is available only for API keys with Admin permissions.
# Attach or detach labels to/from UTXOs
Source: https://developers.fireblocks.com/api-reference/utxo-management-beta/attach-or-detach-labels-tofrom-utxos
https://docs.fireblocks.com/api/v1/swagger.yaml patch /utxo_management/{vaultAccountId}/{assetId}/labels
Attach or detach labels to/from UTXOs in a vault account. Labels can be used for organizing and filtering UTXOs.
Labels are applied additively — `labelsToAttach` adds to the existing label set and `labelsToDetach` removes from it. Neither operation replaces the full set.
**Note:** These endpoints are currently in beta and might be subject to changes.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# List unspent outputs (UTXOs)
Source: https://developers.fireblocks.com/api-reference/utxo-management-beta/list-unspent-outputs-utxos
https://docs.fireblocks.com/api/v1/swagger.yaml get /utxo_management/{vaultAccountId}/{assetId}/unspent_outputs
Returns a paginated list of unspent transaction outputs (UTXOs) for a UTXO-based asset in a vault account, with optional filters for labels, statuses, amounts, and more.
**Note:** These endpoints are currently in beta and might be subject to changes.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Activate a Circle Gateway wallet
Source: https://developers.fireblocks.com/api-reference/vaults/activate-a-circle-gateway-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/circle_gateway/activate
Activates the Circle Gateway wallet associated with the given vault account. If the wallet does not yet exist it is created in an activated state.
**Note:** This endpoint is currently in beta and might be subject to changes.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver.
# Activate a wallet in a vault account
Source: https://developers.fireblocks.com/api-reference/vaults/activate-a-wallet-in-a-vault-account
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/{assetId}/activate
Initiates activation for a wallet in a vault account.
Activation is required for tokens that need an on-chain transaction for creation (XLM tokens, SOL tokens etc).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Assign AML customer reference ID
Source: https://developers.fireblocks.com/api-reference/vaults/assign-aml-customer-reference-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}/set_customer_ref_id
Sets an AML/KYT customer reference ID for a specific address.
Endpoint Permission: Admin, Non-Signing Admin.
# Attach or detach tags from vault accounts
Source: https://developers.fireblocks.com/api-reference/vaults/attach-or-detach-tags-from-vault-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/attached_tags
Attach or detach one or more tags from the requested vault accounts.
Endpoint Permission: For protected tags: Owner, Admin, Non-Signing Admin. For non protected tags: Owner, Admin, Non-Signing Admin, Signer, Editor, Approver.
# Bulk creation of new deposit addresses
Source: https://developers.fireblocks.com/api-reference/vaults/bulk-creation-of-new-deposit-addresses
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/addresses/bulk
**For UTXO blockchains only.**
Create multiple deposit addresses by running an async job.
- The target Vault account should already have a UTXO asset wallet with a permanent address.
- Limited to a maximum of 10,000 addresses per operation. Use multiple operations for the same Vault account/permanent address if needed.
**Endpoint Permissions:** Admin, Non-Signing Admin.
# Bulk creation of new vault accounts
Source: https://developers.fireblocks.com/api-reference/vaults/bulk-creation-of-new-vault-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/bulk
Create multiple vault accounts by running an async job.
- The HBAR, TON, SUI, TERRA, ALGO, and DOT blockchains are not supported.
- These endpoints are currently in beta and might be subject to changes.
- Limited to a maximum of 10,000 accounts per operation.
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor.
# Convert a segwit address to legacy format
Source: https://developers.fireblocks.com/api-reference/vaults/convert-a-segwit-address-to-legacy-format
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}/create_legacy
Converts an existing segwit address to the legacy format.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create a new vault account
Source: https://developers.fireblocks.com/api-reference/vaults/create-a-new-vault-account
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts
Creates a new vault account with the requested name.
**Note: ** Vault account names should consist of ASCII characters only.
Learn more about Fireblocks Vault Accounts in the following [guide](https://developers.fireblocks.com/reference/create-vault-account).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create a new vault wallet
Source: https://developers.fireblocks.com/api-reference/vaults/create-a-new-vault-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/{assetId}
Creates a wallet for a specific asset in a vault account.
Learn more about Fireblocks Vault Wallets in the following [guide](https://developers.fireblocks.com/reference/create-vault-wallet).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create new asset deposit address
Source: https://developers.fireblocks.com/api-reference/vaults/create-new-asset-deposit-address
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/{assetId}/addresses
Creates a new deposit address for an asset of a vault account.
Should be used for UTXO or Tag/Memo based assets ONLY.
Requests with account based assets will fail.
Endpoint Permission: Admin, Non-Signing Admin.
# Deactivate a Circle Gateway wallet
Source: https://developers.fireblocks.com/api-reference/vaults/deactivate-a-circle-gateway-wallet
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/circle_gateway/deactivate
Deactivates the Circle Gateway wallet associated with the given vault account.
**Note:** This endpoint is currently in beta and might be subject to changes.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver.
# Get a vault account by ID
Source: https://developers.fireblocks.com/api-reference/vaults/get-a-vault-account-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}
Get a vault account by its unique ID.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get addresses (Paginated)
Source: https://developers.fireblocks.com/api-reference/vaults/get-addresses-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}/{assetId}/addresses_paginated
Returns a paginated response of the addresses for a given vault account and asset.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get an asset's public key
Source: https://developers.fireblocks.com/api-reference/vaults/get-an-assets-public-key
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}/{assetId}/{change}/{addressIndex}/public_key_info
Get the public key information for a specific asset in a vault account.
Endpoint Permission: Admin, Non-Signing Admin.
# Get asset addresses
Source: https://developers.fireblocks.com/api-reference/vaults/get-asset-addresses
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}/{assetId}/addresses
DEPRECATED!
- If your application logic or scripts rely on the deprecated endpoint, you should update to account for GET/V1/vault/accounts/{vaultAccountId}/{assetId}/addresses_paginated before Mar 31,2024.
- All workspaces created after Mar 31,2024. will have it disabled. If it is disabled for your workspace and you attempt to use it, you will receive the following error message: "This endpoint is unavailable.
- Please use the GET /v1/vault/accounts/{vaultAccountId}/{assetId}/addresses_paginated endpoint to return all the wallet addresses associated with the specified vault account and asset in a paginated list.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get asset balance for chosen assets
Source: https://developers.fireblocks.com/api-reference/vaults/get-asset-balance-for-chosen-assets
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/assets
Gets the assets amount summary for all accounts or filtered accounts.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get Circle Gateway wallet info
Source: https://developers.fireblocks.com/api-reference/vaults/get-circle-gateway-wallet-info
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}/circle_gateway
Returns the Circle Gateway wallet information associated with the given vault account.
**Note:** This endpoint is currently in beta and might be subject to changes.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get job status of bulk creation of new vault accounts
Source: https://developers.fireblocks.com/api-reference/vaults/get-job-status-of-bulk-creation-of-new-vault-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/bulk/{jobId}
Returns the current status of (or error for) the specified vault account bulk creation job.
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get max spendable amount in a transaction
Source: https://developers.fireblocks.com/api-reference/vaults/get-max-spendable-amount-in-a-transaction
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}/{assetId}/max_spendable_amount
**UTXO assets only.**
Retrieve the maximum amount of the specified asset that can be spent in a single transaction from the specified vault account.
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get maximum BIP44 index used
Source: https://developers.fireblocks.com/api-reference/vaults/get-maximum-bip44-index-used
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}/{assetId}/max_bip44_index_used
Retrieves the maximum BIP44 address index and change address index used for a specific asset in a vault account (BIP44 standard).
# Get the asset balance for a vault account
Source: https://developers.fireblocks.com/api-reference/vaults/get-the-asset-balance-for-a-vault-account
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}/{assetId}
Returns a specific vault wallet balance information for a specific asset.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor,
Viewer.
# Get the job status of the bulk deposit address creation
Source: https://developers.fireblocks.com/api-reference/vaults/get-the-job-status-of-the-bulk-deposit-address-creation
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/addresses/bulk/{jobId}
Returns the current status of (or an error for) the specified deposit addresss bulk creation job.
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, and Viewer.
# Get the public key for a derivation path
Source: https://developers.fireblocks.com/api-reference/vaults/get-the-public-key-for-a-derivation-path
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/public_key_info
Gets the public key information based on derivation path and signing algorithm.
Endpoint Permission: Admin, Non-Signing Admin.
# Get UTXO unspent inputs information
Source: https://developers.fireblocks.com/api-reference/vaults/get-utxo-unspent-inputs-information
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts/{vaultAccountId}/{assetId}/unspent_inputs
Returns unspent inputs information of an UTXO asset in a vault account.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get vault accounts
Source: https://developers.fireblocks.com/api-reference/vaults/get-vault-accounts
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts
DEPRECATED - Please use `/vault/accounts_paged` endpoint instead.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get vault accounts (Paginated)
Source: https://developers.fireblocks.com/api-reference/vaults/get-vault-accounts-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/accounts_paged
Gets all vault accounts in your workspace. This endpoint returns a limited amount of results with a quick response time.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get vault balance by an asset
Source: https://developers.fireblocks.com/api-reference/vaults/get-vault-balance-by-an-asset
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/assets/{assetId}
Get the total balance of an asset across all the vault accounts.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Get vault wallets (Paginated)
Source: https://developers.fireblocks.com/api-reference/vaults/get-vault-wallets-paginated
https://docs.fireblocks.com/api/v1/swagger.yaml get /vault/asset_wallets
Get all vault wallets of the vault accounts in your workspace.
A vault wallet is an asset in a vault account.
This method allows fast traversal of all account balances.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.
# Hide a vault account in the console
Source: https://developers.fireblocks.com/api-reference/vaults/hide-a-vault-account-in-the-console
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/hide
Hides the requested vault account from the web console view.
This operation is required when creating thousands of vault accounts to serve your end-users.
Used for preventing the web console to be swamped with too much vault accounts.
Learn more in the following [guide](https://developers.fireblocks.com/docs/create-direct-custody-wallets#hiding-vault-accounts).
NOTE: Hiding the vault account from the web console will also hide all the related transactions to/from this vault.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Refresh asset balance data
Source: https://developers.fireblocks.com/api-reference/vaults/refresh-asset-balance-data
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/{assetId}/balance
Updates the balance of a specific asset in a vault account.
This API endpoint is subject to a strict rate limit.
Should be used by clients in very specific scenarios.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Rename a vault account
Source: https://developers.fireblocks.com/api-reference/vaults/rename-a-vault-account
https://docs.fireblocks.com/api/v1/swagger.yaml put /vault/accounts/{vaultAccountId}
Renames the requested vault account.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver.
# Set an AML/KYT ID for a vault account
Source: https://developers.fireblocks.com/api-reference/vaults/set-an-amlkyt-id-for-a-vault-account
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/set_customer_ref_id
Assigns an AML/KYT customer reference ID for the vault account. Learn more about Fireblocks AML management in the following [guide](https://developers.fireblocks.com/docs/define-aml-policies). Endpoint Permission: Admin, Non-Signing Admin.
# Set auto fueling to on or off
Source: https://developers.fireblocks.com/api-reference/vaults/set-auto-fueling-to-on-or-off
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/set_auto_fuel
Toggles the auto fueling property of the vault account to enabled or disabled.
Vault Accounts with 'autoFuel=true' are monitored and auto fueled by the Fireblocks Gas Station.
Learn more about the Fireblocks Gas Station in the following [guide](https://developers.fireblocks.com/docs/work-with-gas-station).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Unhide a vault account in the console
Source: https://developers.fireblocks.com/api-reference/vaults/unhide-a-vault-account-in-the-console
https://docs.fireblocks.com/api/v1/swagger.yaml post /vault/accounts/{vaultAccountId}/unhide
Makes a hidden vault account visible in web console view.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Update address description
Source: https://developers.fireblocks.com/api-reference/vaults/update-address-description
https://docs.fireblocks.com/api/v1/swagger.yaml put /vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}
Updates the description of an existing address of an asset in a vault account.
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Create a new Web3 connection.
Source: https://developers.fireblocks.com/api-reference/web3-connections/create-a-new-web3-connection
https://docs.fireblocks.com/api/v1/swagger.yaml post /connections/wc
Initiate a new Web3 connection.
* Note: After this succeeds, make a request to `PUT /v1/connections/wc/{id}` (below) to approve or reject the new Web3 connection.
# List all open Web3 connections.
Source: https://developers.fireblocks.com/api-reference/web3-connections/list-all-open-web3-connections
https://docs.fireblocks.com/api/v1/swagger.yaml get /connections
Get open Web3 connections.
# Remove an existing Web3 connection.
Source: https://developers.fireblocks.com/api-reference/web3-connections/remove-an-existing-web3-connection
https://docs.fireblocks.com/api/v1/swagger.yaml delete /connections/wc/{id}
Remove a Web3 connection
# Respond to a pending Web3 connection request.
Source: https://developers.fireblocks.com/api-reference/web3-connections/respond-to-a-pending-web3-connection-request
https://docs.fireblocks.com/api/v1/swagger.yaml put /connections/wc/{id}
Submit a response to *approve* or *reject* an initiated Web3 connection.
* Note: This call is used to complete your `POST /v1/connections/wc/` request.
After this succeeds, your new Web3 connection is created and functioning.
# Create a new webhook
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/create-a-new-webhook
https://docs.fireblocks.com/api/v1/swagger.yaml post /webhooks
Creates a new webhook, which will be triggered on the specified events
**Endpoint Permissions:** Owner, Admin, Non-Signing Admin.
# Delete webhook
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/delete-webhook
https://docs.fireblocks.com/api/v1/swagger.yaml delete /webhooks/{webhookId}
Delete a webhook by its id
Endpoint Permission: Owner, Admin, Non-Signing Admin.
# Get all notifications by webhook id
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/get-all-notifications-by-webhook-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /webhooks/{webhookId}/notifications
Get all notifications by webhook id (paginated)
# Get all webhooks
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/get-all-webhooks
https://docs.fireblocks.com/api/v1/swagger.yaml get /webhooks
Get all webhooks (paginated).
# Get notification attempts
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/get-notification-attempts
https://docs.fireblocks.com/api/v1/swagger.yaml get /webhooks/{webhookId}/notifications/{notificationId}/attempts
Get notification attempts by notification id
# Get notification by id
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/get-notification-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /webhooks/{webhookId}/notifications/{notificationId}
Get notification by id
# Get resend by query job status
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/get-resend-by-query-job-status
https://docs.fireblocks.com/api/v1/swagger.yaml get /webhooks/{webhookId}/notifications/resend_by_query/jobs/{jobId}
Get the status of a resend by query job
# Get resend job status
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/get-resend-job-status
https://docs.fireblocks.com/api/v1/swagger.yaml get /webhooks/{webhookId}/notifications/resend_failed/jobs/{jobId}
Get the status of a resend job
# Get webhook by id
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/get-webhook-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml get /webhooks/{webhookId}
Retrieve a webhook by its id
# Get webhook metrics
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/get-webhook-metrics
https://docs.fireblocks.com/api/v1/swagger.yaml get /webhooks/{webhookId}/metrics/{metricName}
Get webhook metrics by webhook id and metric name
# Resend failed notifications
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/resend-failed-notifications
https://docs.fireblocks.com/api/v1/swagger.yaml post /webhooks/{webhookId}/notifications/resend_failed
Resend all failed notifications for a webhook in the last 24 hours
Endpoint Permission: Owner, Admin, Non-Signing Admin, Editor, Signer.
# Resend notification by id
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/resend-notification-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /webhooks/{webhookId}/notifications/{notificationId}/resend
Resend notification by ID
Endpoint Permission: Owner, Admin, Non-Signing Admin, Editor, Signer.
# Resend notifications by query
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/resend-notifications-by-query
https://docs.fireblocks.com/api/v1/swagger.yaml post /webhooks/{webhookId}/notifications/resend_by_query
Resend notifications matching the given query filters (statuses, events, time range, resource ID)
Endpoint Permission: Owner, Admin, Non-Signing Admin, Editor, Signer.
# Resend notifications by resource Id
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/resend-notifications-by-resource-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /webhooks/{webhookId}/notifications/resend_by_resource
Resend notifications by resource Id
Endpoint Permission: Owner, Admin, Non-Signing Admin, Editor, Signer.
# Update webhook
Source: https://developers.fireblocks.com/api-reference/webhooks-v2/update-webhook
https://docs.fireblocks.com/api/v1/swagger.yaml patch /webhooks/{webhookId}
Update a webhook by its id
Endpoint Permission: Owner, Admin, Non-Signing Admin.
# Resend failed webhooks
Source: https://developers.fireblocks.com/api-reference/webhooks/resend-failed-webhooks
https://docs.fireblocks.com/api/v1/swagger.yaml post /webhooks/resend
Resends all failed webhook notifications.
Learn more about Fireblocks Webhooks in the following [guide](https://developers.fireblocks.com/docs/configure-webhooks).
Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.
# Resend webhooks for a transaction by ID
Source: https://developers.fireblocks.com/api-reference/webhooks/resend-webhooks-for-a-transaction-by-id
https://docs.fireblocks.com/api/v1/swagger.yaml post /webhooks/resend/{txId}
Resends webhook notifications for a transaction by its unique identifier.
Learn more about Fireblocks Webhooks in the following [guide](https://developers.fireblocks.com/docs/configure-webhooks).
**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor.
# Get whitelisted ip addresses for an API Key
Source: https://developers.fireblocks.com/api-reference/whitelist-ip-addresses/get-whitelisted-ip-addresses-for-an-api-key
https://docs.fireblocks.com/api/v1/swagger.yaml get /management/api_users/{userId}/whitelist_ip_addresses
Get a list of the whitelisted IP addresses for a specific API Key
- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.
Endpoint Permission: Admin, Non-Signing Admin.
# Returns current workspace status
Source: https://developers.fireblocks.com/api-reference/workspace-status-beta/returns-current-workspace-status
https://docs.fireblocks.com/api/v1/swagger.yaml get /management/workspace_status
Returns current workspace status (Beta).
**Note**:
- This endpoint is now in Beta, disabled for general availability at this time.
- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.
Endpoint Permission: Admin, Non-Signing Admin.
# Freeze
Source: https://developers.fireblocks.com/api-reference/workspace/freeze
https://docs.fireblocks.com/api/v1/swagger.yaml post /workspace/freeze
Freezes a Workspace so that ALL operations by ANY user are blocked.
You should only perform this action when the workspace faces imminent risk, such as when you have a security breach.
To unfreeze a workspace, the workspace Owner must submit a request to Fireblocks Support.
**NOTE:**
- This operation can only be performed by the workspace Admins - Your workspace continues to receive incoming transfers during this time.
Endpoint Permission: Admin, Non-Signing Admin.
# Get workspace
Source: https://developers.fireblocks.com/api-reference/workspace/get-workspace
https://docs.fireblocks.com/api/v1/swagger.yaml get /workspace
Returns the workspace ID and name for the authenticated user.
# Changelog
Source: https://developers.fireblocks.com/changelog
# Constructing Encrypted PII Messages for Exchanges via Fireblocks
Source: https://developers.fireblocks.com/docs/a-developers-guide-to-constructing-encrypted-pii-messages-for-binance-via-fireblocks
## Introduction
For institutions using Fireblocks to transact with major exchanges like Binance and Bitstamp, correctly constructing and transmitting Personally Identifiable Information (PII) is critical for ensuring regulatory compliance and the successful processing of transactions. Sending PII requires a robust security model that goes beyond standard transport-layer encryption.
This guide provides a practical, compliance-aware walkthrough for developers and compliance officers on how to structure the PII payload, handle the necessary encryption, and correctly format the `transaction.extraParameters` object in the Fireblocks API. It breaks down each field and explains the specific data requirements based on key global jurisdictions.
For step-by-step instructions on completing Travel Rule compliance through the Fireblocks Console UI, see [Travel Rule compliance for exchange transactions](https://support.fireblocks.io/hc/en-us/articles/20851702645404-Travel-Rule-compliance-for-exchange-transactions).
### Note for Compliance Officers
This document details the technical data structure for compliant PII transmission. The core obligation is to ensure your institution has a robust AML/CFT program that includes counterparty due diligence, risk-based transaction monitoring, and adherence to the specific data requirements of all relevant jurisdictions.
## Core concept: End-to-end encryption of PII
It is critical to understand that you must **never** send raw, unencrypted PII in an API call. The `piiData` object detailed in this guide represents the plaintext data structure that must be encrypted *before* it is submitted to the Fireblocks API.
Fireblocks documentation indicates that PII encryption is a **manual implementation step** that developers must handle. This ensures a secure, end-to-end model where only the intended recipient (in this case, the specific exchange entity) can decrypt and access the sensitive user data.
## Exchange PII data encryption guide (RSA-only model)
### Overview
We only support **RSA-only encryption** for PII data transmission. Exchanges do not accept hybrid encryption (RSA + AES). Using hybrid encryption will result in failed Travel Rule submissions or empty compliance data.
### RSA-only encryption model
This method encrypts the **entire PII data payload directly** with the recipient's (exchange's) RSA public key, without generating a separate AES key:
**Process**:
1. **Direct RSA Encryption:** Serialize the PII data to JSON and encrypt the whole payload using RSA-OAEP with SHA-256. Each value should be encrypted (see examples below).
2. **Single Encrypted Blob:** The result is a single base64-encoded string containing the encrypted PII data.
3. **Send in API Call:** Pass this encrypted blob in the `piiData` field of the Fireblocks transaction request.
## Production usage: Encryption & Transaction creation
In a production environment, you must fetch the public key from Fireblocks to encrypt the PII data.
### Example: RSA-only encryption utility
```typescript theme={"system"}
import * as forge from 'node-forge';
/**
* EXAMPLE: Encrypts each PII field individually using RSA-only encryption
*
* This is a simplified example showing how you could implement individual field encryption.
* Each developer should customize this approach based on their specific needs.
*
* @param piiData - PII data object to encrypt field by field
* @param publicKey - RSA public key in PEM format
* @returns Promise - Data with each field encrypted individually
*/
export async function encryptPiiFieldsIndividually(piiData: any, publicKey: string): Promise {
/**
* Implementation approach:
* 1. Takes the original piiData object
* 2. Recursively walks through each field
* 3. Encrypts each string value separately using RSA encryptWithRSAOnly()
* 4. Returns the same object structure but with encrypted values
*
* Note: This is an EXAMPLE implementation. Developers should customize
* this logic based on their specific requirements and data structures.
*/
// Simple recursive function to encrypt string values
async function encryptPrimitives(obj: any): Promise {
// Encrypt all primitive values except null/undefined
if (obj === null || obj === undefined) {
return obj;
}
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') {
return await encryptWithRSAOnly(obj, publicKey);
}
if (Array.isArray(obj)) {
return Promise.all(obj.map(item => encryptPrimitives(item)));
}
if (typeof obj === 'object') {
const result: any = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = await encryptPrimitives(value);
}
return result;
}
return obj;
}
const result = JSON.parse(JSON.stringify(piiData)); // Deep clone
if (result.extraParameters?.piiData?.data) {
result.extraParameters.piiData.data = await encryptStrings(result.extraParameters.piiData.data);
} else {
return await encryptStrings(result);
}
return result;
}
```
### Example: Creating an exchange Fireblocks transaction with RSA-only encryption
```typescript theme={"system"}
import { FireblocksSDK } from "fireblocks-sdk";
import { encryptWithRSAOnly } from './encryptWithRSAOnly';
import { piiData } from './piiPayload';
const fireblocksSDK = new FireblocksSDK(privateKey, apiKey, baseUrl);
async function getExchangePublicKey() {
try {
const credentialsResponse = await fireblocksSDK.getExchangeAccountsCredentialsPublicKey({
// Specify exchange exchange account ID
});
return credentialsResponse.publicKey;
} catch (error) {
console.error('Failed to get exchange public key:', error);
throw error;
}
}
async function createExchangeTransaction() {
// 1. Get exchange's public key from Fireblocks
const publicKey = await getExchangePublicKey();
// 2. RSA-only encrypt each PII field individually
const encryptedPiiData = await encryptPiiFieldsIndividually(piiData, publicKey);
// 3. Build the Fireblocks transaction request
const transactionRequest = {
operation: "TRANSFER",
source: { type: "VAULT_ACCOUNT", id: "1" },
destination: { type: "EXCHANGE_ACCOUNT", id: "exchange_account_id" },
amount: "100",
assetId: "BTC",
extraParameters: {
piiData: encryptedPiiData
}
};
// 4. Send the transaction
const result = await fireblocksSDK.createTransaction(transactionRequest);
console.log('Exchange transaction created:', result.id);
return result;
}
createExchangeTransaction()
.then(() => console.log("PII transaction sent successfully to exchange."))
.catch(console.error);
```
## Real-world PII data example 1: Binance - Compact French withdrawal scenario
This example demonstrates a common real-world scenario where minimal required information is provided for a withdrawal.
* **Transaction Type:** Withdrawal
* **Jurisdiction:** France (FR)
* **Relationship:** ThirdParty
* **Entity:** Individual
**Scenario:** A user is making a withdrawal from their exchange account to another beneficiary, where the user is an individual located in France.
### Example: Before encryption (Compact PII data)
```json theme={"system"}
{
"extraParameters": {
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "BE"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "FR"
}
}
}
}
}
```
### Example: After encryption (Compact encrypted data)
```json theme={"system"}
{
"extraParameters": {
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "DkGFzfPCLi3SNl6BrrS1C4X/DmuqfVvU83iczY+pDgamI3FUTmzghoGvtjERSH6uqKo3h9gwAWQN8mYV7PGdgkV7cnSS6/H4CNJWV7BlN63RU7DmsmVdHoGbA0F7GnriQvKlnTFPU/CCXJDcsaXG7cHa5VtST8rw+acw73fnUpwUnGMLnw0QOUoYrvu6eGo+BX1aZu+Ve0hrhJTcYXXfnvekkXWCLxDu8AYltJSy4YgzsFNvHb3JyOOuPvJg3qka2NfVrzRXv+7pQy6c4eyErfBJZ6T8i/WXsu9gVZXuOC24wtZi99pP2XGz9ogW2hv9edmEUTitZXneWm26sbtwN9jBPVh4ZRLfGg9wxV1fN/g6MPVbil7Ilu6olO9gRlPj2GUyFIfNPFAziqGEw7CEFvPlQuLv5n2/Pbh98jS/sGANwjKZhXBKyy79WLs/HDVZw6E99+Vxf786HdmIc4MEyj+AELhqcdp8uF0D1/xA+hDFiDpcZjV3JASX9b8EPOaxix9P7TdPepoFoZo4fJFQtaXvAunnsYiG2bE/NareEjLZvqcHadeaCdy29sXCmxeaj1v5hL5GZJFFkBEUa9QLcle0YXQQa3ukkc1W0tChIeGwSEY/qNW/FZ5jg3Pqm8gpdwGzd0gZk/JO8YDIthtTRdgm7zjydIxVZGChTO/h4WM=",
"entityType": "CvnHs/CzrfdTpGukJXmJH+88n2cW9C0Ezc6HtJtDzN6+e7dk+GoGrK/ia9Kptncrh7Q+6AVHR3pmrJFH10Y8kwxLoNOmJkPtNDJLoVPDSxAn4So7Jw0mA+OGXu8J1e/b1v9u4g3/2L5373MURnsrMydU0vt77YaBZgmZo0dtukLE4kGTnW2lUKexdeRs6NR99r+VQNYG38XGi2/OAjwvBPIAxfmaXBoNMCVda0JZkjlweezwIGL8theV+RMPtQBm8mUsBpbcIiBLAFA4/pQgCKVHZuUMkfaSXh6zPBga6hQu4N0fhLxTj1VwW1Mocd373ifUAn5mziMB4tunObI6jy91s0zunmIajZeHqxIvxci1sMEI6RXnuzKfbkadUzM9cyUMjnzkrQk5q5VuurxfZRqFHuw9Ikq8dNUavAetwgJipUi2aTVh0+uVgZ84QKusJ08LqD3N4k6eghZwIDUkCFXNZnK1reK+oIqGcbs8y0r+Vmr1zh5GukA55+yqRJXu/YxAlS3HIwp+HnhSvM8Wz1O5/PgCHm2iRcP3+pCYWJltkPoKPzynurAN6I1tGSak7+AiPwiJsd5sqdNylR5eFR4N28U61vYhk4nebsvvI5J+7M9+f25hs4hDloV+bmj0wzN3QnCRS3RyaPg91fdCo2iTR5PTuLvjVJ0GX/h1674=",
"names": [
{
"primaryName": "SpDXvmGFXH3qe0jAVZeinBniH18VBPsAqnLz+SxidNd9Hh6XKbs10cHMPoda4Yga3dDLXSZTRMb9hJPbsYlanFgWpcIW6rq4KGeK/Q9LiN1gVSGwZrXMD2Jx/3+hPVcSUqYqGiirZpoeQqJUTzmJvglRCWDDNbE88jFcQ+XEvj0v9tC1rrHrxrowe1QaxFeOt8HMl2PjGVzUGCD9QdRsG0DbBa4To49EsvXl6qCMr11pioCWzAVgYxRJU5HlfikbsU00dxXTVVaHAFGfGgeTSBBVpNLTvUuk7Q4CW4TIa9PiDYiZsT9KW3X0tjXLs0xflrUXMXUWDC3bVfEMcFtM75YyOFrMY4IhGfyND6o+4MyeqC7LmYc09o9wmheiRS/l3J77SNc8w7tlqoSgvVVb45TDpBtf611SQ8GnCQ9rTg9rKROwPXA58micxFKrgVVYfY+E0uo90kzs/Hfw0OohrC/3vS6d3ocXAEp8FEtmCvyRxK+xgTv3obIzL6eVqI2TBDkkyjT3gGBrbS0a8GPZSKUw9W0cNnYjxZ/rxF1xBUG1gg+cE7St2yNwQ9m3gcneoB8U3AA5y/f5Zw7iz5ekAmMdrUFWf5ENNodNNv66KVNQLwpSIWeHiVkr5mqEIooAJDaFDaYKw6A2GRJzU+ZQ7ca3rOumleUq6kXfQcCmpr4=",
"nameType": "UFvT9EbXqfGJGH3UPsXtRbwyi9VDb3JgEyGXDM6x4Pkk/R8nlfEVnKFSmt0LSU1Vnzl/k8pjMsLcap33RDENMWTRAfjasnqDK7uZCNO8m37SBZiTLmTYrX3k5V4hF0p6SQqvltPV4cye4AwALxZKtc95jzsfJUxgylaXbmuR8+W8RoHZrhid4YCFmarpC8xCz0fcrWrbRtfV/wuv4wHotkX7SQJj0pf31xsRjfDYIV6Fo0tlnhI1JTdVh+ztE9e76OcRdlpM2Fk7UM42+CXUSvvO3iP4E1ot5K7O+u+3a8pcVWNbAIycLlz79fz2LFXiQ7jc63Yg/sG/P2yQqk/ivDT/ZWjSoCNlB8oi7VDpL2ir0Xwh1+D6I9n6f1G4jc0Fkqr0DP00P93jpmBQzqPi2V7TBrnIwxPnQeEzj1SXE0ENMbj2P/PGeinGW34h6/0WFKyyOubMqLnvG5lPUusFPA7NFY7NdS/1OAU/y4J52R9YFWkW9o2jdn9G3iLbjNKx8g0yRbnT0sTXql9E+VCv2HPYS1Wuoqo/S1LhG6j0y9ugUCS1+advbxHm0/4ZD5zJ4+5FHIlH8s5+CJ7/FGFsRRN/R2jAW9GSqdzczzYm4X24l8cn4xHRWR2XO0jqlYmoH8sBMrZVgfvJnDy4KotlthZT5ooIOQJY+58x6gXnUL0=",
"secondaryName": "KjXjKySekOb13IvuP4ainsMzGCmxK9CUeVI6VMLp3MYxz1zFbZBq95v8Ly5TBoH+RL176yioR5o4l0NHEgL8+vjjSeau/o9cHRZK16VjrGmF2MmpuFeD4NPN9IAsD8M+xeq2X06EK5ns9ebuGCADAiEGIEbBfnjZcJpUhnlllTptbuzBoeaK/k1545XMA30f6SuR+6hGxDBX6rX+vYJOvEBhSfK9km1mJ2y89it38QY2eRcDD8Li4nuLPaKrqzWGcN+Lp8KrII604D9ewUj/a9LfefrZBB5H+gL0XI2h7rVfiYNBJghXakfunS595nBNTjbxz5spuDxE7k0EqhW6t2N70FzyNVUjmxo0nFCSRViONXuiyhddZfRcIeTXJf1hXp0/cujqvOkbdrl2yPXl2pZ0/XZaCHfx76unLaLHUcFKCVpib5FXi5i7C6Gd+8QuBliUiUAdWUJGpcqQLkz7/zALdZLqISZ5WLyKENIt/Rdo/GzQ35CZVCe9TtIIIEHq0wmMArCB73KFzMrrJStefPA4tNtbWM4iwPmahoSWFYl96pIclGNdRdFNTF1jM4VgfboB27YG/6YFJMcWYJvXR5gkbeYUgRRe/q/B7iFvGKdNIrCe34iCGEZ8/hNs+ljBFmcxEbOiFjoAg3sOe3WKnpLaI5jaFyel4Jar7XkKAxg="
}
],
"postalAddress": {
"country": "o9MZlFzz76bKfw3giyekwbhpZo3Nn1+o/NTzFQnSWaozIKa9xoAiOE8IvmU9tkT3yZLYOeaX6F6Am2hyzpers9lMHr2Ha1pOFnreQUKE9x2fEFZyAXv625Hz8Ja+ZeywlkbAok1atpc7+JC8GD7quErQwC/qgZ8yzW926JyQ38sZPHY+W0IM2sc7S0KoL77Yu5+gixQPbiUdMfYjimuRRwW+4NzsSOWUcZdQ+NB/khz/7CDc9q6tqYFuHg17sFo6QO2rQSpcgfzDrqmdCX0ZnSRBf5FZG2I0tHA2t24UuRJJGNIU66jr9b4h2pJFWpE+UwSmx8skyI+0DCk4P8gxhS6ZhQ93TGpSgpI5rWW7pJLLzlmEeVF5bm7zYQg2eu0HTUi3DEyUHfW0g/LpGEfLCudwSXRjGUUXI7tSV6BxC4EY7T5pt6RkNrnTdjSo8B4azdv06BqVjYzeJFwXL7Zo4khoaQETQf3PiTlwMQw/WQox/65IfpKfM1KhHtPFCiG1v358q2FO/S0yV6hcKNVRNfrZXG5v32DDZ8S/K8Cs0+XBEBl8OxHo581uahVKONzb2VwBGTxcXouWHVLEq928wDKnhAPvUmFMkHtkpmdSxOWr0qoMUD9WQFvkYqm9RXeczoN/RTsAqMSr1InoqfmqU9TZBCdjiMDnhe4ggAvFKkU="
}
},
"beneficiaryVASP": {
"vaspCode": "VTiePIZHqIn6q17/SWZ8fdpWga72UvaVjvwBs2PQ/R5DyN6GwDOC6msAFr3+1h/14PwFfawmWXpWu6xmKm7iyUHpMmmnnPlUKSjlNeb+k2QVTHPXYT6eboT3V8gav47mIBfv+XMm2AtXfLRGpWF5or6Q929QqxXgOOl89xwdYxRFnboSB/T9coZ2lonf15F/n+8XEMmE/g77iGwlY5pIi7VmAhi0MIJthRgxIXbuB5yzL1MtaPQr5a4tTY9J0WR6MlMjkeGODV0VyVX90aajDgTv4ocB0TLwGkC4GRTLBsdyGD3jkpp0Lion5ip+BT0MhYg2xvshef/GJ4cob2bZy+10GAdWUbid2n66HQUJjIyPuPtAZLzf/hZiL5dsgykRz/FpT291eoTeQ0V6RIYLBGSqSPkc+n56Pqum0c47Oan5078R9/k5YLpTX9DD464m5pHSPPh/sg5TeBydd31bHJy0EfwGMJPCK4yjaTlK2At6vLzhJ+BZ6au8oWoDvbCbS2bh1jJh5x/V/4HAkv/h7woGb3OY+z/GazfFEhCBAC4WdvGExHqbQhbhcOlbZr3Wt6b3Vx1U06u+acwLUwt3P9yuufAvQkjxYp60nSKKJxjj0Vnk/Qjf1vCXab8y7siEXthVO1MqTsozGtgCqzHw8aNtg7rEAykSd8AHyyjRqz8="
},
"transactionData": {
"withdraw": {
"isAddressVerified": "g6y8yN5t+5GrJfFkhqrOz5dfJjTRiIO2qYH+OXsRNaTrtoJjPwda7OOnAmuSp2yBdRFTPKxgcWzBo5fofQvOyl64RdrWmtKFkWBDAtJUzoIE5s6yk5qp+wi5+gNdo4bHmrKaJXaOsaKrO+o+kfg0ySt8K1qrsZK7AFa+yqwabUmiDwRdElromyDpACv2n2ol/1W2Oh87nAHIW8fUWsEiuI8nM83X5Do6ZlsUGjTXRhIVVuu4Yd9Jkeld1OSe2iSETFb2XEy0ml5viU5H31AJ1RQaNCvBVpzu/1fe6YgB05MQjTiL01/kn2cT3PlZ5WaKZxXQuuoNAR0y5eeJPiwfdBCCrL7Z8KJpsCRspRBXxXoUFkN56XUfBHaRwoeA4flSLfpmfKYSNcATUr13sd/fH7n6wk6mU8Zl0CJJkoWQaUCk0cM54wxWGeRtgSqPAteBsAw2olBpRrK5fIvi5YWd7ez88CtlIZwfsAI7WaMtZMTTlC8E9BdRhJVjX4neadpVfNYoiVPLiEzfo9gK5jqyeuFgYG1fAhWYvKVk+rw2Csn5iqO/AXhkEQht1riw4BnrfymFGJY8+9hrz+KTUZndG1Xw5GbFlEuitqg9yRGCUdhJVALoSeJ71YCMFIWPoq/3IRogFTqEBtzkP4N9ohUBlZVxPXZhZFc+Axe6SsaH+Wo="
}
},
"originatingVASP": {
"vaspCountry": "ppyFQ37QrH2GUityQet2+PMZdkqbgxv3tM7hiokv0TLUjZikj6TT/8jaDXumx2itIDKYr+N7zhvPtM9cm9mMWTjo2D7m3LOPNXu0uRPOCNWOQAACOlx21rC5Sc+yUazLq7e8kyi2wlF3ngH9DIjlVeQ6aGZk5q6HEWm4pvuqOaLA6h4qLsLB5VLg4ygEOw0Lqmc04Y5pKRkrB8f4MrAQtzUjwaQabUXheeAncakIKlRGYfOWYnyqKjJ+X7WD2dK95nNHahORltLeZkPVpHz7ERNqlDtRWlplbBT08PZ0pv3IVWxkFDPc1UB5NVGl0PhkdLSmCLvQe8DwmeBMZzC8o0Ks+vLlmJZbcbjYFmosaH5ZlbJh01Azs1xLaYqhNF/NwFSbYqL5vm7GsKS6wXgKCDJkikyIXG1UavKhL2HdrOIXOv07E/ox0pH7Sn8rs3p6aVM5s0fQKV5nRaM9s5ixbC3VAX5uVKG0mBSu9G//Q/RrjUXCdcaKD4lKw9hzmX1linKJCnCjEjwaDpRtPXledumNFt7CWn+dcvjG7xhOro/EeTpTcT1IqcPw+D0NnZLddNyx/xrJC5YMU3yZ7tKHLsvVZyotC6UTTjBQJUCLt0rpEvd7stZtpp/Nn5i1KeSwYbXIaEMthNZQaO63gMi8od/R0LCcYeEHInZ5qYhD1n0="
}
}
}
}
}
```
## Real-world PII data example 2: Bitstamp - Compact deposit scenario
This example demonstrates a common real-world scenario where minimal required information is provided for a withdrawal.
* **Transaction Type:** Deposit
* **Relationship:** ThirdParty
* **Entity:** Individual
**Scenario:** A user is making a withdrawal from their exchange account to another beneficiary, where the user is an individual located in France.
### Example: Before encryption (Compact PII data)
```json theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"dateOfBirth": "1.1.2000.",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "23",
"city": "Boston",
"postalCode": "02108",
"country": "US"
}
},
"originatorVASP": {
"vaspCode": "9bfe73a6-d38e-4d14-8089-8d5a06ac7ec0"
}
}
}
}
```
### Example: After encryption (Compact encrypted data)
```json theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "UIQ+McWqzwP0DFpWd2Sm3vfduvK6N/S6lWlihgoGTE0AkBGbmqkMzgsES6rqOl5fcliHVYOh/9CdTn3tNCQXKr8yCGnBiiY9rF9ANSECbmJkm5b0h1i1Amdqna3il995Q0Lit2Zq2an5SP0vglj/3fd5F9BRehQOoBhW9+p5gYWxB3ICukdVHO0L+YLtzrR3nY0L8LESmipZ95wmJii9puiULgeEV8Xe58MyK/DHHuerzjlpvA2T18qp/p/y0aHnSFuWlGQum0BhWZ3xIOb8g/pwHszYaBzSo2tfOYg8Gc10/7emg98mlLybVdKtioKu2Jsdjj0v6BHzlp8O05UmGXecpWc0LWRCUENOV4ui+YF9dBMY/MArJNVd5E5eIuT7VmayQ7eEpsyX/ymJCPLwDUFnL9Ibl0SW4/Y17Nmz+jjTrWqXroyUgqTuYFZZNf6IRHx89/Jr7d5LlfFRHzwgDiolPRM6gfC8/5hgc1JZzk9kh1ym75SRgIVnGKADwCz8rtwfxMRIK+X91l7bn5nNb19oEoiX8hfQi+o2VSX1gUhIZQjyPz4FFdfDsyF90WQdZrCxn8irf9fNrstxQZcJicYTXnxvSFMHnqWF8P459qatcTAWpujsQnHAaXPa5Oc/fMX3Sst/t4f/onKAa/s/t0sfOwlaaGFHwMZpBgUMeDI=",
"entityType": "c1WbvG7ievrsGv06wb7dghictBBkSJv5E76e+mXeUeO6NXOZuTzL1PiJoqUAM0h9o2fup01V+uIQWqavYmPbiooFofAGaLNhKC1kK4I39xuG7w9hEYQwh5+5J0J6yLOkVe5+pJD1d56fuV6RW7kikIpcTmINSwBMMNVfdhcFei4paBxNLuICMafMM1YzHHxa844qDpP0L0YYSz3rfJQ8Fj6UFGsg+EXqMwxSSWD9tOO8w5yfzc264BndN8byU0c7cXJtgRTkTXppCcMJtXzvRRYCQ/1mYNqcaOOgXlv4XkUfe2+/+PhSzMw7mI2rhkMwxLOpchiNDmhtglvK7kVW+3jbebzvgfhPyVWcjVweWjtgWAznfhX62U8mWWfLWMhJX++8IInh5bZfdnBAzp6hRDK7u1cxRUeBwMvdvy1rPXmUnNpsgLEXwb1WNGH3MhCbDKSo4e0J0E9/SooV4ZZJDaMcpF48rEfBy5I1GEBGzZcJBuOO1FkwqUH8Y160+1FPMe/vdy9Lee7C0r7u2ztQmU4z5m07k30mizQJly3u8bEAVpktoGuc9ujpYG35K15gybOCb7ll6+5Lzl5n4YKqM1Gfk8GSRdNlxD1MaVgKtwajIvpWTSZn416znBQWcEW1Tnezf15c5G9OM/B7LKiDhJ9OMI1fYZvGFf3Nk6A27oY=",
"names": [
{
"primaryName": "JnR/jKh5u+x1BTUT5j/H6S83firFCO7gYEfVe+BBA0K7Ng3KoPA54VUt/6oXAoXQP0JZIeli3sffmnPB74XC99OTjbSyEFm2V2hGff3rAJAJ9b15PhFSDS0AbQKAV+BZeucy/nl5gOyh7mo/eEqSzEjfclj1zAYQsfDbuiMATl85vgsFqb4Nt+EwmmyiWPcUUXmsFg/eHJsNi/F0U3jsyGhD3djcloJF88GKV8dfF2XteQYMkegbLlBLPwXx5Ey+9v1fsx9FcB6oN8eu4yMISuxF86KPXMHgX59ZD2Rgd218d2gx3Fdnm0AeHq0+Sc5tJ+/URRYvMhF59+ubnIb3cIqOyslkLAngYtwK3M6aUAxpTs6tIbrBDd1QMFZDLugHgwXaTV1tRxY7bCM75VUmi0TIJnF3T5kgPtEAaiia1VbH+amxYHk7q7V1jVeevJv+TpwSZ4eiBBpx6pZEVP4iHgTnqFHgzjtX9MdQaG76LEED6HQjeIs3ikFNrpxn1YZMkaTFnuP5NiUELN823gSYVtIyUC/Z4gjxRD3X+tOrGcUq+ntYP9zj7ievPsc4JGHHF3H/tfFqbC2xHLD4cTkeLanOgpGkJkAX39EUqmxwmmyp2JRPXcly0PE++RRY6TjvX6JCbeFRrr4ycFq6sIT0p3LdfNqAjm0gyqqBwnYgEXY=",
"nameType": "AUZXCG+yLWovnc574QwAsz3g0Yb0TnH5C41oODS2J0buSDBrdjXWoyCH3L5a+43lWBGKjqDEO5IlbNpffwRXN2yoLG6KS4z2amFDzt8wKmq5WBqZRC6RcM5AVWsqDRv+HT/44CmIXJlHDKZC3h1AGPQ0Efh6YbhTpdtIxXddzFi+PlhApnkXtyUa7KhWQQ+kQ4H+WifDFu2oSJ/2CXkpT76Sbj6O3glrBa7JRg0lIRNgV8+Xcph/8Ws3mTthkYYgac15YzO023qf3aU1N8BOyEwQuyyZUc64BTzK242uv3c170hSU2DSLAgDEJ8F4UW1w9zTp+DW/uSe7oe8l/rUSN/58QFYK+MAPAdGVA44j++sF8IuzImbXXI6ku/t8XXUFr/ToD7Vf5wgKRbujwEbiXNnGDyVDwiQWQaP20lKlhJjeYijEnWbUHslIiY4KSUQv5XYYnc7tWSt1Iy7D8XPtvO1Vp0Hg2hOGSqlwGHIN5DQY9h1QAAguSBsWf34f7J+PnSUI8mK3itmgx46/OGrYwuKwAeM15eL/afLItPJyqtvu/zAtOgo90MwK+/z2b8VJFzxyt0e1tr8c1XqfX+9y4Ohp4AMrvgaWKaNfdqVbWUjMVndWbh9SYABGyh2jC+azjlkxG3G/M8ncj9EVYs+NFCjFj878QZCovF0S409zek=",
"secondaryName": "SJUSYKA5w5XAeS0Oz/wmhMsGqvZ2J94iJ7jXUC2BIbf+1rtzlD5B4x77fxWXGh96dDgQ6Cr+COVz7ebvSStefJDRbu65jFDcQRC0y6cnfaeU9DrERrmcbobA1LWm0/xkGhYQIEZnGaxoxYZOn8r65PD4l7Mua7g4low3lhjBGkzsNbtrp5zlGoh8QhYXpzpj0Z7oMGEcCmesx0Tq/lb4Mp7Uhc+4/njT0rFk5Ogw9G0y8VD3UEFSxhThwT8FnKwdksyNHDuTm+sJ17ozd2dN47mka8tSMEp7NWayT5rTj5CMM+P8MOV3D1EEODOaBMo6XULCsApgzDOdtXDnjCMwWJqNzYNts16fqWktzpBy6Z8iB+IDPqMbpoE1GPLSvd6RIgcjocp8uJ0wWOXxVNXV1pH0I5jOPEcM/4Q3LA/kH/3Stjdvbyx7alYkRP4shuUP9ZWUdAPwAklRrtgdSaItOhm9wuuRzTzIu8OlFBsfd53kpiYKZN3FrzeQ/XeQNwvqj5yTH7BSadyG89vXyt/JObPjK87VtY2Tk8EWOnRtCIoZ8YQXnONMaYheJgje26i/ZYI1jUTneL7OgBwkePzRBgRgsISQ7NVgIqbZInEmLuaH7dpUT5pyAB4lFQD70vR79R5+S3iEx4UbcN9CtPYlmLVXw8SsuMQ4z1SI4zIm258="
}
],
"dateOfBirth": "rvku0/k2oXk51TcqHmWJRXGNtdEtU0ruluSIOj0XytFfuQPRUomhekaGJtm2GSR9WgEa+KS4hrwtZ+87TgL45tIvEXkANurXFtIaI2thsiSfWDGqCHaFi5n/cLCUesnThU8GGvgrzlucZIWH6eQMkbVSn3HVZmuUbIDMbfieL4NI1l+T63Q6vbxRtMzfzJMDI3hiRn+7LS5BG0uLNsJ7r2cc2NR5hFht6nfKKiLn2SIL+ndoWYzVKy7vDEeNT6frbMeICCGdJVSxX+vLdhSAx29qYlQ+75iPJ4bMi5PPuJd7yp8l/14AUbYkBqjC+9tTu2zEKH0UPm1IqxHdpMpN+OJ05J+9tMOL3S/jRahqk45P/0rDuWBkyvRRsANw6Ajn/rIplw05QJA1H4k/wbT0gYU6iVF7chXA7xFS2897TtSISsKzHy3ux9sFRbeyWs2jTicuNNllECYtgs98LrAbKEewFyJ4r3vNJdNOirte1xAIUD8/BAYGKUb+74f/Yb32DlgOe8+emGtrTQZbyzqjNrnXVulONXaS0DQJ6wRMMtyOwothBZg49Jw9hjqQPMpNRU4Icpd05mmMkKkJJ8uEuDUWA5CZYHrsmYTTysxdrYUDa+BNwgL7V3zp9geZHbdoEyaPGTSFNQKiC/WL5NC4O9r+sM55QHRBRoc63+zt58U=",
"postalAddress": {
"streetName": "HILYP3i4FW252ELMopPjbC9t2U91+cXyfCCsaJwHkx01L/qlL8UX+h8YAuY0zsW8WEv7H9h0ZRDKqDZRdQ5zeL9hLgQUnWNoSi3ACIQR1qsa7oMoVNfhWn0tgTSKYuvkWYIuSGV5J4vwBJysNXPbtzft4bBxR2VW+nP0kxiDqslkF1mxa5phy1uoJZHauTAZIxpoatFmBTAEldSpa5IxoVrWQj4fYjQiYPAjAF46ssLVQZwK2EGnexFlc6oH2XAZtTw38XthOt7aWpPrJpLFl7iQgpVPhALfINQwgff6Y3o3XQhY2Jr/IW6P11mOUd/FrpjIo8jwrnk/5i2S52z2fotgXS7mjinm6HvqCDaUCujX+3Bo967wmm1ENAaH5Bg3OssCA+k/VXI7o7fAQ7fLUfnZcLxxKR/8108DN+Q1UrULeyk5f2IA+xTztxQHbnUCRMYfJO3nP91odKF3xkBnms/OVlNBcTRB4dBr8I0CdmmKv/3/4WU1BoHnlwMN29bPagXAVp2mHcj+J2HSoN3viC/Om0QITmD2hToX1smpBg1UQYTX3URu6uJEWiUqQZft4q9DSMgyXT6/rBskpTPGuWR1J+ULWXF2Id1ULzrRgPuszxx+a4SK8iXtWFeMGh+Y3o3SDoqXyVcigqDYJpIzuomJzVgzowrUBbwdmL3sFAM=",
"buildingNumber": "flSWDJwwX8yDTOYbG0+D7PNQQm84plW7n12yP1gTVTL0dNt5DlWqgGCs8fXfVKH1uqCc73s7jqmX+uMej0Grb7Cm33fp330+113OnjZUnCxLRI2jXls6PFBKO/poRMyUQql/waDIfnM4bJ230cu26Ki5B0D0mDrMEkb9IIkILp+7E4lkttWmZDAez/CG4eO3PJ8NiYr15YAm4O5VCJYbgHLSHC/11+pOiinMHzySrTrDM6D/gmZ1TnqD51Y9CbgS6VWIlwOOjwSGpUEc4rUXDTedoYxr440KYLdbDpl4mBB0Fckz+UuyRxoTzyfOBYcWMdBYIm8EeMq3g2aQFfP8u326v1vmVIrKG4m+dITy/H8XZ7GJVpVm95NAtblRxQPNXSIieSQZyuKP4WHU3XlaSvP9GK519mNHPAsApOZpLLH+RPnqnCXMGcr/ZQ5tvRQWvOkO5N4HQjeVUHvrCZ5lJo8aYXFN0qKMi2T/icCm58YPHGEKj7gQM18ZtYh5SJCH+VAVbBt2c+49sCKX+A8BLeVEvfYkgIF8qCNQlal/6+LSMmMzv0MO/751CpnqpGLvEsqfx9/lgaSvxZ3RSJ2Ac1faBMAhiKP8DMoLeTNm4ooKjFBRzoP69JUPeKPZ+N7TvhoyJgL7Z/6HQ+Hs2dwsTW6W/tBwpRyxvBOjOJgwey4=",
"city": "W8NUxiw2sMgIR5tCM75oTyaI//HTejVm/ZtYf8eec15C9J4TrUSqKKZ9By9A44nMLTQEkwF6uGNS1msS24fq48I6X2dV219icb1WR/r/+wW8HAFi0qjofqYV4hslIhF3lfVLP4R79i9uDYwMhLYcRxMFCXDMTe6zEg0b+qav/7y/6XS6DzUeHUpZhnDjQ65kNpQoAyNiw+1vXaqZCJf+fIlbSDxLGaLAZe5ue26wishv3rmqQdrALmdz5VlMG5tDrz3FakK/vup4SMMsKJHYmFCQnq+3lssB8gHsf/6swa/FMTKVEY6dOTeelcQzawfUu7O/Q1Rkb7O0ht8LquyxNgXIt2MSn3hvEucI5w/e1ZSLkf/mI+RmTsqAccR18mQRL4KAlgYtkWWBAr240k1svWfsG1F2BxcvLaqZiGOY99mjLjY3zkTWDyKHJOb5+DvdedyVaJkIoFAnuCL/iAP3U7vrmYnuFCmnlu2TsqWp2UDD59VhDo8xMl8sAuiqrRZnUDMrqMKOOAvHOvJUKWDG7iV7u8RnYO3vqMLCsIx7bVzpYs8pydCUaNesVrZYOkUGiUoCGcSQyy5O5XcfBzqo1UEY9lfkEvYDKIOOjpt4xZCc62faJv3NH0g+4w+4Fjzyozks+PgjyA0roqp+iaVSRSGeg6x/YDuvkY9W/yaOHGg=",
"postalCode": "jycssk3S7asgoMs2mqT9HDTGQjcbEbnKWF5OFMbekXIjG98dexKySSzODLTYBfAbGcWTpA3oH+PxUzHeyZY8NJ6RNhvHjhmacsoDp+Yt9aHl9htJfwDHvkpB42sJb90suPZ3gJIOOLs2Ac1oesjKv7pdotqMZ+3YAT0xunzSAFNGrU00WW9jSZ7qavzq84QzrkhjrnlxvrKaon4C/D136kxNopcorrF3SYxRG+bD3pFbEahfnDl5pW8+uZelUIdqn95iDHWgy3Wtkh6T1jIi21rBItZ9sXmfas7x4Lp81Pw/0sid817y11pydGlK3k9rbbxPYem+zclV9QMLW4qQMZBgKaHGAvpjBdtx+OmtlibJMxKZStWCo0oJof+BZOo5LS+FKRDFCFM2sP49xnsFMjRjuPjYfAupHEoQ4rx5x9RJLED8glix+ozeyMCWN9ybW4j03qzu0hY7kk+rOCpH8C2bQaxZkDXxO+iiFhdN92/CSoQsx0dtffWe322slEuZulcXUTZ/Htk7WsQZgnqNbc77Pffrrj8ralVPY3UEnqwjtfVHkx/R1ChJNvUOHCb+VZR37iYM924iXnaZRhF0htRyNDm/VKNT8wnJgEOU0sK6QhYJTz1IOsms0M/r8/tE4EtTuIlXFHeM/ekm0a15sGDzwPmfw6y6GWhWqFVWz2A=",
"country": "cC8LkS0FvsXXe1p04SeEqim35LDfW46Unhb6xXQbg8OBWsMSjDxA2xwOiYuRu33HfTObf3o5CHiHL96iJXp8Ou1IWs07s8kr80U1DpThBbe90a0vk0CfQLk1TYN5k/SGz8x6cyUyqPSqOGWOVFBcvqgCWJ0C8upZT1U1jYLW+um7dqiC84a32othiZkHiwyMnY6AlwG/kcIsrXxNpmoH7MH9mGxXqHg9y1reL9f8HWw9N48OBKeHHU83DiFqnR5ZvSMWRlyQko+wVh/a4gLkfWNtKcWysTnhw6dU85rXoz+CUJdjdDCYUmn40EYF/hQixj9hTOvY/aNv2Uh2IjQWDhify3iel5UGHMv0bi7amWrPkh+37rtmyteZM9oYRRusgKgTW9M2/Gm4kq/f8IarCGOcgLeXbxT1qnjAbCZXNiflC1nKVmLFqnH10SL+l/KDdIJLQZK4JX8oM22W6hP49ALqkPp5ONyNHGoJtUVgk9lbWGSMmp+U2Niye7TlC7G1XpCsJlt6zfYUsUG3tOrkJM6LsOlXHf0rrH6wLF4j7APCahQ3Ax9WvC/lFarY11tEm1mf+VwBT6LwljA1gOWmMHAI1jHDrcNaNKl7mSF4NzLaZdw7ktHqYL2wm78XKKPaI8Exi0kGrwpgdohw8FnByK/eioAr9RRfvAbFxXR+lhI="
}
},
"originatorVASP": {
"vaspCode": "Qx/d5nSqgW3i/MllXNJ/k6uaQvNZJ3r/egre0TjzsEtR8lILIe9fh3HTd5cAT68Gl5T2K+tjeMAR9hUfRe4sMtybpsUV5Z/yEclIqMg9L90Jqtmx8irLHvzaOS+3o1SoWEiFbn6p5lXPkElCHaj3ruVCXBqw0+rXUXCbVFgG6NFKJ4ZvkaJsxO2+n9h9JDEpGRqTR3KpRudfwxiC7afC03xUrkh0OYeegZ5YlrEMDrUGjKG3lFjjbGZL0JAywh/RnA6fG4dXW9VuD+0/x0XtZpG/6YSUVmQJnwAEhfGZnk2CboL34XQUpsKA+/naLP44UNjkbhsC6y4VPg5WdAv5/S4sTdKj5Wx/RUhDKissldSEdxHKSfogbESvllZxctqA68sliuiB6y8Pj10WDNruoTU5N+kwOa/9asLhDOrYykclvtNNwGUgG4yg2jSz1N/pr2J8BOqzRV6jQRjKeHgrtSnglgZS59/isjz/TjNR4AHHJbaH6wsJl0VAQMCuphv/zaVZwBU81M9uUxHyg1wV2HT6nKTf8H8U6mWuH/SwuLMYa8seS9f4yH4GbAoGLkLObVwGtbxvTH3mcgPPzQqzOujmhEO1OeftUXgnBHjns4mUnvV+TireHTMtZMv0MR8tG3Bff8pg/zymrlaLKzjfONALN2kQ+c4QO7lIO6S7WOo="
},
"beneficiaryVASP": {
"vaspCountry": "fVJdps6ZNAOhABTF6lAF7hui3dGL4ijQfNinhE70UAEBVoy5r5CQ98f0iu5wjkDk8lxmskDBf2ltHVzFk90RMG5VHQASWMLXwv6NU+xp0k2tp1AFRUX3CdmsWgtoTRAMPHCmJLvwIJGkNBZDGWx84kbzIwosZ0mKfjvrm7UnHGBTSa+aisJ+DglQsBp6MxCxgQLbDx+6+MwTarrt7FQ5l5CwUEs9+3yabQWrHLjmrwHtYEGAlIjtkm0FDKskqkpysEwC7BPt5drL8UTq2GdH9UMU93a6LixJZlZpARZPWEEwPu+v0BjcIfFCBDcG+Vo+3u3lQjaJ8wm2hdIdF8Rbjg7vb1b+IFHN6Gnk4Y7zxZ/lJkKO17RxntNGXCesymKodwXKNXZt0mJMegmyXQpG1srfiRCZ7pFf3HcuKsbiXEkvd+V+//60rkGJGxFoQ4FZcbJqD4dKA3E4cVmdMDPq6EzzO/d0s4X1DyXQ8+6HuQ9Ai7YgvaPQIrYIRKWntG8tEDKCrEyQN+7WQzejmYU3sQe4+M2okH7gBoe8o3GpNmqPE/JxUO2t5tdbLieiySa+vX3T6N2DBc8003miuUMXMDfX8Jf0gi7Ynp8PXamtIj2T3ovbwTDGokdZ3PC0tsrKBHbwAiLxfk7K5S9BXObMGnHgIvpv2H1lydJjrI4XYf4="
}
}
}
}
```
## Real-world PII data example 3: Bitfinex - Compact withdrawal scenario
This example demonstrates a common real-world scenario where minimal required information is provided for a withdrawal.
* **Transaction Type**: Withdrawal
* **Relationship**: ThirdParty
* **Entity**: Individual
**Scenario**: A user is making a withdrawal from their exchange account to another beneficiary, where the user is an individual located in France.
### Example: Before encryption (Compact PII data)
```json theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
]
},
"beneficiaryVASP": {
"vaspCode": "did:ethr:0xf2bd35dc59cbbe3efb15a5bd411ac84e7c86d25a"
}
}
}
}
```
### Example: After encryption (Compact encrypted data)
```json theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "EI4heAsEl/uBuHDmuthkAZdcERQiczkG+Lpf7K9vycAGvwMFfiXgYIxbui/7lPcUEG+LQQQKmPBlVa4CRSrIPjI+bpP1C6QoNXR2sctaP3vnIQInoUD5REvoUrcY95qd47uIvBGAIV5TIdHug2RN3QE4S7bY1jaP+ZuDi2w58rdUlMC7C/suHNLiGBX/rN1SwC/g6WiqCyoJ6HmqnTObD+s4WXmWxSqNnl2TIzE7DoaFVtSiv895QI5os3hHrxX832mRFZDlO+QDJJKA7c44dSAHo4DjOdVUKWxW0h+RMrgi3FiDuLdwVPbYPD+sRCCNmsM67TVuoOWVbnbZfolY/EsXCTcWeqJ+Ickh4Z1pNfHqm2MUC7KivhLws6D3YULoPQCkpJvF4NWXN0uFvzQ191DoG3pl/T6u2eh/rU0N3u7VwYS92uVaNHKL0OpsYDMP3zH6Gb2sNx4bZCtyJEHIQqhdK8+ISASVmrO8Jrr/RVDe7c7mFWUXFpQZBUpE87qKxk2Zk344Optfj9aoUJ6gFBQ9SqdWXo9y2iWfgpIQoFsI9amTneCG/3PfxG2bCA1qg0xwukM8rugi1OtsBUdGX8f5Eeqtbw/h79z0/3kbhnHaQOE6SzAga9Q4xhDm5USJGp6qeeFWe6WoxVKI0O1SnhEhFuxt/nNCa2pB379DLSY=",
"entityType": "jX80pPFp9Yd71BNS3xPXvyghZT0u1z9x559uftSr0NItpPH26ZP8JNcSLsqOr7VRYQVCdaMrHFso0zDqPimaLxIj3SooElegtRrK/XltEZ7zNVR2EScuTWKDWabjzT2CzWno2/Ba+q8O5A4iZ/cNoZ688CcSzMHOSxvt9KsQar6A/wUjAG48CEj27cVL33IADF3SVH2Da+/fs1uuSdp/omUJ7Fa8dG8oX/8KdEJrYDnWHlzYLvSjEsv3TGZlbwV1fGwJ/2kvr6gcN2+8uxyh/r5+TsoX9SfuIfoa4GxHcCTcrYnXOPAqQXsCwcpq0+oLZ6nX/vO9OoW9yo74zaNLLW3ItaFYHdj9Lhrnnk7mgD1gsWxRM6DLEimKng7jzfimtfngrexqmJA+mtwD+/1NKe0PfghOxZInLbZIAktz9HFriWkol7U3fCgaF1/UGEmADMlZQayFsYSDmuA/19MsOIq3mtTX4k1DVAgHevgBubzYoEhSbhbBjfKV41GX16rkG3hVtzKJmD9SeGFRwr3c559J1/8AriRLoyMTuyYJ9agABc6fc5fpTh/OFiWXTyB2GpLeoBluf/pVEcNH6u8NE7A11B80u0wEwgboNi7pywGOX8fx1rxeEG/1LhGPy/xUvtJExmMdljoH+fiSInRjgZkgEgB095YyOZcNls+pm5U=",
"postalAddress": {
"streetName": "UoMYgz7bwLjd6zmBUujBLZKpvLZBczhnz/zjgZF2LgaJw/1SnTrDMACNVeGhAnVDtBNnYokvM5HwJnd6kQPp3G9UG+56dEc9uRR3WtNcIXTuxErpX62dG80ltL0H+0jUxsrJbvDeL1pOPORox5t5xEiCLHQfsFtiVSsaVkZOoJkulV4QMh4dfmm1rvAuCCVYCODrPy45+mOffbLnBkJxhlTco1XPjzrXGmGhMWazsprkGgzU9+3FkZQwmI5JPWn5Lhg+uaQDX503iKKTq9lef8KWnOzreQdSG+S9mJH+FInS3/8e5ociQ7g0YX/WLh/tTffjmSft622/lElTBS7fEVmGuJ+gN99o9K/XP2ojc7zuogHCDBTA+fDRnSzhxkiRvnyQAUp4Zm4jgbt/pZlBYGmmqWL6vbFaDJupgLUaZTEhlgVYV6m556V08yHOotukrJWZt65JOy248z8ukZoH97df0C73GuZ0rHyTimvNZSWR8nFwk4woRFyHTahJ6LwYz169HDtRbfYGzabTuLDWfbeYF6vJjo6pLdnz87Hf1nmVkOzA+oway6pZ7uHnFsgAOXJ5ReCwuufLTbQaeeWKxXIFEUxdY8fQ8u98lUIQaRRJoM9HdMuve/+hWIGE1A8mxITkdaBtbXOk7HzOAnTs+BoD+tR2VWAii3F2P+nehPE=",
"buildingNumber": "x7pcs3x6eW02Q3LaijSPg+meS/tj3/CK1JpU0XSacaqmH3rrpXrfuW7b2l/bJJ7HeBzX3JJFM7SH9vlgqtsfcO2dHlzHuht/U01fQXqBHHndMMB74EAoIDgV47jNn67WFCd8ix1XvGBtEfhGJUmIy7Pd6TcFfN2V4A/bXKDFgAx1IYUkn+pERPBuVXiXjsjW2hnCpjjSROmie9PVG810oaWw+Jw+ZinJO3MrF1qIqLhdZwRihcNhoWOGK0S7/t4pwivMlUvcLbKSFIQpYaWAJq16OOtX1V4X93PG/IJax08JtC/K9LRYattFxNThAQC4Sl3ZGHRsKwUAF8vvH4Et+HmfvK2j03TOaW/ep8xsVEgx19fHdsUda5AQGHY48+wKYBCSvRhQTIDwJxj3XgxdVJolcWhTR9KAxJJRYLYVQqmclSUQotF0sr5wrS2gKFceA/zI+JJwSUN18Y5OhPOA1e+6/XF/Mvigde53D3dcuZKNR+Jy6R3OWRGDfAEWSVQmD1neSFpb707b/RID1Ip1My+MRJcXEuWFnGTqfHKczcZSHD4rjkzER0F4+935mcNohlz+3pv/irnrPq4mB5nu2vB1jI128NQKU61Om+rDCVruzXSHa6AcmSyZWMqgpervPCEgX13vBk8Creu+O/pEJHO+YMnMvyvJJScnnb2QjpQ=",
"city": "dMDm/oJbonP6AWm/pfwlI7QbQspN4dzJZdpaOKDDrfIndxpiA7TfvFaheVXhJdaFumr2NE/qPAOZtUd0mZ/2vs3FUjR4JlVJWtAwnue0YcOYD+hAaLQVZ0MPNXUnefHcKkS/oZxfsBLIHXaY6KMuQ3WE1xMsc5q3IMwkCc9Pt+xouhiFS6FUIAx3O0m0lDyFQqJAk81FO5O4Dxyqcox5KvKC5PRl61ylHVNj7Nu3hgEYPlAzoRWTDv8sihQJYbrQ5mvVby4DrKZZK5Jx6t9Vni/4jJi/O8q0z/7H508/DCdkNpFM5qHVIAgzJXDN0at4Y3G6aFgd2Qor3yqNtoK3yIDVAf0oq7AuRTZmLzZO+1djD89p+thAJySs7oQoLNTetjbRqVJJRbYmJHbB04ztHKiHSUu7hr8HR1jik1Xq4Kdn5Fv/HBFdyYRVQC6INGnEvOCb2eHh9PXgPIRawlzBzfCx/v+saeqRf8LDlV9qkBjvXiQXXijj69fQ+XF4H+lqqELrzbM1RTpIYNGaws/fzXuRT0SPi9dXTzdw95b/nCLrLEVEJB+H2OHi+PCSX4NU4LkJkbP0kcuSPRTwT+AH/8FMe0NV2VHTZfdqZRIl2lwCGkz+ujOoqFFMFNXwK2do7o+B45W5tE9WQXRbOQBr1y24OgUTauRhP81vr61zPcw=",
"postalCode": "qB0pD3xodmBVDMB++PXB7CcvDJbu3nYO+mOj2NRvgwAgMeTEJmKjC9DYEaWMHlYaqDr5rhwK7j+z5dIcVSgCCYKQBIvVMdwz3dlLkX//L78p8aoWAx3KIjTdsau9ePUpkgHTJf6G2M+h3bZb3ihPgd0F/Bk5zgpF7ec7o4q5lGR0lVyKvXzEEw5nGocs+xLvu93i0awH0xQcdglfvoEAQf9yL8UxKfPwlfhPj1EQd7djScewITE2JsycJBdUl8HkDViI3gZtJAlL5jRwRGghdEqYQQ5Kv0w8OgqT6y9GArc/0Idvx8exSa7C3z71+krsXHpDhcLcyzOb3mvCzT9HAbWupXJhumJJplHif3bQpCb69xFoVNABW9G2f/AR2iY3Dm/ZYxB1xyqlEQzsv7gNj7FtKkZ+d3jwLbYG5uSThDKgL51WFecCrpgkzVx2BCJ2/pgtz4wDqNEarF5zUu1DG3c1C04fjc7536J4s3gGvbAI0JgCGGw0SX6GfYVv0LlfTJMvI6q9Ppcz5xoGdfF4m9XwQD51BtVDRRRbcaDK/3eTuCqurCrrfGqW8TpJkn0iJ1JuTBBNcmjHqJAXd+WHug8uL+K26RTmq5J+Ah/hnnqZ39hfD1O241fDukqxpGq8gg/oZAC+VY/pUgjF6n7E6pjjkNjWWGccbOcrHwXNoJQ=",
"country": "tG3VTkEygrYnOB/PwL6B/NI/xYe80QresfJvlNhCTUE9P2MwUp+aGFdIfGOAFbFBYZJ3WUt2Ydh+d/+x3mTczowrtjIEZGGWamO8IFrnZR0V/w0bjJB7pFWZFwdxBd/QV7QGrHKvQInMTnjNsTP1ZM6fS+42sZiUBT/mMsiFT2CJrhqeD/Tr2sLH+nfBd6qofAV942tw8LPjVGGV/i49fpePsq+2L1Ua8XKpXXfljCTCVkwoSIGLSd2a0AfxxmCp2Gq+5WeVeTBQdQMPwuRjywwcheZeko82eBcqq3A0IoujXWFDbP5CF+7NheCkT0k6T2c2wrLzEha1WCSW3xLLl8xZr06kuVNwFKgWSpxIDv05kWX9bToCwQQaDXKvu3zL+EG/hrSK6Olfd02kgtuK+HenNOKPOsGSAxdX7IKramDcKRUljxwQ+PcdF3cDeHOM0cMXjwkUZBT3bvOKwXG8sWJM2ckQPBPgQ52kcmxO6OA5Ui7vjFw2A0sXFkKBfUaIDtHbqSbwVLurzspuhaiYdL1Mfdwrx8gRXNwzIcQGqsG9EnBa68wSfk3w8Lz+OkI46VF74LW9k+owktOth7DpRHqcOANzqck9Kfbfp9CfXwIbzuKUDMYYIGC6Uo/GJ+YTXWPpW5XH8jk33S0mLl6OjON6C/Gh+wbLYj3U/G3ay5U="
},
"names": [
{
"primaryName": "IC33gNwLRw5a5Sr6OQ9WIGeTI7p42kzJj/bunWr8x300ZoNRijOGMcTcEMmRCY+7UsXtSgk4cewjfIwrxC31tJLQ+LX+u+47Vsq5Ndsspf8pd3N43Dyo3OIOjzoePsKrOLpm62B2PR9n0iYwS6OLOr72xqrx42y00b8ZJ9dejYoOW1Ri3Aj9ZsTih8m5PBdbZG/u7ZvlsRJ/agjXsfk11mrvWYxu8YWI/86OuQgOMfBjmNATHeaAmb6Mw/mFERmgrOw7XOob9xRRdAa2K1Pi4hK3yKT59ZUpwGdgobFRkVw6z+x6Tr9EkwDtXayFZ5BO5nrRsUUEdP7+fzUD06cJzLCoYXLkpyE49X1Hq4IXU3H09u540CIovYkpipKSMP3hKOxAPVukOlVRD2otpa9lsGf+ZGfL7zRIlIkDNlpKZDQaiL4d0Zmd2E/f9TTuk/s88ZOXoR1Viwk58aY+GmMfPkZv7DommfdNpzlP0emFTIQeQtGTyuTRZpBBfN3mbMb37eVmEzcgrcXnvw24ApVeC4KCWxVhZJeERMFohMqS7yH+cJuB6eYsYlJHL6Lv771CpgaeC+pPE72OU6HZ5W3RBUz2rOaoL6PafIsNndABcvnPyS1k0NulMYTDLsiGUS6kDm5qBN/SJuatTf+uAozyc8ecFHATOar6wM6I2ZfuyQQ=",
"nameType": "cdLzkNW4sGP4T/1bo8GeWmWOsL1MpaP///kzmOpDm8DxmZ+atGSbkYIPc0LN591+5bFalKIzsYUVaORUNscw0+pr/6xXDzz6Ps/JqXoJivn+u4aj7x1+G008Ln9bqg823wqZVDlmEV9B1dGNQXwarsJazaBgojCKnGZJ9fqEOzmDYHTsYVoGLX9pr52+lQpBCWC+xvdCf0u/15PEfufP2WqFAKMd8lW7UflwVQGstBUURbsb2WQxk1OUsoMcI/v7UsAmd6SP/GoopfPuCmUfj/bT5h2UnWkffQNz1zkaXE7z+Q2AzVwUMp5SHmp/V85V2rQ1Q1Y5+JXFrgpEAkKowEcoSZaLPoshuhXAjmkcVgt3Xw9TUd4jas5+u4geXndqt6lmUOCUXR5oWTk0WNwHCb5ieA/wVGBPAjJ616q26Eytu83o3wbNaj5t7Jp4H/xRqztWlMI/0by/bf1rSnYh1l6ur/qPyurt8izh4gffeZbJe7YYAjGFVzvkT/BxUMVWWAlbwJmxgd1/IOufvOtiXy4aDuO6Vw4Ik86nByjnjeODIJueIek6ID2tAdi7mLZxTpdLA1jAdGsfqgQ0ubILsosY3XUlXLOzVJSXbajTe1WM9wK+64yYnrltWsrXtxyqITgE5Upg9BwCjyLR33tP++589X7hfgY47VG35/cJI+w=",
"secondaryName": "SlQHE2A2wko4hFVEnl+Cj37J4HAQi62NKOflhxgZxGs6cgDjI28SYeXZ2Qgyq5v2j7HJeQq5oetJHdyDdXTk0q0vh//yQ5COyf+Fo+9vhk+reGRv/wjiNaGFp9Y2+wmE/W+mOsKNKPrnwhu0wyTEFbtgH6PPax/HgEUWm5NCL7Fier3zTwPNKqF5GczFgeSkhUXRDkDQZ00PI/IFIIRnoksemkMQVt63YHXqW+FIITasGkCQy86x3GgBaN6E39dQ+OAg+8HDQzI+9mjXDbykc+5aCFYA0Xex0TeocP9o8R1DZvGhPJ1e3qTs660WL2qzpWGZ5makStxw6aAW8pLLfhapgmM1R73lPSk5ZOk1Xtqoeij8PUmuyFALhh3wOCS34W8u5DjKcUpkhCr8Fn2mS4qbcMYA9elHvpGWlq0hOPtAB9Lg01dSpRZKqt/GPNhTGMZg/qo3nnnVMk1jAt7BuGsGHw8QIJbooyT0qGCB2JUg6QJ4lnpdcthD0mIEDrParzAvuKeaM4P9PNK+uLfhJ3GX5UUkFNDJYpS8hh51ZX8rTnzWOAvCnhqqVQVJA5h2yAQZhW6Y3fsntcrW0kFyhFYCmp++0pFGagvwnjG75u2U7DgkSZXKRD70yOnJj8LiZl/tuIHVmcZCt9KxTb5R5CD/P/0b49e73uc2hQscmGg="
}
]
},
"beneficiaryVASP": {
"vaspCode": "iJ/XUSCcI393qo3ztWPi2FSmOUhj/9Jp1bjjoC/H282U/KUyywFim+xnYvXL+RkpX00LHReZBvW5ppifuNOmyMMQzFcUgUj0PiTwT5BpC3T9yI1OHc85rUb9QFZzT/ylElO7DRFiSwke9lzl7bYAHTPwjNCHHLLJaQyPIPl0vIYVFoU9KvaquB/C97c3hbTlI5UbmzQ2iV268qYl6Xeq/v+bnZkR3EInJYwuw5SOcJpZeQtfFVVEtKh2ovctfueu/5UhUWh9irky8tlImHFDwyB2qKhNzimOm+IwRYctQ94U35WoQio88B2JqyG+QAqXqmuHer755pEO3RvYv5HnEfElu/nQ8S8bCu6/M0hHEqCiYBuz4HO985IN7+7uG2Ls6VS5zzh+K4xWXULYcTvQ9VDMYKrM08DJqu55ResQKVNNjD8auCRnPHh7zWP2DJcqonEB+pTFHwZMil5WASLYk/PRLHqPIU8gSBPo5BDFAPYk1FdO/5fsjsOXb2PqKks+yYWkyvVsfmWsxlFLrAgwcTyqhrGxgoPQtlzHE+Hv8ZXaAkEK5tD1IfCEOWYfyntGAPJ1g2S4DzdTjMRgWgTEgT5nrU4DaNC/VjVWOpX1fKrf20mzzuMlI/HX8F5jnSsxUBkD4y08jAyBsg5xRsYIwJ+Dqym2zuI0x1sxt89FkS0="
}
}
}
}
```
## Real-world PII data example 4: TrustCo - Compact withdrawal scenario
This example demonstrates a common real-world scenario where minimal required information is provided for a withdrawal.
* **Transaction Type**: Withdrawal
* **Relationship**: ThirdParty
* **Entity**: Individual
**Scenario**: A user is making a withdrawal from their exchange account to another beneficiary.
### Example: Before encryption (Compact PII data)
```json theme={"system"}
{
"extraParameters": {
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"externalReferenceId": "111-222-333-444"
},
"beneficiaryVASP": {
"vaspName": "Prosperity Financial"
}
}
}
}
}
```
### Example: After encryption (Compact encrypted data)
```json theme={"system"}
{
"extraParameters": {
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "XsWeoBbRRiBy3GkuZ+iLtLBsUagst5/Ah1Vf5fROP2oDiRHsCucHPXU9an0eqcEjeCIhyawNbDDByk+SJhbIGf84d8LysqpdhyNwsvictsnzKhe76GV92tGzUP+Fd3N1bGTQ3SoNKr8NMir6OmsCYbdll/Ywr++8FD1A+WTiom0JKo2xWN5oltmknPNChWo02MVfoP5VdUzaBEhZsHG2GT5WGjul3Y3z/WJJLidV1lnDdVUO8CIVegj+fp0j5fi8QtXQ+7/jYdpkCUIi6wIco+neh7z9HGJ+PlQ/tf2BjsyYnNVqm8odrCYPwvVmAWWzXq4feCMWmYQHYBDh/jIz6oCoAg1jqwbeeDedihdo+Sv+IyVlZq/UMJ5fHyzIcIdfcBT2igGyx+DoYvSY/7PPNc5zu90PlfwJmOLa0PA7jgVn7T44YGjIF60M7xU8HTNwgS339oTIrIMu0EucQYW7s5sIcBq4+GZVCdSUBRCIdsrnN2CJwGDK08LlstCg4gDtYO8kRDiVj99j+HKHi36AV6AgYL4Xe1X97TyBSZnVJigRic2RKssHwEBYH1zYIae0ttdw0BhvAuhWV48Om8ds+R+qAWVuHL69wC4emSFCN7K4Dnvz5p8vXzZSzYbLdwIg6qCX9s7bMNux+XPHylvkCDcOG92Rvew1UXgPRB3r5ms=",
"entityType": "t7TB8+RshOk4PJlkMsClq/2EX4YsvEehiwsvhiz7uule8xgEvjmKPfng07u322F0800WurXVWcA5geI5uyV773LZz8zpWrSQOyPnYc0xl9ybg6ZC4R5yvpRBXcFHJ6Ts1ccUGXMr2KBpARxVmkQLyHGWClyYH5h5Vnb6u9ADjj3b6f8pDoybzpRKSPGplm/kUSM5Mb87cIimSTXFRhmWrdxzxx1W9tCVm0ehMPOWSvFcANbSGJIKc09+/55g/9q5s7efReU/izEMut0vlN+rf57XAsjPQ7tFAtp+LFsJC22aFtuhMnvKOlu9xOK+bxM8YafvoaI08ZeQKXXibRuVelOxRWNDucSGPlzXAdFUMPlqvOMg9EZxt1miVsU+ImXUd51K8Ix7s9MvvA4DAtBY19v3Q+15LLmrnTYdsjnVFr6UmSWjZWvFd8ivY9PY+/UFD0A+rCHtHoT9zLFBP4FccYAuXcgPktsNZsCq51bweFySnnThIT6EUAx3RG+/8twU4cS2HzXL+63DR7SXx79TQTconpnaRwYCCXgUeUReeRkLTaMi2g1ULHSxNjfYOqXA4DPTa0yXghftoy+asduphDnAqqqFfkik1F2Qt0FyRSHENAgIFBm17Ng2FXOLEspu2YR8t4Nnf+KL5c++GrJueKojNwuUu1V0SNrpLpRc7eo=",
"names": [
{
"primaryName": "EMCGeR+yq0Niom+CNO3UqShEh43j/+9zt3LUcaAIBORcMo+LzgiNskHFR2w5P/f6VNke1LY03Ium47vDAFbvvTilNMTB+CcIW774E98vkUAQchscyqsUMEpPK9S+6fJtkbTOVPozekoAHD1TihEkpjiBrFcI1SL1zsuV+idemiBPCisGFvYQkPRU+iZH0AzL5aSpk1p54s+/gfofVbhrq6WWOb38VdCvYsOmMOdnIaKbk17y9VBdX3aqZrQjG3eKigPVqDaKMReYTAdRuGWZFkmfVp9ogunJ1FhxJJ8YUFJkrMEaYsu87olmf5DuuIPs44muT/7J6mr1cbpRnGp157uLn4hRnqQslsB88zcT+chN6M1ON5u4Z8HoFLLAWMoM5LD9Vg/3apSX+61Rpqqqxg8r2CINYfNmYL05LrYROBDAeq2gwxeHgWskTJBVUodJHuka95PZYRJSDMCy/13k+AdG3WZJuePDFzqKHhYKSpcI4MtPiHu2zdMeOwaqgFug9gdI77ULGkf4oDxr9sZtpq9AXtHp2VO4qowlLsXxsZIzYUXf0f1RKw9x98lR3vUfbz6n0ooSGJBRuuZljIbaZxXs7du8qgc6PDw9ykupSIfq8DvWDQtsOt6kYoX1EdkxiebO527e1TGAGK/Fgwo7M58jyF+sN9Y+vzPvfvlhqQk=",
"nameType": "hm9/Z+c3qsx19wllgSlNO6oq6UCTdZz09Nr6lfgQl5X1FecWOlEG4YEBfYESbwFvC8rqBKwFiUYaB7S5jI4EGoyLW9XJbM5NumAH01vPmCnD5q1Gnv0gk8ijxWiOUSNOiTTJGqKzry38hRPyMGeZIrvjWQjrH3YGnJfdGzorG8GUTDLIxw6dxG0YOmMTMPRm18oLw8cpoqBC8QiPFQuMaVOn95+WB4VfNyuQ+mnbYMnts36VCpHrvgly1joh+eiDz5PA0RSGjQEBXg+zNWrR+3Pk1+OP3D1NKyJr9WvtanQJC+v1B+uYIMnjarN08UqntajIX/QPbg2yPlF6VjFxbOTLb8s/6geHKWyB5c1tbUXSuotWs1KPP/636uJspvf7oalADR2peXoK1XroX6F229xX/+H3w1/rovsp2xBorsj+fETwTm6Al1lMbkTjKg3n8Nea5MMOUCUt23TbDo4m0bFVQ2ACQ+Tt6E0SSUieJ5T+Fv0FAekjUVTUP2qyeYTRAAmpCxYcD8W3yLhvvI6E4L8akkT8AyTFEehM7Lx8/itB601IIZLy+qp3ylvZwWMrvE3l8JRm+K9PAo24Jcj0WKDmf9XZyS9MMyK/TRxqSv/SsNfWAIjkSKyOJuH+Cbf3r5d97wqkRER1NjTKsDudqBiu+mcIM9KToY3/9O/m6hk=",
"secondaryName": "Tk2gAKBgWk+5cWenshj5yeCQUjZf8tCc+OI5Fnfevi/VJKVHGjWWYlqK7jlFUBugde7alNfedpSUHH8qNaC0kL64sOiwqf9CMIN4Fbr/GcX4ib+aOJAEG9drMtBohvy9u9VjsHeG9PkVSi9prWA5KRUSASZXU5xIqYZYIkwMeoo2WPamCk+++bL5bx5feVuPohP3gdIE5RswUaZ8NeqGZKdDcuBCtfS5GPEYZGhAxrvHRMkjSd/2yTExAhC/loO50wxAl8oSgCt4j6Ib2grvPFP4dPp2SgHrGKIxnTkXfm+KPPHIAxFjfKKnUjeVpdRPuYkHVYEYb+TYyOsZMmy5W04FYyoasl/6SMm+8m2K0jWy0nBI4zwyOTHMh4rNZHZgHgvIvFXkIbo2b+o8X4CIVF2oG6Vymvqo2fLofNtfiEb1Fom5ZNOMeeCb5vMy4EOq7OI3AZTNKnt/bp8qq1yf4UmWHyUycc/OxkMvLFto6wSvXJWoySlEx44nptGNFrmc0wVA4sgZhbN2mkBIFbSqihC90JHebvszBHv84IqT88Di66n5h5wnrYwXbpR60bVgd0mNFqXvgluViFwyp0ADOMt60yXGfC5N1snQkG5CP8Mrhj7B9Eq12U43pXVF4vdBOcQ8/4xMcsed3vncKQF2b7fJdKSPlCxKUh4H8OqTSg0="
}
],
"postalAddress": {
"streetName": "MMx+oeWhO6z+tuVsS/GMHAxUvbFYJA3NbcFmcnO7dFcVY/WFp80a0q9i8kbA9QR33xF4qHC5Jef3COuAhL6gtPlE7AmiCgAH9AyhygkkKoPkdBogehJNwwn5+8bqJWeQ1nJYRMLBJYU6z+k21fBAbj2ERt/Vkmm7DoXLXx6tL1wxNIcclcLrd+rhlp2zEgsIIhD8gQvYX1L9iNCzORjKYntyC8/0USISBeYtqSt3SmUwL+nFHUdQV1vhtWWYO1QsIVFyPaccUm6jGlDi9G5JQQA2M5UIjKs2q6vRUiCusXMfGeowuLmThnk/87o0TM7GTJ8ORhxAzefPWAtE2neDxCCOy0VmU5DW0dK+HZEp2kEZDdxjW1hs7UfE79P2PdiNAvwyNfbCQ3ff13mXxSu/O4jTyyZgE7iciAWmzWTk4NHrma+y+4Zycw0NbQNyTHGIlCyBAoR3oFnZAs414KJK+yMdQC7TAxm6FKcf4SfWqIZH9Cc3ubNLsK15qsBIDw5k3xqGGrBsaBVwNROFuOEm46wM6XeWjvUbyRWxzSCS/xcZZc5flTp7gcRFYNEtvMvWP60MqRjSh6usyJvir1aL+l6JPdJgZid2PuCfblQaSXh3MrTrYrQMztO5FdfszMrb8I0lcNCTOTY0upfz4nO0ZCpz6KkmMCYgymZzQNxZJh8=",
"buildingNumber": "qvknuxOfuGbd3MgXA522vIl4Uw+pq0euzZBtteTWMaiuXzLyRChJhSrcA1hy71eqG03xLCPfu6IkE4ExKfxM1Y9unjTyw5YnnHbCyxaqU1uGV0dUjAyTOFAU0Dx/8UZK0gsTopc5qi+7lNRK3aaGG86R7JgY/911aq0UKb/cO3sE7m699R6DXmi6OgFNYrPjTnFQfxmEfBenQJhocICMv4eLG6n3koFbmjAi4pYoIJc39zCtPhASNdl9TqaFypHHTubnlUgYvJPB2URisxJTgws0BsgqtciLhERHydAG8uy+574UnpdbkCDmWjvEfL/yS0T4pEGrE5FYmhcOHCTH69MaVVggVkv4uyS9z6DnvEbuj6njUDPasoS7Sz+uTSCjnr+SVN5yGc7MnRUHeX2+1q2/oWtmSa+kBkn2jSoLcZxYX0DNx+cJgk8MzL9SwHlLCsqLWDoxw8XWc0M/k5vfvf/j7GnXH+A8PTEM+uJi4Xnr2CXij5wdsjfXEX2c7wfYGIVt6CGymUPTjRbqbOGrphRFudZYxZg8weCC01IMjiMSzGnc98ywDeIm7tBaU+yHAieOQ3DEBaGPfu++ybfdfHbCYY9gexxxFqmHyxHypPvFA+vU3oWYQxm9tq6uSBEzNBYo5wIIZE90qzOAXSXh1MCekk4ShKC5Oy7S6MI6d90=",
"city": "fm4SCZlzFdf9KO9unLxu44evTpR147KXy8X1eDbDSnVeR0ehWPvA7yCuzqoxfc/f6vRHNcJgG3RlWHVwwvBT9d8UEfmXoZVsYpH0hU16e9+Y/XZLueEeAaVqgBtTRettSv8UNMxcweSqiu62Qqb8GtlO3tJfm9ZPeZE/fR9/ysXXamyEWtMfd3cgDfrxZx2U+ccZoVtOWlxQKV1AZjpit4E2WU2jUuBTaNTBY4cziPTfjdy6wt5CA9uuh5Bkvnf3QNdZf70PJHUdzv1ukzuSaS2Uxjls6WHx14j8EEWp4kiYIA5LHa7pA5ex9gyNHL0CbRbo9w/KLwXp1UqVwsbXGhEVo11qkrSqA3bq+Fn53qamH1lEzOoHOW0INoVpEJq7TuBcor0VcVaKZffwaaiy7iCY2Xi0MJYbOcaY8JabBJWWxoMatefLOQ0i728fI8w7yA7hFeKUsCjW6pba3kdSS3mx8N8CV93cB/qRa96UcRbP1CdRYwubQRSlCg4fFM1FNWNnPT1kST1wujoTQd41YaEPX5KZ4Pv/sa6Tl1Jck3rPPUY98UtslwajEEtzwGQr6BFEUtp8DA7GKb5EBgVqEMbn+xRp6vlwoadFhuwcUXNrfCpHKwM/Jnk4wxzFY2CT9FnhSMZ8349JAuQ87/C2vKhkKVmcPAJicW0TrrUq0ZE=",
"postalCode": "sHnDJDY3GW2bM9xQ3t2ul9O17Ahb8aG2THJwKQTeKdilj333dyVPEgnuwhS/wsUhKYcihAltCP5DpdsJzpjD2ireLc8FSfmEKHg8+EgVvnv4FeXVGPFuomesmlw85jv2gtzZDIU80poHiWSzYEZ3hfi3D5AIf2YXse/5iVLGlGBjSnjicmB2741Vq50UyP1PO4TNolm2CqsYgPssfYXfB2eGrjSbKOH4ZGTWOHvP5uorJEpSZyt2RI1xskiFzd7/6SlfSQYheHFGxvYNJatGDkWkKc7JxQYClAbbhDQxfWD7eMdtVbSxvQV9dVRnGLaLHSWKkORWVdVD0+sSdvWKwbVxs7a3o9T3LkQGo8XM/xH+IWIHiubZ5WCQWsQOoRfk7tN3QD9lDTFMnH6HgmgeE2aI+Ap1jvEADVO3Ss/Dc1t5NB7tWKNcqKzt41z6iX71sB8IOC3kKKYzgs13v02n2BQrjLqhEQK8HPcOLJOU+09b5ISjZQrVopxaoQmjBZUeL05rKynvMQ2i5GIqmzvWAEwqXOkN3ste4nBtTrzjQYO0Dg/OmlMUFtbuRjZa00dHU9/W+VU+nnyU0pYbOnH+4aSZ6V/uASBboz95LUioZgEOk/RTRIpIfVsr5U0rgwCt+xd17ryHOsilNDshI2bQtuk2REGFE47ddLIvF+P4s/Q=",
"country": "WhcElq1vcdYOffUHkVnukKZcZjyOQG6YSYOdtz5WfAsNs049x1P3Ddzpk0ELyPl4IpDz1OYIgcRC71bI4UUJl1zlgTmjYATZYm345O8LeBOO+1QJEfKb8x/zYE7e9jID4jH6INu68uZw/sOrV1diOVBkN8SV0v3MCFI+SdIfgTRTgLZf1/iFCh3baZzrw5feNpIQFg26ZQhNyn5ViZrHbB1GmEHguWaXdb5bGyKAOUYQngetBhSDVz9LHXLaIrOLzA/t5oC/0zacvtSug1rqiIO7UMtIl5za1k6IvF7N/rwJ0PvPBIXsR6hp8uM8W7GMKzaqG+JHBZubiU67/hVBfnYx334UzV+a43sEdY//9G70V+46SLQ1DcTYsG8Ynu8swok0VOWOQeA2YWi1EF6DBkCAjpeXO3Oe9siGBxxP9qUQRgNTQW+0OAgB67jF9yTj9qKomEVKfN4+/c9GJDn84hYypJjDANWpvxqzxBOM4ouNxhWBKBTbX8ecLcW3ppphUyTUUztJ63Ud3qVk8cpjYwz0v4hS6WsgT5DZf4RTex3qwG5lsb5Zhsp3Y4yckBz2Ky07AWDPH8o5Vrk8gdbSUU+equKY1djgeg0ui85ShqoOjEJSEx/viDNIC1J6McoHyaXwycFlU4JsIM5L7LNUuwtr2piTIJVWVn+IwmGz9HI="
},
"externalReferenceId": "QdrlVMPrbn8HTJ1UFfI9JQ9UIsCc+/+eyU96fHMt4csCYaW14dxfdVjrjjf0jp8BdNp3w1KT6f7l7AaAr3X5Rb5MM0P4tUpaIIZIMr59SoLeu6OVIFRsFezIWIjL++z46N4CVP047VYX/Uzd8SI19Yj3JoToW7frN4UvPUA6iM+2ROEE04ro2tn7iDeEIKZBk6VPyEjDjXKB6RrFvNnsTrUr11aeCZLQw8wIFGR1ckM9xb+DVU1T1qjoyrCZHN3qxpsK5/Up1qaAEY8plrLw6V7Jwf9bvUFI3DhyFq6am0Gpcrepzkc1Kvlzel2HJda3qLJbr/5OChe96Cn1OSmVKjAFGzB9O0MfYx4bufrgliSa0N0boy5OUKXAM5el5CNmzPOQI3MnQkiI7vBOgetLmVRYrgCs1A3wB5b9kdfOAEopxnMS1p9gCYeC1Fx8PMjKYyKwRwtJgpsnWx8aQx2RJ1I5hhAKP/xvQU6nrpWScL7Z5HmcFRsypyYHRXGq7HfJapeE7CreEzhVgxVgB5p3HPz1GJg8vHmYFXPi9Yl6oN+udXa6KaAffj5SV9h+A6nfvAhGz9RPoTOV1rjJhBCHAiWo4SWzjex6S9iYkDLk7HY2/IXMbSxpRDYzg6Qh8Qfq+s5LsdX68H9ZDxSxxdZU2B0WewAVa+a+e1eZtyV+PJo="
},
"beneficiaryVASP": {
"vaspName": "Vey8bhZqfcKheVSwccHKs7U7w8dvkS/5dQDtad7O8KD1B8n5z16SWiX5jfjeyha8/KI1WHcJrQV61j8Kl235fM85iBr9tmQ2qf69UlZUTgXxayh8P0C0yjIewpwE6l6wqrMEMqMKBcDm+PBKxQKe9mkUhnOZUoNBA+E0k+1xBg2l7jkEMpqRkfZQUy4VhHnaf/gO2viwGB090EMiNtdOTcVR6beqRET7PZPKfC1J9hRX9FAPrMQhhFnByircrAS8sHUG9C9dYwlWLjxR6UQsvl6IMdcHH64RJBXgaOuOV1/d3ewWHinG/MaX9RCmSkyFQYUFVbuEAgNJnjGuqr226fQg59NT9WMzw3/HKK8Z0fDB/x9tvewkxQ5N+3VyQKLYe7uMW02d/xqegSsR26Ol1dqbaRNZ1kYR7twXaOPw4S+W3UiQGhxhVrAApKiedrKNbnlhsURus1BC/lGbdJfG1g8DefkKsRgXNn7vR4N7AIwXEkp0d7v2G8xpRTYOFdRUGJVwGaGexTRcHumlZ4LmHniqCl+2zoMPwrwijr3yK09h5fVWolopp22EnNf0rYEEl+CQCsY9LSEVIku7HeBn+TiUtt+y66a/ZvqTTpBNJvUb9zLbYDOn8uHA6J6pezxImu/xx1ZwjW0rXFq/xbq4TMDrrzKfAhYUBF3TklN/3Dk="
}
}
}
}
}
```
## Real-world PII data example 5: OKex - Compact withdrawal scenario
This example demonstrates a common real-world scenario where minimal required information is provided for a withdrawal.
* **Transaction Type:** Withdrawal
* **Wallet Type:** Exchange
* **Entity:** Individual
**Scenario:** A user is making a withdrawal to a hosted wallet/exchange that belongs to an individual.
### Example: Before encryption (Compact PII data)
```json theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "true",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "11000",
"subdivision": "Massachusetts",
"country": "US"
}
},
"beneficiaryVASP": {
"vaspCode": "did:ethr:0xdf41ef7dcb92ab5aed72e284db3766ace5026948"
}
}
}
}
```
### Example: After encryption (Compact encrypted data)
```json theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "odRFwGbH1U0Fbe5K7+B34qeN8eAACPPS97ORhkk5LvB2IDwmDkC2jDNyYqmy4AtzWaK6cEM+GsNvE1LIrrOkOTcKI9qFxX+3bprUbPDLSlPGmSkdCwv/xm9EGO7ZJunvBIIO0gXLK7kxkzhBT18YO3T7QQhnbJ+IKLIcb7PJi358jnkkFFMyKdDEg08IzL4a388lghqaK7uP5NWkEGdFFshFESdxQddqW745Y/arbiT6T60Kpk+ZUrapF0AcOiCmkigYyv8L572Ykzs8ev55ywrYbdrcEqfh2yIkde8C0oosbKF7r+Ko3cXVCzNDGBfpgeMmYlVs1yzqUGoShdIlBVf/neCclzXeng0bkoc0BfW52e6g4t8fOE8fBF9KS8XjNAKMpfhfCNl/5h1k6Aj1DlfzBE3ncgBtFPQ6tYu3us3LCKizfqNNiHMOw8Bo1HysplupQq4jMCsHCsRODyDmT55CCPRlvn291EGT6Mc0i9r0Pqz/bxhmapd7w3hk/kcsPgRSdqqwQmf7pMqrQStSaKBnB6pPF5NBCjGBBuIrZGaDCeLnHtTeM0BuhWzXWJltViWp/v8D5hRuG7LqbT2CFHroxTCoSy1vpd5VvjK7b/KyvGVq5jzJ4U4798g4+kVItJsbFFYtKZBCWXhqO7n/d8GVsWrWNBppRzwX4guK9Zw=",
"entityType": "UeEaw/QcSatRbgoW4Ffku2FkkHksM9gAHVkGxRuyVHxxcU6S5eMuXeWqrRWvACWIXznRaeeCB1R0cSCxIp5e8m7trptB2uyAQ7pvots9YLczm8YIWaniHelQReaNShCsir6Dh9HhcO6gVKKKWYfI0dg09pr3SQx1ajnXm3+FaT7fjDBQCtNU96OgrF6B8D5UVaapKLNQl3PWBw0GnY8LGAUfgqnAq0FZTobAdOJ0lwwuV1jRqPjxjnAjrN6mcbjQzs/7ENyOBLtIlYm/IL1TprpCK9J9SDgBHHaiCFhClP+U8oKrFU+W995ps3vTFI1W/oj86Ye0HTX8nonESmperWGtxuIzAu7CW/hSxQCIe6/lECP5ZpOZZ9YrTw++x2CEifakc+VoIOBZufMRfOHntA8et5PWJsGtCNy1aNTqgGpEjJnBEjnb882pH4rGwAu2uqJE/H2kmswZlTjci7Pcgwuzn5vOU/D5PsbJqPrZynoujQwTelFBnyVfPvEpyFxGW5QIEFQoD9gAUdz+qAqI+AlzQdGa3DqZoALQxA2DtPysZbYGVzKIRHtzLGyhIG+wtzGMw2bTWEixvMZuR7rQXgjGpFGwFmYfT71/+u56tPnCAfLUmcg++6wBknPkdeit4xOWkfmROYgJKqxu5ZPAhpBLDQsMoEohy003iq13x74=",
"names": [
{
"primaryName": "eidD4pDO6xBt8GpFymHCnJQ96bE+mqVMBdXgI+mDstmLmABzGob6JdmDcN24b4kgIpuEEGwJiJTZoVYi+lTuQdPJsA2W6WuSVYJW0Sm8jGfpva7mzg88Uf8N+nHt3yqHo8/m7OeRmd6At+lTscI0pGl6paJky9pTefF8PlSJ4IV7dA1lMNTfE/L8u5bJ/8p+7TX1O+G23UUp21G6xskC54dr6yLYRyer8JTTS2QxB42luYWC3UlIIX9dQRONx5Edr+OV8f5Na4L/+ExuD588dhcUEDjFaffoZhWJYYmfjN9lFVZE2tw6UsGxknH4dNyoc+FiMPeqL4Cw/RbQ+fhxD5otX8au/A4ByhwVMA9a4yt7+kYyNvSWpUGVj0ee43HXvxdIPyKCewaBvbNc5yvwX6X//9c27tjYM1ADRzrSSYzhVHCtlJZ2fwpnmUDcfebemvt/Vrt26BSiXrx1/G14wLhoTcCS6i9av5x82QbQVconePIbRIndIMvgx5Qeir+HU2VyCkAkBie6+NcWgdUHO3h79ZjRS5wsMC13IRX99ClXDsYoJBuOlTGxY8XrAXiTr8+CysHLXileXv+EJyoCf7HaHrXar7ym+xUCqyUnTM/PuPlUVw0D1lK7jjqSEY+0+nZuT5rC+A/n8D6UWRLAgd/V6ghFTe2171ez6hW6z2Y=",
"nameType": "B6plx2f0k0D5O86CcY1NazOEI/EfDOhQpKR0brKgDbYx5TyY3OmKOciD7NxnV4j0EgtnKMT9vB2vNMS4/Wy9tDXnHxx9h27HkKQnJVppat+jFy1cpSwFeWCjL4w1pxnjTapalZzwWD5nAqjFvOx9IRiCvvonKuRaLQSegqVhhIQCLs9+ZMtaKVy2JNfrDR8Rk8Acof+iP/k1poSwkFBMiOWCAErMEZq+NF0jwYgnDOUoQFT5IC4HDlva9PANMGFJUvW8RpsMduYrjw0e/iBPs01UbKMtCIZ6h+31+XW6b0xfVTI7jwowPNWe5uvybaG8wzPSLVnmUi2+/OoJax8tUwlCXBHD8keocSZpaPZ1ahuJW6bI+3rFP/FRk6asg8iC4A78d7RKsvomcA3+AtXUWHR7dRQlQVwRI3SWuMP+YWXfI2lt1dT4Zq957FQSdDxAb5t83rDJGv75s9x4Bv9dBY1Lz2mQkzXROHfHQ/6W1SW8FzrSysm9QT5/nFddpzhVpGLpcTt7nXNNxs3PqsFQD14KClAjDQ44yBdDD8MV7txQmo0Gc+mmqvBs0cekpwbBJpm2fRcFzFGYidzu/qUB5vBOH0urT74mLBIKYeW6TnB9xwhaXHYDkU76zntIxQRACd+8Vol85Bb3SR8B8lorgEW9OpYw2kvdnImiKrF/yJc=",
"secondaryName": "Nl+eig8i/WL4Fue5HMzQ/NCEQSj7std3eggvgh6NTW/2bLLlBuoeJttS6jmQA5Qs+/QrZ9k01AUXmYhWp7mYLFaCY9vZ9J1C7YThlrXjdSCH71dpJxoF25+HsGz2NPA+mDg0GWb+bwcwiKbHnaKlujeBNN1TKQabFwoOUXsYBeDhwveagHly45+t5QwlMi8R+wdXsfxTIAX6JnjPRywHb/uropU2X/cX2KUzgRUQ8BCBnOGO5uh7kFbCRNAMScA5byXBx4RZbolFIvMWJkpvoeXgIFKLqN5M6qe3GePLHTIWbs7EsNFlufKwYunmsADj5xWg+vO1s0L1fKslf2iWSaQTBTzcRLjdkFKngJoyyktXARQJxJwLyFksNyfhAp+64upqBg1eSiSBDcSUIKq2kZMyBdOYnq4ZrnEI89Gqlt50h9FpHuCZzgLzYhPThSKwtgOpEXG7CtVIbNy8EGGjnQiD3Hu4k1piwZ9FY+FBlz9h9oKsxHXho93oz2g1ZufGz64iqis3A+gAiNnBjJayzPRxcSRqRXfPBzU1g1IJttKsvYRP66ouocHWRpCGJNDnKTEZozDlm1G8Ysbh/HXRBG/41pzp3MTj53gNxJ+/PW0VA3bcdU4/aZOv8m4xAjufcSJUXXLQEvRe9s8hi4HroTKYxELDZC0tU4vGe4t5Vng="
}
],
"postalAddress": {
"streetName": "eiFtUS4TgBrsxUbNiksZ1RsWlPrCpE/rVrfghwhoYjqdkhdlxfZV8k/Odu/pjAVhtalWfEFOj/oWLp/IhlzkAhxKUg9GxXqv1kyMQBi/qsGm0zuNW8eYkYd9DD0K0ERWAsZXvxHfDbTxzdHEmSyu1sdefX/HM2yRuUo80DAPqY36h5YoxVtGsDZ3eJ53a6HYxD7KHf/tsdPWn+GS8BsWe4HxlDh8nvRnNB/Q6+8puvo+nNRMtBV4Vum9eY60wyGBtgn19g6m8UPe3josrsxj9zUI59uAy3AH5QjaUSeYBTXDwUZl9uP9UAjx5QyGlVnZSy8d3ciWnc0fdxBJZWoE3aGNQLJq3iaoSwSnBHNbhaeNwVw6yXzW77PJEJiONFZzbyrBnWU/yAhKPsOk4xYsNMJ33yfxj2ZLbCeIS5xyNxj7QS4W+tMyfqSIAEzneXZvYmYJHUkZykyOla7drmiXByUaGKfQvKa+Pyh9daRI+tVQE/NZnGG3+p3laLSzx7LAU7Qc4BZ9Te/FLPCfcfTphn+wPLj7MDicCpvllblK+tlKW5Q/NFF9+vTzCkXtVD1ESbzTot3Hz7nrjGUqSr89N3i6vvddWLwUfpPHDi+Jd6m2X0sZgKXQZIXL1IsWJka4OWOecIfvB4QLSiXS4Bnan7dNj6v0emYzIrswoJoWC6w=",
"buildingNumber": "JC3m27RRk8iH9HBA/lNhqTt/XnEtnDOXFIA6Tl3TPazmvAFAhd+SxHWKlVULg2rMBriy+AfHsIR9RX71+fUQBKhG0SyzuFieNFwfijDWbfVDfJYmRmiksEkepsrPNRQlC0vacP4yiIICVZqQZYt8tvkJ+3otOAtJQ9L5k/Dcf6GB0luUI8NXXglokrmWk32BUXfB/6kaLRCqSHE5fBeJDx7MdzsasQOULsavUrhjz3+XmeDoVghooYbkg47ATnAeNb3EyEFotKqeYtCsIdgk+DzjS56HAol5nmPeoJTqxhrLvQp/Qdgw8+y4Jt/W80/p/rZVMowQnt0sn+fHnn0LqeZdB3b4asbX6kQeZGHrjTO35STgs4ppvHp+YBOSoxOJsUJBHat+Yfeb0Q1vydBD2s8vQCeqUwN2EZEa7D7p6VdcSaa3fAZXrOs40qMVZDA4yjJ8unbN2egMcq64mZqfzM9IAkfN6E5AZ8L6Mgz1H8+fPQUFMwawOW6rZssaXOwjCnU9nbNcI4Rz8S07/BaY/DOPyKOPSUtG3oyplUoKPpdMPAsbokcVmJW0eb4vMT8NUIzVM0JnA+VBy49mGTNMv/N1C/9eajzj3uZjkBCxBKDOhAiYhAziZLfWqaHhCTBNyqB0e2776wDEZcGvatlz4kRffZEBh0O7YfoWGGqKGfg=",
"city": "td6CCpM/U799g8jmbSfm4HBKCONWLuJ0FNJ5hIrRBsYa4ju2+poEsmu5dUmFNg17afhMBhbchuNY9RY0SZxNnwIloPQibdJrkY2PpxQOaytXJvdHfbCDie2IZDSZ2kqOuT/FNMQlpbkUaSGVIrTYMrXLuT7Y4lvH+nsOEL3Hpkg+sKEXgZco7UlkoZhas6oQ3RYAzDGpNomzwWfQLy75ef/vfvomSny6a8RroZscATgNKLPIBedi+Aq9egELIE5c3+JHhnhn1a23R75HzKG5RHb8HZ2ddAFG7UJWOf0mOzaKkLF89xLgSmVCOGQCBEyW67SkM4yeWZU5PTxIrmKORl8ndfQVYGsFh0UikAZ+7yVCsghlj1kKrH8vP8QuFEshW6iHTENesbEAXKu5uFh17ANcwgwTetwPjxe/EDBH69bSYt9WzPntsDs0Dk3vvUMZ2YMXyFaK/mKa7F7on4JZHcGIj0Wb6GVM+M8q0R9UyGDTz1L+ho6hgA2OsEIJ/7RKAn9KVCOXyDiH9sEHgrF9bhGGOUkkRjK5PYmIao9pEPWavcIsKvvCeFsm+tk0H1RuTp1GvojYsbyAGSKpi1a2wnqY+XCtDkUDE1mOCzzwklMIW6qCq1QmNr0NQbocH7GI9oWBTrl+A7y5NJpzBHHkHH7t06OODv0jjbkV+hj7Lj4=",
"postalCode": "bz0BGwPFlCY5hyMkbfoxYkTq3uCFBoqG4gIDh56dz8cthPteUTRHA1MN4QJRHaDYiXkl0FxRhwY7k7FSm3+XqhPlafF1UNTE5Dq0CAQmYoTtRgLst6pREZWePMePXF3UeitfAMByZU2G5kt6hPO0ut6oBLZrT52ds8O83IjC1iJye9nSl7QU9U+Li+wRi8yqH4gSP6h+Hyf4hrYP7rqRbOehLolDfOIzxedpEPkr78ryfApv2lZaZWffMYwz5N6I2pKp6U9FGfCv3HJbIsyK0JiuFbOND9gPn7Fb98FcSL0OKgvS0H6+8DxDA84CRCjNUOKEHf4uu+5vB9rt/XR5JTPxpk0wFtwUPdt2DroG4Sl13FhjZL2nCJbe5EC9mPa2pHotaTRs/NeG5zlMGGTQA96VA1DR6ZugO0YxjCkmBbCQ75/6yKSpH4xiVaIk2mDk+SpbjpjjzJXnHrdAGwPHig/v9EIvyYTkwBBOcQ0M0HOcKPhTOxcFKET3fWkM498Oya4A7/3aN0bbdpfgIbjIX/3A8BObd+UMjYuz1fPwRIZHxDVUMuPdbrA0oGxxFZV1tVwPracgJ845cygt3HJbn6l7I+ao/VtTyhorfqFwTtpaHd/WmOw6Jr0zpRaYEyBBjS+eQD2g2OYOAEDoIqrvMr8isZ9kRqUxXXTxtcDYDSM=",
"subdivision": "IYO7soEscFJRNL4XMrghCgLi64XywMSRSpwImiVzU0Qh7fdXqgsbkpnRdW0XxsCgdmpSjAb+7OAOMMKZFKpzTed7nSugGz0fKYZR+PH8Ca+lBGwjqIax8w2b69jZSGDNiyMMRoIEDvGK/f5exaJR408YuUShl6vGpSH6+p28d/hBbN/VEBCnFVkU/6+G62Ej7NmQ4ucn3388xTbMQyq+D0KpR4PeI3gi5SYpuKsgu8sniD0j/pqZsmGD/OY4KW90A2XqnkX4x7dMd7jvL8HDkSsL1ewOx4BiwZgbmrJjuX2eV+SRpYhj4a4i5na/2kIS2z3DgahfCkDsCxjWM2hf4IpbDvAtViYEero2yWBlwKkF6f36XO39uEIorl3RJa6saKkvg5CoiRUxEjazpn8rInJoLKo1NbtxgDyoYmEqqKcrn26Nv5ETOFDu1Y8AljPOhA4FW7N3xcBJDKfYIVW1TJiXZ1zDveFj0GccHP+RZOixuBT5gu2BWSDG9Xz7oCu4eTsQoWqeOBe2WFNQFWXQ91dp+a+asDoSCkd/KDI/8drdp3y/Yhyx7JI4nQ7IVXWcodJA/X3y6aMxGdnt1p1aDp+i8auMzfvwsEAH3ATzS1MNYoGdg05oFpDk38rXbQvdEsde+vKZmmo4u6n7i+weNaeAHeAOkhAkyBoPAZxVdrY=",
"country": "aBDC/toz/kTpplSpTc10iV4IRqVqaT1cYoOqvpJy00Rpnnw4qB0gf29FJsaW5hG1XV4J6nPOphcgCK1tN9LGeqk2tF2SAl1cnTiEfuDTrX4D4Uj8dxlAKOuqcT9p+lhhGf7sWsS2/qSyAB/gAv2eyCs7RuVdL7kShgVFHXg5LZ/1zA26UI94lk0CLy7ASqPByvoJWLO07YQZuFhlfvsAE6Jt52qW/Nm5kGibwhhej/ayPfc+9qndVROzQ7I5O+epCBclyPG472a6Gwyl4UC4ftOYFB+S0Ex+PHolg4UTCDJs/l2WkH35+PYpel/pDel7WRryFzsb8MXThrx5lBKXzEh6s+++JVuEL8pKt/FbbBzuVr9D8wlnmhyekuo7ju5z1DbeRPSmgvTD9jWc8wp+/BQ4ptzewn8qVIRT8Zj2Tl5cNfCSrlGJOCQHKSX4WecotQ2LtcQiu6z8CKc5HWoiAdJIIOf1JNFTe/6XsURcwsdJ5OxMnKNCRe4eCeaPQqJtYQGh71F68fSRULyAzbNLD3lKOcy0J04t+57ohnhPQ9XUUqczqY0KJFWolLoCPhyYwmyrm83wlumhhU6VjJUjR2235vy5pU/b35iZrCxxRGdD10zFZBoZ+uyp1tl6cACZBYxmNqUqvq3PJngWD6UuyvyLiJ6AhJA82c6LuXpCfnM="
}
},
"beneficiaryVASP": {
"vaspCode": "NPUTGqnJs2aPOH9yAaO5W/VGfYvrILZiicUBsQkr8eaomQKawkSZQYAMo7ay/XZeLejNz2e5WNaSTUs398t+PINZ0ALqGH/ZNye+Yz1CvoGhgvyyWLrfZ38bTq81jIUYu4UXpabEw78e1GXWTHDqzRLpxjD0Z8d7EA+k5fN5pg1lDDTUldqMlvIRoYhoHeT9H4TZo/lNaNGqjVbfEcZ9G2UycPQjWrVJ+DaYVNgXzzWGqjnH/frBXSrmqBCmjZofyvQq+ETSGGY9H0o5GzZntN9NyGVD3TljIuZLechN68rspiMt6Fs6D7S1aN58/qB5rCS06uZ3fjZuWXX9ip2dSMDyjx935EIyhutqKdQqhO+v6uo++v5UDv05vIIKuUT471sY3bpcNQVII5dlBa5LdnOOta7YjZL8iwuYWBxtfOpyeWEU6Z/0+AIv6faSlJ0t7evhUb+emvVXE1kfLGi+jepHVNtGvNDraadjFU1v4+Vo79bgqBhD4FHyJzo2IoDHVmZgyAOXOFaBWfNgTGAPX88btgV+qp0CWImk3PQeaSb5b9kRTHaOCxe75EFuIAKK3+MDHPfmCXXyv2EXubFW6bPXOX5YBfD0XtvToW4JfCv3BaUxAK9ib7ZPcpWboSr7wBKQErpcI9SCEeBg1bAK5282EImv/ketjK0sOHC1W2Y="
}
}
}
}
```
## Mandatory field requirements by exchange
Understanding which fields are required for each exchange ensures successful Travel Rule compliance when submitting transactions. The mandatory properties vary by exchange—some have jurisdiction-specific requirements, while others use standardized field combinations.
### Binance
Binance's mandatory properties vary by jurisdiction. To simplify mapping and usage, see the following resources:
* [Mandatory properties for Binance withdrawals](/docs/mandatory-properties-for-withdrawals)
* [Mandatory properties for Binance deposits](/docs/mandatory-properties-for-deposits)
### Bitstamp
Bitstamp does not have jurisdiction-specific requirements. Instead, Bitstamp requires specific field combinations based on transaction type and participant relationship.
**All Bitstamp transactions require:**
* Complete `postalAddress` (streetName, buildingNumber, city, postalCode, country) for all scenarios
* For Individual entities: `names`, `dateOfBirth`
* For Business entities: `company.name`
These requirements apply to both deposits and withdrawals, regardless of whether the participant relationship is FirstParty or ThirdParty.
For detailed field requirements, see:
* [Mandatory fields for Bitstamp withdrawals](/docs/mandatory-fields-for-bitstamp-withdrawals)
* [Mandatory fields for Bitstamp deposits](/docs/mandatory-fields-for-bitstamp-deposits)
### Bitfinex
Bitfinex only requires `piiData` for withdrawals. For deposits, the sending VASP transmits originator information directly to Bitfinex through Travel Rule compliance protocols, so no `piiData` is required in your Fireblocks transaction request.
**All Bitfinex withdrawals require:**
* Complete `postalAddress` (streetName, buildingNumber, city, postalCode, country)
* For Individual entities: `names`
* For Business entities: `company.name`
These requirements apply regardless of participant relationship (FirstParty or ThirdParty). Unlike Bitstamp, Bitfinex does not require `dateOfBirth` for individuals.
### Note
The Bitfinex withdrawal examples intentionally omit `transactionData` and `originatingVASP` as these fields are optional for withdrawals.
The following example demonstrates a common real-world scenario where minimal required information is provided for a withdrawal.
* **Transaction Type:** Withdrawal
* **Wallet Type:** Exchange
* **Entity:** Individual
**Scenario:** A user is making a withdrawal to a hosted wallet/exchange that belongs to an individual.
**Before Encryption (Compact PII Data)**
```json theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "true",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "11000",
"subdivision": "Massachusetts",
"country": "US"
}
},
"beneficiaryVASP": {
"vaspCode": "did:ethr:0xdf41ef7dcb92ab5aed72e284db3766ace5026948"
}
}
}
}
```
**After Encryption (Compact Encrypted Data)**
```json theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "odRFwGbH1U0Fbe5K7+B34qeN8eAACPPS97ORhkk5LvB2IDwmDkC2jDNyYqmy4AtzWaK6cEM+GsNvE1LIrrOkOTcKI9qFxX+3bprUbPDLSlPGmSkdCwv/xm9EGO7ZJunvBIIO0gXLK7kxkzhBT18YO3T7QQhnbJ+IKLIcb7PJi358jnkkFFMyKdDEg08IzL4a388lghqaK7uP5NWkEGdFFshFESdxQddqW745Y/arbiT6T60Kpk+ZUrapF0AcOiCmkigYyv8L572Ykzs8ev55ywrYbdrcEqfh2yIkde8C0oosbKF7r+Ko3cXVCzNDGBfpgeMmYlVs1yzqUGoShdIlBVf/neCclzXeng0bkoc0BfW52e6g4t8fOE8fBF9KS8XjNAKMpfhfCNl/5h1k6Aj1DlfzBE3ncgBtFPQ6tYu3us3LCKizfqNNiHMOw8Bo1HysplupQq4jMCsHCsRODyDmT55CCPRlvn291EGT6Mc0i9r0Pqz/bxhmapd7w3hk/kcsPgRSdqqwQmf7pMqrQStSaKBnB6pPF5NBCjGBBuIrZGaDCeLnHtTeM0BuhWzXWJltViWp/v8D5hRuG7LqbT2CFHroxTCoSy1vpd5VvjK7b/KyvGVq5jzJ4U4798g4+kVItJsbFFYtKZBCWXhqO7n/d8GVsWrWNBppRzwX4guK9Zw=",
"entityType": "UeEaw/QcSatRbgoW4Ffku2FkkHksM9gAHVkGxRuyVHxxcU6S5eMuXeWqrRWvACWIXznRaeeCB1R0cSCxIp5e8m7trptB2uyAQ7pvots9YLczm8YIWaniHelQReaNShCsir6Dh9HhcO6gVKKKWYfI0dg09pr3SQx1ajnXm3+FaT7fjDBQCtNU96OgrF6B8D5UVaapKLNQl3PWBw0GnY8LGAUfgqnAq0FZTobAdOJ0lwwuV1jRqPjxjnAjrN6mcbjQzs/7ENyOBLtIlYm/IL1TprpCK9J9SDgBHHaiCFhClP+U8oKrFU+W995ps3vTFI1W/oj86Ye0HTX8nonESmperWGtxuIzAu7CW/hSxQCIe6/lECP5ZpOZZ9YrTw++x2CEifakc+VoIOBZufMRfOHntA8et5PWJsGtCNy1aNTqgGpEjJnBEjnb882pH4rGwAu2uqJE/H2kmswZlTjci7Pcgwuzn5vOU/D5PsbJqPrZynoujQwTelFBnyVfPvEpyFxGW5QIEFQoD9gAUdz+qAqI+AlzQdGa3DqZoALQxA2DtPysZbYGVzKIRHtzLGyhIG+wtzGMw2bTWEixvMZuR7rQXgjGpFGwFmYfT71/+u56tPnCAfLUmcg++6wBknPkdeit4xOWkfmROYgJKqxu5ZPAhpBLDQsMoEohy003iq13x74=",
"names": [
{
"primaryName": "eidD4pDO6xBt8GpFymHCnJQ96bE+mqVMBdXgI+mDstmLmABzGob6JdmDcN24b4kgIpuEEGwJiJTZoVYi+lTuQdPJsA2W6WuSVYJW0Sm8jGfpva7mzg88Uf8N+nHt3yqHo8/m7OeRmd6At+lTscI0pGl6paJky9pTefF8PlSJ4IV7dA1lMNTfE/L8u5bJ/8p+7TX1O+G23UUp21G6xskC54dr6yLYRyer8JTTS2QxB42luYWC3UlIIX9dQRONx5Edr+OV8f5Na4L/+ExuD588dhcUEDjFaffoZhWJYYmfjN9lFVZE2tw6UsGxknH4dNyoc+FiMPeqL4Cw/RbQ+fhxD5otX8au/A4ByhwVMA9a4yt7+kYyNvSWpUGVj0ee43HXvxdIPyKCewaBvbNc5yvwX6X//9c27tjYM1ADRzrSSYzhVHCtlJZ2fwpnmUDcfebemvt/Vrt26BSiXrx1/G14wLhoTcCS6i9av5x82QbQVconePIbRIndIMvgx5Qeir+HU2VyCkAkBie6+NcWgdUHO3h79ZjRS5wsMC13IRX99ClXDsYoJBuOlTGxY8XrAXiTr8+CysHLXileXv+EJyoCf7HaHrXar7ym+xUCqyUnTM/PuPlUVw0D1lK7jjqSEY+0+nZuT5rC+A/n8D6UWRLAgd/V6ghFTe2171ez6hW6z2Y=",
"nameType": "B6plx2f0k0D5O86CcY1NazOEI/EfDOhQpKR0brKgDbYx5TyY3OmKOciD7NxnV4j0EgtnKMT9vB2vNMS4/Wy9tDXnHxx9h27HkKQnJVppat+jFy1cpSwFeWCjL4w1pxnjTapalZzwWD5nAqjFvOx9IRiCvvonKuRaLQSegqVhhIQCLs9+ZMtaKVy2JNfrDR8Rk8Acof+iP/k1poSwkFBMiOWCAErMEZq+NF0jwYgnDOUoQFT5IC4HDlva9PANMGFJUvW8RpsMduYrjw0e/iBPs01UbKMtCIZ6h+31+XW6b0xfVTI7jwowPNWe5uvybaG8wzPSLVnmUi2+/OoJax8tUwlCXBHD8keocSZpaPZ1ahuJW6bI+3rFP/FRk6asg8iC4A78d7RKsvomcA3+AtXUWHR7dRQlQVwRI3SWuMP+YWXfI2lt1dT4Zq957FQSdDxAb5t83rDJGv75s9x4Bv9dBY1Lz2mQkzXROHfHQ/6W1SW8FzrSysm9QT5/nFddpzhVpGLpcTt7nXNNxs3PqsFQD14KClAjDQ44yBdDD8MV7txQmo0Gc+mmqvBs0cekpwbBJpm2fRcFzFGYidzu/qUB5vBOH0urT74mLBIKYeW6TnB9xwhaXHYDkU76zntIxQRACd+8Vol85Bb3SR8B8lorgEW9OpYw2kvdnImiKrF/yJc=",
"secondaryName": "Nl+eig8i/WL4Fue5HMzQ/NCEQSj7std3eggvgh6NTW/2bLLlBuoeJttS6jmQA5Qs+/QrZ9k01AUXmYhWp7mYLFaCY9vZ9J1C7YThlrXjdSCH71dpJxoF25+HsGz2NPA+mDg0GWb+bwcwiKbHnaKlujeBNN1TKQabFwoOUXsYBeDhwveagHly45+t5QwlMi8R+wdXsfxTIAX6JnjPRywHb/uropU2X/cX2KUzgRUQ8BCBnOGO5uh7kFbCRNAMScA5byXBx4RZbolFIvMWJkpvoeXgIFKLqN5M6qe3GePLHTIWbs7EsNFlufKwYunmsADj5xWg+vO1s0L1fKslf2iWSaQTBTzcRLjdkFKngJoyyktXARQJxJwLyFksNyfhAp+64upqBg1eSiSBDcSUIKq2kZMyBdOYnq4ZrnEI89Gqlt50h9FpHuCZzgLzYhPThSKwtgOpEXG7CtVIbNy8EGGjnQiD3Hu4k1piwZ9FY+FBlz9h9oKsxHXho93oz2g1ZufGz64iqis3A+gAiNnBjJayzPRxcSRqRXfPBzU1g1IJttKsvYRP66ouocHWRpCGJNDnKTEZozDlm1G8Ysbh/HXRBG/41pzp3MTj53gNxJ+/PW0VA3bcdU4/aZOv8m4xAjufcSJUXXLQEvRe9s8hi4HroTKYxELDZC0tU4vGe4t5Vng="
}
],
"postalAddress": {
"streetName": "eiFtUS4TgBrsxUbNiksZ1RsWlPrCpE/rVrfghwhoYjqdkhdlxfZV8k/Odu/pjAVhtalWfEFOj/oWLp/IhlzkAhxKUg9GxXqv1kyMQBi/qsGm0zuNW8eYkYd9DD0K0ERWAsZXvxHfDbTxzdHEmSyu1sdefX/HM2yRuUo80DAPqY36h5YoxVtGsDZ3eJ53a6HYxD7KHf/tsdPWn+GS8BsWe4HxlDh8nvRnNB/Q6+8puvo+nNRMtBV4Vum9eY60wyGBtgn19g6m8UPe3josrsxj9zUI59uAy3AH5QjaUSeYBTXDwUZl9uP9UAjx5QyGlVnZSy8d3ciWnc0fdxBJZWoE3aGNQLJq3iaoSwSnBHNbhaeNwVw6yXzW77PJEJiONFZzbyrBnWU/yAhKPsOk4xYsNMJ33yfxj2ZLbCeIS5xyNxj7QS4W+tMyfqSIAEzneXZvYmYJHUkZykyOla7drmiXByUaGKfQvKa+Pyh9daRI+tVQE/NZnGG3+p3laLSzx7LAU7Qc4BZ9Te/FLPCfcfTphn+wPLj7MDicCpvllblK+tlKW5Q/NFF9+vTzCkXtVD1ESbzTot3Hz7nrjGUqSr89N3i6vvddWLwUfpPHDi+Jd6m2X0sZgKXQZIXL1IsWJka4OWOecIfvB4QLSiXS4Bnan7dNj6v0emYzIrswoJoWC6w=",
"buildingNumber": "JC3m27RRk8iH9HBA/lNhqTt/XnEtnDOXFIA6Tl3TPazmvAFAhd+SxHWKlVULg2rMBriy+AfHsIR9RX71+fUQBKhG0SyzuFieNFwfijDWbfVDfJYmRmiksEkepsrPNRQlC0vacP4yiIICVZqQZYt8tvkJ+3otOAtJQ9L5k/Dcf6GB0luUI8NXXglokrmWk32BUXfB/6kaLRCqSHE5fBeJDx7MdzsasQOULsavUrhjz3+XmeDoVghooYbkg47ATnAeNb3EyEFotKqeYtCsIdgk+DzjS56HAol5nmPeoJTqxhrLvQp/Qdgw8+y4Jt/W80/p/rZVMowQnt0sn+fHnn0LqeZdB3b4asbX6kQeZGHrjTO35STgs4ppvHp+YBOSoxOJsUJBHat+Yfeb0Q1vydBD2s8vQCeqUwN2EZEa7D7p6VdcSaa3fAZXrOs40qMVZDA4yjJ8unbN2egMcq64mZqfzM9IAkfN6E5AZ8L6Mgz1H8+fPQUFMwawOW6rZssaXOwjCnU9nbNcI4Rz8S07/BaY/DOPyKOPSUtG3oyplUoKPpdMPAsbokcVmJW0eb4vMT8NUIzVM0JnA+VBy49mGTNMv/N1C/9eajzj3uZjkBCxBKDOhAiYhAziZLfWqaHhCTBNyqB0e2776wDEZcGvatlz4kRffZEBh0O7YfoWGGqKGfg=",
"city": "td6CCpM/U799g8jmbSfm4HBKCONWLuJ0FNJ5hIrRBsYa4ju2+poEsmu5dUmFNg17afhMBhbchuNY9RY0SZxNnwIloPQibdJrkY2PpxQOaytXJvdHfbCDie2IZDSZ2kqOuT/FNMQlpbkUaSGVIrTYMrXLuT7Y4lvH+nsOEL3Hpkg+sKEXgZco7UlkoZhas6oQ3RYAzDGpNomzwWfQLy75ef/vfvomSny6a8RroZscATgNKLPIBedi+Aq9egELIE5c3+JHhnhn1a23R75HzKG5RHb8HZ2ddAFG7UJWOf0mOzaKkLF89xLgSmVCOGQCBEyW67SkM4yeWZU5PTxIrmKORl8ndfQVYGsFh0UikAZ+7yVCsghlj1kKrH8vP8QuFEshW6iHTENesbEAXKu5uFh17ANcwgwTetwPjxe/EDBH69bSYt9WzPntsDs0Dk3vvUMZ2YMXyFaK/mKa7F7on4JZHcGIj0Wb6GVM+M8q0R9UyGDTz1L+ho6hgA2OsEIJ/7RKAn9KVCOXyDiH9sEHgrF9bhGGOUkkRjK5PYmIao9pEPWavcIsKvvCeFsm+tk0H1RuTp1GvojYsbyAGSKpi1a2wnqY+XCtDkUDE1mOCzzwklMIW6qCq1QmNr0NQbocH7GI9oWBTrl+A7y5NJpzBHHkHH7t06OODv0jjbkV+hj7Lj4=",
"postalCode": "bz0BGwPFlCY5hyMkbfoxYkTq3uCFBoqG4gIDh56dz8cthPteUTRHA1MN4QJRHaDYiXkl0FxRhwY7k7FSm3+XqhPlafF1UNTE5Dq0CAQmYoTtRgLst6pREZWePMePXF3UeitfAMByZU2G5kt6hPO0ut6oBLZrT52ds8O83IjC1iJye9nSl7QU9U+Li+wRi8yqH4gSP6h+Hyf4hrYP7rqRbOehLolDfOIzxedpEPkr78ryfApv2lZaZWffMYwz5N6I2pKp6U9FGfCv3HJbIsyK0JiuFbOND9gPn7Fb98FcSL0OKgvS0H6+8DxDA84CRCjNUOKEHf4uu+5vB9rt/XR5JTPxpk0wFtwUPdt2DroG4Sl13FhjZL2nCJbe5EC9mPa2pHotaTRs/NeG5zlMGGTQA96VA1DR6ZugO0YxjCkmBbCQ75/6yKSpH4xiVaIk2mDk+SpbjpjjzJXnHrdAGwPHig/v9EIvyYTkwBBOcQ0M0HOcKPhTOxcFKET3fWkM498Oya4A7/3aN0bbdpfgIbjIX/3A8BObd+UMjYuz1fPwRIZHxDVUMuPdbrA0oGxxFZV1tVwPracgJ845cygt3HJbn6l7I+ao/VtTyhorfqFwTtpaHd/WmOw6Jr0zpRaYEyBBjS+eQD2g2OYOAEDoIqrvMr8isZ9kRqUxXXTxtcDYDSM=",
"subdivision": "IYO7soEscFJRNL4XMrghCgLi64XywMSRSpwImiVzU0Qh7fdXqgsbkpnRdW0XxsCgdmpSjAb+7OAOMMKZFKpzTed7nSugGz0fKYZR+PH8Ca+lBGwjqIax8w2b69jZSGDNiyMMRoIEDvGK/f5exaJR408YuUShl6vGpSH6+p28d/hBbN/VEBCnFVkU/6+G62Ej7NmQ4ucn3388xTbMQyq+D0KpR4PeI3gi5SYpuKsgu8sniD0j/pqZsmGD/OY4KW90A2XqnkX4x7dMd7jvL8HDkSsL1ewOx4BiwZgbmrJjuX2eV+SRpYhj4a4i5na/2kIS2z3DgahfCkDsCxjWM2hf4IpbDvAtViYEero2yWBlwKkF6f36XO39uEIorl3RJa6saKkvg5CoiRUxEjazpn8rInJoLKo1NbtxgDyoYmEqqKcrn26Nv5ETOFDu1Y8AljPOhA4FW7N3xcBJDKfYIVW1TJiXZ1zDveFj0GccHP+RZOixuBT5gu2BWSDG9Xz7oCu4eTsQoWqeOBe2WFNQFWXQ91dp+a+asDoSCkd/KDI/8drdp3y/Yhyx7JI4nQ7IVXWcodJA/X3y6aMxGdnt1p1aDp+i8auMzfvwsEAH3ATzS1MNYoGdg05oFpDk38rXbQvdEsde+vKZmmo4u6n7i+weNaeAHeAOkhAkyBoPAZxVdrY=",
"country": "aBDC/toz/kTpplSpTc10iV4IRqVqaT1cYoOqvpJy00Rpnnw4qB0gf29FJsaW5hG1XV4J6nPOphcgCK1tN9LGeqk2tF2SAl1cnTiEfuDTrX4D4Uj8dxlAKOuqcT9p+lhhGf7sWsS2/qSyAB/gAv2eyCs7RuVdL7kShgVFHXg5LZ/1zA26UI94lk0CLy7ASqPByvoJWLO07YQZuFhlfvsAE6Jt52qW/Nm5kGibwhhej/ayPfc+9qndVROzQ7I5O+epCBclyPG472a6Gwyl4UC4ftOYFB+S0Ex+PHolg4UTCDJs/l2WkH35+PYpel/pDel7WRryFzsb8MXThrx5lBKXzEh6s+++JVuEL8pKt/FbbBzuVr9D8wlnmhyekuo7ju5z1DbeRPSmgvTD9jWc8wp+/BQ4ptzewn8qVIRT8Zj2Tl5cNfCSrlGJOCQHKSX4WecotQ2LtcQiu6z8CKc5HWoiAdJIIOf1JNFTe/6XsURcwsdJ5OxMnKNCRe4eCeaPQqJtYQGh71F68fSRULyAzbNLD3lKOcy0J04t+57ohnhPQ9XUUqczqY0KJFWolLoCPhyYwmyrm83wlumhhU6VjJUjR2235vy5pU/b35iZrCxxRGdD10zFZBoZ+uyp1tl6cACZBYxmNqUqvq3PJngWD6UuyvyLiJ6AhJA82c6LuXpCfnM="
}
},
"beneficiaryVASP": {
"vaspCode": "NPUTGqnJs2aPOH9yAaO5W/VGfYvrILZiicUBsQkr8eaomQKawkSZQYAMo7ay/XZeLejNz2e5WNaSTUs398t+PINZ0ALqGH/ZNye+Yz1CvoGhgvyyWLrfZ38bTq81jIUYu4UXpabEw78e1GXWTHDqzRLpxjD0Z8d7EA+k5fN5pg1lDDTUldqMlvIRoYhoHeT9H4TZo/lNaNGqjVbfEcZ9G2UycPQjWrVJ+DaYVNgXzzWGqjnH/frBXSrmqBCmjZofyvQq+ETSGGY9H0o5GzZntN9NyGVD3TljIuZLechN68rspiMt6Fs6D7S1aN58/qB5rCS06uZ3fjZuWXX9ip2dSMDyjx935EIyhutqKdQqhO+v6uo++v5UDv05vIIKuUT471sY3bpcNQVII5dlBa5LdnOOta7YjZL8iwuYWBxtfOpyeWEU6Z/0+AIv6faSlJ0t7evhUb+emvVXE1kfLGi+jepHVNtGvNDraadjFU1v4+Vo79bgqBhD4FHyJzo2IoDHVmZgyAOXOFaBWfNgTGAPX88btgV+qp0CWImk3PQeaSb5b9kRTHaOCxe75EFuIAKK3+MDHPfmCXXyv2EXubFW6bPXOX5YBfD0XtvToW4JfCv3BaUxAK9ib7ZPcpWboSr7wBKQErpcI9SCEeBg1bAK5282EImv/ketjK0sOHC1W2Y="
}
}
}
}
```
## Final checklist for developers
Before deploying your integration, ensure you have completed the following:
* [ ] **Select a cryptographic library/SDK:** Choose and integrate a library that can perform hybrid encryption (RSA-OAEP + AES-256-GCM) using a counterparty's public key.
* [ ] **Implement public key retrieval:** Implement the logic to securely fetch the recipient's public key from the Fireblocks API before each transaction.
* [ ] **Map PII fields:** Ensure your system correctly maps your customer data to the fields required by the `piiData` object structure.
* [ ] **Handle jurisdictional logic:** Implement logic to determine the required PII based on the transaction amount and the jurisdictions of both VASPs.
* [ ] **Encrypt the payload:** Confirm that all sensitive fields within the `piiData` object are correctly encrypted.
* [ ] **Test with Sandbox:** Use the sandbox environments provided by Fireblocks to test your implementation thoroughly.
* [ ] **Confirm data accuracy:** Work with your compliance team to ensure the plaintext PII being sent for encryption is accurate and matches the KYC records on file.
# Add an Exchange Account
Source: https://developers.fireblocks.com/docs/add-an-exchange-account
You can easily add your own exchange account to the Fireblocks workspace, provided it's supported by Fireblocks. Once connected, you can seamlessly transfer funds between your exchange account and Fireblocks via the console or API. This guide will explain to you how to add an exchange account via our TypeScript and Python SDK.
## Prerequisites
1. Contact your CSM to enable this feature and get access to:
1. [Get Exchange Accounts Credentials Public Key endpoint](/reference/getexchangeaccountscredentialspublickey)
2. [Add an Exchange Account endpoint](/reference/addexchangeaccount)
2. Make sure to prepare your workspace and perform all the steps necessary [here](/reference/quickstart).
3. Install all the prerequisites for our [TypeScript](/reference/typescript-sdk) and [Python](/reference/new-python-sdk) SDK.
## Add an Exchange Account via SDK
You can use the following code to add an exchange account
### Note:
This endpoint currently only supports the following exchanges `INDEPENDENT_RESERVE`,`BIT`, `BITHUMB`, `BITSO`, `CRYPTOCOM`, `BYBIT_V2`, `WHITEBIT` , `HITBTC`, `GEMINI`, `HUOBI`, `GATEIO`, `COINHAKO`, `BULLISH`, `BITGET`, and `LUNO`
```python Python theme={"system"}
import base64
import json
from fireblocks.client import Fireblocks
from fireblocks.client_configuration import ClientConfiguration
from fireblocks.base_path import BasePath
from fireblocks.models.add_exchange_account_request import AddExchangeAccountRequest
from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from pprint import pprint
my_api_key="your_api_key"
with open('your_secret_key_file_path', 'r') as file:
secret_key_value = file.read()
configuration = ClientConfiguration(
api_key=my_api_key,
secret_key=secret_key_value,
base_path=BasePath.US #Make sure to use the correct environment. Please see the note
)
with Fireblocks(configuration) as fireblocks:
tenant_id = None
public_key = None
try:
# Get exchange accounts credentials public key
api_response = fireblocks.exchange_accounts.get_exchange_accounts_credentials_public_key().result()
tenant_id = api_response.data.tenant_id
public_key = api_response.data.public_key
except Exception as e:
print("Exception when calling ExchangeAccountAPI->get_exchange_accounts_credentials_public_key: %s\n" % e)
exit(1)
# Credentials encryption
exchange_api_key = "your_exchange_account_api_key"
exchange_api_secret = 'your_exchange_account_secret_key'
credentials = {
"apiKey": exchange_api_key,
"secret": exchange_api_secret,
"tenantId": tenant_id,
}
pem_public_key = load_pem_public_key(bytearray(public_key, 'utf-8'), default_backend())
credentials_str = bytes(json.dumps(credentials, separators=(',', ':')), 'utf-8')
ciphertext = pem_public_key.encrypt(
credentials_str,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
encrypted_creds = bytes.decode(base64.b64encode(ciphertext))
# Prepare add exchange account request
add_exchange_account_request: AddExchangeAccountRequest = AddExchangeAccountRequest(
exchange_type='BIT',
name='My BIT account',
creds=encrypted_creds,
key=exchange_api_key
)
try:
# Add an exchange account
future = fireblocks.exchange_accounts.add_exchange_account(add_exchange_account_request=add_exchange_account_request)
api_response = future.result() # Wait for the response
print("The response of ExchangeAccountAPI->add_exchange_account:\n")
pprint(api_response.data.to_json())
except Exception as e:
print("Exception when calling ExchangeAccountAPI->add_exchange_account: %s\n" % e)
```
```typescript TypeScript theme={"system"}
import { readFileSync } from 'fs';
import { Fireblocks, BasePath, ExchangeAccountsApiAddExchangeAccountRequest } from "@fireblocks/ts-sdk";
import { webcrypto } from "crypto";
const crypto = webcrypto;
const EXCHANGE_API_KEY = "exchange_api_key";
const EXCHANGE_API_SECRET = "exchange_api_secret";
const FIREBLOCKS_API_SECRET_PATH = "./fireblocks_secret.key";
const fireblocks = new Fireblocks({
apiKey: "my-api-key",
basePath: BasePath.US, //make sure to use the correct environment. Please see the note
secretKey: readFileSync(FIREBLOCKS_API_SECRET_PATH, "utf8"),
});
async function getExchangeAccountsCredentialsPublicKey() {
return (await fireblocks.exchangeAccounts.getExchangeAccountsCredentialsPublicKey()).data;
}
function str2ab(str: string): ArrayBuffer {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
};
function arrayBufferToBase64(buffer: ArrayBuffer): string {
const bytes = new Uint8Array(buffer);
let binary = '';
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
async function encryptCredentials(publicKey: string, payload: any) {
const pemHeader = '-----BEGIN PUBLIC KEY-----\n';
const pemFooter = '\n-----END PUBLIC KEY-----';
const extractedCode = publicKey.substring(pemHeader.length, publicKey.length - pemFooter.length);
const binaryDerString = atob(extractedCode);
const binaryDer = str2ab(binaryDerString);
const cryptoPublicKey = await crypto.subtle.importKey(
'spki',
binaryDer,
{
name: 'RSA-OAEP',
hash: 'SHA-256',
},
true,
['encrypt'],
);
const payloadStr = JSON.stringify(payload);
const encodedDataString = new TextEncoder().encode(payloadStr);
const encryptedData = await crypto.subtle.encrypt(
{
name: 'RSA-OAEP',
},
cryptoPublicKey,
encodedDataString,
);
const encryptedDatab64 = arrayBufferToBase64(encryptedData);
return encryptedDatab64;
}
async function main() {
try {
const credsPublicKey = await getExchangeAccountsCredentialsPublicKey();
let credentials_payload = {
"apiKey": EXCHANGE_API_KEY,
"secret": EXCHANGE_API_SECRET,
"tenantId": credsPublicKey.tenantId,
};
const encryptedCredentials = await encryptCredentials(credsPublicKey.publicKey, credentials_payload);
const request: ExchangeAccountsApiAddExchangeAccountRequest = {
addExchangeAccountRequest: {
name: "My BIT account",
exchangeType: "BIT",
creds: encryptedCredentials,
key: EXCHANGE_API_KEY
}
};
const addExchangeResponse = await fireblocks.exchangeAccounts.addExchangeAccount(request);
console.log(addExchangeResponse);
} catch (e) {
console.log(e)
}
}
(async () => {
await main();
})();
```
### Note:
Make sure you're using the correct value for the API base URL for your environment:
* `BasePath.US` - for production workspaces
* `BasePath.Sandbox` - for sandbox workspaces\`
# API Communication
Source: https://developers.fireblocks.com/docs/api-communication
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
### Not familiar with the API user creation and authentication?
Visit the links below to understand how each process works:
* [API user creation](/docs/quickstart#api-user-creation)
* [API user authentication](/reference/signing-a-request-jwt-structure)
# Overview
API communication between the customer backend and the Fireblocks platform occurs over HTTP (REST). Authentication uses API users and JSON Web Tokens (JWTs) signed for each request.
**Note**: For end users accessing via the app with the Embedded Wallet SDK, authentication uses IDP tokens and pre-configured SSO OAuth, where the NCW Signer API user is configured.
# API roles
The Fireblocks EW feature requires two API roles: **EW Admin** and **EW Signer**.
## EW Admin
This role is used for administrative workspace operations, such as disable/enable a wallet.
## EW Signer
This role is used for specific wallet operations, such as creating a transaction from a specific end user wallet.
There are two ways in which this API user is used:
* Implicitly, as part of the EW SDK using the OAuth pre-configured configuration.
* Explicitly, similar to the NCW Admin API user (using signed JWT)
# Role permissions
The table below lists the different operations that can be executed by the EW Admin & EW Signer API users.
| API User Role/ Operation | EW Admin | EW Signer |
| ------------------------------------------------- | -------- | --------- |
| Create new EW Everywhere | ✅ | ❌ |
| Create new account under a specific EW Everywhere | ✅ | ✅ |
| Enable/Disable EW Everywhere | ✅ | ❌ |
| Get deposit address information | ✅ | ✅ |
| Create transaction from EW Everywhere | ❌ | ✅ |
| Get transaction fee information | ✅ | ✅ |
| Cancel transaction | ❌ | ✅ |
| Decline transfer | ❌ | ✅ |
| Enable/disable a signing device | ❌ | ✅ |
| Invoke RPC (relayed from the EW Everywhere SDK) | ❌ | ✅ |
| Add asset to an account under an EW Everywhere | ❌ | ✅ |
| Get public key | ✅ | ❌ |
| Delete algorithm | ✅ | ❌ |
# Associate End Clients
Source: https://developers.fireblocks.com/docs/associating-end-clients-with-transactions
# Overview
You may want to or be required to add end-client identification information to vault accounts and wallets. Depending on the purpose, you can use different endpoints and parameters to do this.
# Internal or auditing identification purposes
## Vault accounts
When an end client owns (or will own) all the wallets and addresses inside a vault account, call one of the following endpoints:
* [Create a new vault account](/reference/createvaultaccount) (for new vault accounts)
* [Rename a vault account](/api-reference/vaults/rename-a-vault-account) (for existing vault accounts)
Then, use the `name` parameter to enter their identification information (e.g., "Customer\_12345\_Vault"). This propagates the information to every transaction that uses that vault account.
### Please make sure to not pass any PII data!
## Wallets
When an end client owns (or will own) only one or only a few wallets inside a vault account containing many other wallets, call one of the following endpoints:
* [Create an internal wallet](/reference/createinternalwallet) (for new internal wallets)
* [Create an external wallet](/reference/createexternalwallet) (for new external wallets)
Then, use the `name` parameter to enter their identification information (e.g., "Customer\_12345\_Wallet"). This propagates the information to every transaction that uses that wallet.
### Note
Wallets cannot be renamed, so you must create new wallets for existing end client wallets.
## Deposit Addresses
When an end client owns (or will own) only one or only a few deposit addresses inside a wallet containing many other addresses, call one of the following endpoints:
* [Create a new asset deposit address](/reference/createvaultaccountassetaddress) (for new deposit addresses)
* [Update address description](/reference/updatevaultaccountassetaddress) (for existing deposit addresses)
Then, use the `description` parameter to enter their identification information (e.g., "Customer\_12345\_Address"). This propagates the information to every transaction that uses that deposit address.
# AML/CFT identification purposes
### Warning
The `customerRefId` parameter should be used *only* for this purpose, as AML providers use it to associate the owner of funds with transactions.
## Vault accounts
When an end client owns (or will own) all the wallets and addresses inside a vault account, call one of the following endpoints:
* [Create a new vault account](/reference/createvaultaccount) (for new vault accounts)
* [Set an AML/KYT customer reference ID for a vault account](/reference/setvaultaccountcustomerrefid) (for existing vault accounts)
Then, use the `customerRefId` parameter to enter their identification information (e.g., "Customer\_12345\_Vault"). This propagates the vault account's name, the wallet address, the asset name, and the end client’s information to every transaction that uses that vault account.
## Wallets
When an end client owns (or will own) only one or only a few wallets inside a vault account containing many other wallets, call one of the following endpoints:
* [Create an internal wallet](/reference/createinternalwallet) (for new internal wallets)
* [Create an external wallet](/reference/createexternalwallet) (for new external wallets)
* [Set an AML/KYT customer reference ID for an internal wallet](/reference/setcustomerrefidforinternalwallet) (for existing internal wallets)
* [Set an AML/KYT customer reference ID for an external wallet](/reference/setexternalwalletcustomerrefid) (for existing external wallets)
Then, use the `customerRefId` parameter to enter their identification information (e.g., "Customer\_12345\_Wallet"). This propagates the name of the vault account containing the wallet, the wallet address, the asset name, and the end client’s information to every transaction that uses that wallet.
## Deposit Addresses
When an end client owns (or will own) only one or only a few deposit addresses inside a wallet containing many other addresses, call one of the following endpoints:
* [Create a new asset deposit address](/reference/createvaultaccountassetaddress) (for new deposit addresses)
* [Assign AML customer reference ID](/reference/post_vault-accounts-vaultaccountid-assetid-addresses-addressid-set-customer-ref-id) (for existing deposit addresses)
Then, use the `customerRefId` parameter to enter their identification information (e.g., "Customer\_12345\_Address"). This propagates the name of the vault account containing the wallet, the wallet address, the description of the deposit address, the asset name, and the end client's information to every transaction that uses that deposit address.
# AWS Nitro API Co-signer Architecture
Source: https://developers.fireblocks.com/docs/aws-nitro-api-co-signer
### Learn how to install AWS Nitro Co-signer in the [following guide](/reference/install-api-cosigner-aws)
## AWS resources used by the Co-signer
The Fireblocks AWS Nitro API Co-signer leverages AWS Nitro Hypervisor technology and attestation mechanisms. It utilizes the following AWS resources:
* **EC2 Instance**: Nitro-capable VM, through which the enclave operates.
* **S3 Bucket**: used as the Co-signer's persistent storage and holds the encrypted database of the Co-signer.
* **KMS Customer Managed Key**: used to securely protect the Co-signer's MPC keyshares, which are stored in the Co-signer's persistent storage within an S3 bucket.
* **IAM Role**: used to tie everything together by granting only the necessary permissions to the specific resources.
### **Important**: Allocate a separate set of resources for each Co-signer to prevent conflicts and ensure isolation, enhancing security.
This is illustrated in the block diagram below:
## Co-signer attestation
Fireblocks uses Nitro’s Platform Configuration Register (PCR) as an attestation mechanism to ensure the enclave image file that is accessing the resources at runtime is signed by Fireblocks.
In AWS, **PCR8 (Platform Configuration Register 8)** is a part of the **Trusted Platform Module (TPM)** ecosystem and is specific to environments involving Nitro Enclaves or other secure computing contexts.
In the AWS Nitro Co-signer, **PCR8** measures specific details about the Co-signer during the secure boot process. It ensures setup integrity by validating Fireblocks' enclave image signature when accessing the Customer Managed Key (CMK).
## Secure Co-signer database encryption scheme
The following process is implemented to build and secure the Co-signer's database:
1. The user creates and configures a symmetric Customer Managed Key (CMK) in the KMS.
2. The Co-signer, upon initialization, asks KMS to generate an additional AES 128-bit CBC key: `FBKS-DB-Key`
3. The Co-signer initializes its encrypted database using the key `FBKS-DB-KEY`
4. The Co-signer encrypts `FBKS-DB-KEY` using the CMK.
5. The Co-signer saves its encrypted database and the encrypted form of `FBKS-DB-KEY` in the S3 bucket, serving as its persistent storage
6. The access to KMS, including the CMK, is restricted using a Fireblocks enclave image attestation signature and the IAM role and policies that were created by the user.
This is illustrated in the block diagram below:
## AWS Nitro installation package
The installation package contains an Enclave Image File (EIF) and a set of installation scripts. The EIF is built based on the image containing the common API Co-signer code and the AWS Nitro enclave functionality. This image is scanned for known vulnerabilities, and only then does the build process continue based on the AWS build procedure.
# Backup and Recovery Overview
Source: https://developers.fireblocks.com/docs/backup-and-recovery-overview
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
The Fireblocks Embedded Wallet (EW) provides a backup and recovery mechanism to ensure that users can recover their keys even if their EW device is lost or damaged.
The Fireblocks EW feature allows you to create a backup of the end-user key share on the device. When initiating the backup, the customer application will generate an encryption key. The key share is then encrypted using this key and stored on Fireblocks servers. The encryption key can then be backed up in various ways, such as placing it on the user's iCloud or Google Drive using end-user authentication or simply downloading it to a file.
Upon recovery, the encrypted key share is fetched from Fireblocks' servers, and if the end-user provides the correct encryption key, the recovery will be successful.
# Key Backup Configuration
Key backups are required by default in Fireblocks workspaces. If you want to make them optional, submit a request to Fireblocks Support (requires a Fireblocks Help Center login).
Please note that when key backups are not required, end users can start using their wallets without a backup (but can create one later). Fireblocks highly recommends users create backups since it helps ensure they can access their funds.
# Boost Transactions
Source: https://developers.fireblocks.com/docs/boost-transactions-1
# Overview
ETH transactions can get stuck due to insufficient gas fees or sudden spikes in network congestion. When the gas fee provided is too low compared to the current network demand, validators may prioritize other transactions with higher fees, causing your transaction to remain unprocessed in the mempool.
This can lead to delays and a backlog of subsequent transactions, especially if they depend on the completion of the stuck transaction. Managing gas fees and monitoring network conditions are crucial to prevent transactions from getting stuck.
Replace By Fee (RBF) and Child Pays For Parent (CPFP) are mechanisms used to expedite stuck transactions on blockchain networks.
* **RBF** - commonly used in Ethereum and other EVM-based networks, allows a sender to replace a pending transaction with a new one that has a higher gas fee, increasing the likelihood of it being processed promptly.
* **Drop EVM transaction** - uses RBF to replace the original transaction with a new transaction of 0 value, and a destination identical to the source, effectively canceling the transfer.
* **CPFP** - primarily used in Bitcoin, involves creating a new transaction (the child) that pays a higher fee, incentivizing miners to also confirm the original stuck transaction (the parent) due to the combined higher fee.
Both RBF and CPFP methods aim to prioritize the processing of transactions that might otherwise remain stuck due to low fees or network congestion.
# RBF and CPFP in Fireblocks
Fireblocks customers can boost or drop their stuck transactions using the following methods:
* Clicking the "Boost" icon on the Transaction card in the Fireblocks Web Console. For more information on the process and the availability of the boosting operation, refer to this [guide](https://support.fireblocks.io/hc/en-us/articles/360018600160-Boost-or-drop-a-stuck-EVM-based-transaction).
* Using the Fireblocks API for the following scenarios:
* [Perform RBF for a stuck EVM transaction](/reference/boost-transactions#replace-by-fee-rbf-for-evm-networks)
* [Drop a stuck EVM transaction](/reference/boost-transactions#drop-evm-transaction)
* [Perform CPFP for a stuck BTC transaction](/reference/boost-transactions#cpfp-child-pays-for-parent-for-btc)
# Building with AI
Source: https://developers.fireblocks.com/docs/building-with-ai
AI-assisted development is the default way to build on Fireblocks. This page explains the tools available and when to use each.
Building on Fireblocks is designed to work with AI agents. Start by connecting your agent to the docs — the Documentation MCP is the one step that applies regardless of how you build. From there, use whichever combination of SDKs, CLI, and platform tools fits your workflow.
The quickstart walks you through connecting your agent to the docs, setting up API authentication, and making your first Fireblocks API call — with SDK and CLI paths both covered.
## Developer tools
These are the tools that matter most when you're writing code against the Fireblocks API.
### Fireblocks Documentation MCP
**What it is:** An MCP server that gives your coding agent (Cursor, Claude Code, Codex, or any MCP-compatible tool) real-time access to Fireblocks developer documentation. Your agent can search, read, and cross-reference docs without leaving your IDE.
**When to use it:** Always. Install this before anything else. It keeps your agent grounded in canonical, up-to-date documentation rather than training-data guesses — especially important for Fireblocks, where API behavior, authentication, and object models have specific details that general LLM training may not reflect accurately.
**How to use it:**
```bash theme={"system"}
claude mcp add --transport http fireblocks-docs https://www.developers.fireblocks.com/mcp
```
[Click here to add the Fireblocks Documentation MCP to Cursor.](https://cursor.com/en/install-mcp?name=fireblocks\&config=eyJ1cmwiOiJodHRwczovL2RldmVsb3BlcnMuZmlyZWJsb2Nrcy5jb20vZG9jcy9tY3AifQ==)
If the link doesn't open, add it manually from Cursor's MCP settings using the endpoint: `https://www.developers.fireblocks.com/mcp`
```bash theme={"system"}
codex mcp add --transport http fireblocks-docs https://www.developers.fireblocks.com/mcp
```
Point any MCP-compatible client at the Fireblocks Documentation MCP endpoint:
`https://www.developers.fireblocks.com/mcp`
Once installed, your agent can answer questions like:
* *What fields does a vault account have?*
* *How does Fireblocks JWT signing work?*
* *What webhooks fire when a transaction is confirmed?*
**Without an MCP client:** Every page on this site has a **Copy Page** button — use it to paste a page directly into Claude, ChatGPT, or any other LLM. You can also open the page URL in Claude's Projects or any tool with web access. The MCP handles search and freshness automatically, but copying a specific page works well when you need focused context on a single topic.
### llms.txt and llms-full.txt
Fireblocks publishes documentation in the [llms.txt](https://llmstxt.org/) format for tools and workflows that expect a static, crawlable text bundle:
* **[llms.txt](https://www.developers.fireblocks.com/llms.txt)** — a compact index and entry point to the docs.
* **[llms-full.txt](https://www.developers.fireblocks.com/llms-full.txt)** — a broader aggregate of documentation content for setups that load one large file.
Use these when you cannot run an MCP client, need an offline or snapshot ingest for a custom index, or are wiring a tool that only understands llms.txt URLs.
For everyday coding with an AI agent, the **Fireblocks Documentation MCP** (above) is the best option: it searches and retrieves the right pages on demand, reflects the current site, and avoids pulling huge static exports into context. Treat `llms.txt` / `llms-full.txt` as a fallback or supplement, not a replacement for the docs MCP.
***
### Fireblocks CLI
**What it is:** An agent-first command-line tool that exposes every Fireblocks API operation as a typed, JWT-signed command. The `help-index` command returns a compact JSON index of all commands sized to fit in an LLM context window.
**When to use it:** When you want to explore your workspace, prototype API calls, run scripts or CI jobs, or let your agent propose exact commands you can review before running. The CLI is the fastest path from "I want to do X" to a working, reviewable command — use it alongside an SDK in production, or on its own for operator and agent workflows.
**How to use it:**
```bash theme={"system"}
npm install -g @fireblocks/fireblocks-cli
```
```bash theme={"system"}
brew tap fireblocks/fireblocks-cli
brew install fireblocks-cli
```
Download a pre-built binary from [GitHub Releases](https://github.com/fireblocks/fireblocks-cli/releases), or install via yarn/pnpm. See [Fireblocks CLI](/docs/fireblocks-cli) for all options.
Connect it to your workspace, then verify:
```bash theme={"system"}
fireblocks configure
fireblocks whoami
```
Key agent-friendly features:
* `fireblocks help-index` — compact JSON command catalogue for LLM context
* `--dry-run` — preview a request before it executes
* `--no-confirm` — skip interactive prompts in automated pipelines
* Structured JSON errors on stderr with distinct exit codes
For any operation that creates or modifies data, ask your agent to show the `fireblocks` command first and use `--dry-run` where available. Review before running.
Full reference: [Fireblocks CLI](/docs/fireblocks-cli)
***
## Platform AI tools
These tools extend AI capabilities to the Fireblocks Console and broader operations workflows.
### Fireblocks AI Link
**What it is:** An MCP server that connects your AI tools (Claude, ChatGPT, Cursor) directly to your Fireblocks workspace data. Where the Documentation MCP gives your agent access to docs, AI Link gives it access to your live Fireblocks environment — balances, transactions, addresses, and workspace state.
**When to use it:** When you want to query live workspace data in natural language, build dashboards, or run operational queries without writing API code. AI Link is oriented towards operations and treasury workflows rather than code generation.
**Two deployment modes:**
| Mode | Capabilities | Deployment | Best for |
| -------------- | --------------------------- | ------------------------ | ------------------------------------------------------------- |
| **Remote MCP** | Read-only | Fireblocks-hosted | Connecting to ChatGPT, Claude, or other external AI platforms |
| **Local MCP** | Read + write (transactions) | Self-hosted, open-source | Custom workflows with full data control |
Example queries AI Link enables:
* *What percentage of my holdings are in stablecoins?*
* *Summarize fees paid across all vaults this month.*
* *What is the current balance of vault account 42?*
Available via [Fireblocks Labs](https://www.fireblocks.com/fireblocks-labs/) for early access. The Local MCP server is open-source on GitHub.
***
### Fireblocks Genie
**What it is:** A native AI assistant built directly into the Fireblocks Console — no external integrations required. Genie answers treasury and operations questions in real time using your workspace data, and can explain complex DeFi contract calls in plain language via the AI Transaction Summary feature.
**When to use it:** When you're in the Console and want fast answers about your workspace state, holdings, or a specific transaction — without switching context to another tool. Genie is not a developer tool; it's built for treasury, finance, and operations teams who work in the Console.
**Capabilities:**
* Answer natural-language questions about balances, fees, and holdings
* AI Transaction Summary: explains complex smart contract calls in human-readable terms
* Respects your workspace policies, approval quorums, and user roles
Available via [Fireblocks Labs](https://www.fireblocks.com/fireblocks-labs/) for early access.
***
## How the tools fit together
| Tool | Primary user | Primary context | Needs live workspace data |
| --------------------- | --------------------- | ------------------ | ---------------------------- |
| **Documentation MCP** | Developer / agent | IDE / coding agent | No — reads docs only |
| **Fireblocks CLI** | Developer / agent | Terminal / scripts | Yes — calls the API |
| **AI Link** | Developer / operator | External AI tools | Yes — reads/writes workspace |
| **Genie** | Operations / treasury | Fireblocks Console | Yes — console-native |
The **Documentation MCP** is the one tool that applies to every workflow — install it first. After that, use the SDK, CLI, or both depending on what you're building. Add AI Link when you want natural-language access to live workspace data from your own AI tools. Genie is available in the Console for non-developer users on your team.
# Fireblocks Key Features & Capabilities
Source: https://developers.fireblocks.com/docs/capabilities
### Hot, warm, and cold MPC-CMP wallets
Fireblocks wallets can be hot, warm, or cold. What separates these types of wallets is where the third MPC key share is held, and how transaction approvals are conducted.
* With a **hot wallet**, the third MPC key share is held by an API user on an API co-signer, and transaction approvals can be automated.
* With a **warm wallet**, the third MPC key share is held on your internet-connected mobile device, and approvals occur on the Fireblocks mobile app.
* With a **cold wallet**, the third MPC key share is held on your air-gapped (offline) mobile device. Approvals for transactions require bi-directional QR code scanning.
### Workspace compatibility
A Fireblocks workspace can be hot & warm, or cold wallet-only, but not both.
### Workspaces
The **Fireblocks workspace** is a unique feature of the Fireblocks platform with a broad range of capabilities that allows you to manage your various accounts, digital assets, transactions, and more.
Each workspace is a unique BIP32-HD wallet structure with unique security and transaction policies.
[Learn more about different types of Fireblocks workspace environments.](doc:workspace-environments)
### Role-based access control
Fireblocks has extensive role-based access control capabilities for various user roles. These access roles grant them permissions related to:
* Parts of the platform they can access
* Types of actions they can perform
* MPC key shares that they hold and can use to sign transactions
These roles can range from admin-level users like 'Owner' of the workspace, to a read-only 'Viewer’. An API user can be assigned any user role (except 'Owner').
[Learn more about each role's access and capabilities.](doc:quickstart#creating-an-api-user)
### Admin Quorum
The **Admin Quorum**is the minimum number of workspace admins required to approve sensitive workspace changes, such as adding or removing users, adding whitelisted addresses, or approving network connections. This is set via an Admin Quorum threshold.
If an admin attempts to perform malicious actions, such as attempting to steal funds via a personal wallet, the multiple approvals required by the admin quorum prevent and mitigate damage. This would work the same for an admin that has their account compromised.
[Learn more about adjusting your workspace's Admin Quorum threshold.](https://support.fireblocks.io/hc/en-us/articles/360017665119-Admin-Quorum)
### Accounts
**Accounts** compile all types of accounts that Fireblocks supports, including; vault accounts, exchange accounts, and fiat accounts.
* A**Vault account** is a unique on-chain wallet, with your private key secured by our MPC-CMP architecture, that enables you to securely store and transfer your digital assets.
* A **Exchange account** allows you to leverage your exchange's API credentials to securely transfer assets between exchanges and other Fireblocks accounts.
* A **Fiat account** enables you to transfer fiat to any other account within your Fireblocks workspace or network connections that support that specific fiat provider.
### Vaults
The Fireblocks Vault is your secure MPC-CMP solution for wallet and address management. The Vault allows you to create and manage multiple vault accounts, which contain your asset wallets.
Depending on the asset type, you may or may not be able to have multiple deposit addresses or accounts within a single vault account.
[Learn how to create vaults and wallets using the Fireblocks API.](/docs/create-direct-custody-wallets)
### Assets
Asset wallets are used to manage internal deposit addresses for different asset types. Each asset wallet contains at least one deposit address for its asset type. Fireblocks supports over 1,200 assets and our asset support is continuously growing.
[Learn how to return a list of supported assets using the Fireblocks API.](/docs/list-supported-assets-1)
### Policies
Policies are a set of rules that set the limits and boundaries of the transactions in your Fireblocks workspace.
With Policies, you control who can move funds, how much can be transferred in a single transaction or a certain time period, and how transactions are authorized.
Policy rules can be applied to virtually any parameter within a transaction, including smart contract-specific transactions such as deploying, upgrading, and performing ongoing operations.
[Learn how to set up rules for your Policies.](/docs/set-transaction-authorization-policy)
### Transactions API
All transactions are routed through the [Create a new transaction](ref:post_transactions) API call. Users can only issue transactions based on their access roles and the workspace’s Policy settings. This includes both console and API users.
When issuing a transaction through this endpoint, the `OPERATION` parameter specifies what type of transaction this may be. It could be a generic transfer, a token mint or burn, a contract call, a typed message, or a raw message.
[Learn how to build a transaction using the Fireblocks API.](/reference/create-transactions)
### Whitelisted addresses
**Whitelisted addresses** are deposit addresses that exist outside of your Fireblocks Vault. You can perform transactions from your workspace by whitelisting an address for any supported blockchain.
Whitelisted addresses (also called "wallets") can be categorized as:
* **Internal wallet** - a deposit address existing inside your organization.
* **External wallet** - a deposit address existing outside your organization.
* **Contract wallet** - a deposit address of an on-chain smart contract.
[Learn to whitelist new addresses for transactions and deposits.](/docs/whitelist-addresses)
### Fireblocks Network
The Fireblocks Network is a settlement workflow allowing you to quickly transfer with your network counterparties without the need to manually whitelist their addresses.
Streamline settlement using the Fireblocks Network by automatically authenticating addresses with your network counterparties while automatically rotating secure addresses for supported assets. It also maps transactions to counterparties for accurate reporting.
[Learn how to create and manage network connections using the Fireblocks API.](/docs/connect-to-the-fireblocks-network)
### Tokenization
Deploy, manage, mint, and burn custom tokenized assets on-chain. Enforce governance and rules for who is able to perform sensitive operations such as minting new tokens.
[Learn how to deploy, manage, mint, and burn tokenized assets using the Fireblocks API.](/docs/issue-new-tokens)
### Web3 / DeFi access
Fireblocks lets you securely connect to and operate seamlessly within the Web3 and DeFi ecosystem.
* Connect easily to Web3 dApps using our WalletConnect integration or browser extension.
* Interact directly and programmatically with smart contracts using our smart contract API.
[Learn how to connect to Web3 dApps using our WalletConnect integration.](https://support.fireblocks.io/hc/en-us/articles/5403817784732-Connecting-to-Web3-using-WalletConnect)
### Securely develop and operate smart contracts
Securely develop, deploy, and operate your on-chain smart contracts using Fireblocks' industry-leading security layers.
Provide granular role-based access control for managing which developer is allowed to deploy smart contracts, perform upgrades, or call sensitive smart contracts operations, such as pausing or updating contract data.
[Learn how to deploy and operate smart contracts using the Fireblocks API.](/docs/interact-with-smart-contracts)
### Fireblocks Gas Station
The *FireblocksGas Station* service automates gas replenishment for token transaction fees on EVM-based networks such as Ethereum, BNB Chain, and others. This eliminates monitoring and manually transferring funds to these vault accounts to cover future transaction fees.
[Learn how to set up your Gas Station using the Fireblocks API.](/docs/work-with-gas-station)
### Transaction screening (AML/KYT)
*Transaction screening* allows you to automate real-time monitoring of your crypto transactions in order to ensure compliance with Anti-Money Laundering/Counter Financing of Terrorism (AML/CFT) regulations, prevent interactions with sanctioned entities and identify customer behavior.
[Learn more about our AML screening engine and the KYT capabilities of our Chainalysis and Elliptic integrations.](/docs/define-aml-policies)
# CLI Authentication
Source: https://developers.fireblocks.com/docs/cli-authentication
Configure credentials for the Fireblocks CLI.
The CLI authenticates to the Fireblocks API using the same JWT-signing mechanism as the official SDKs: each request is signed with your RSA private key and identified by your API key.
## Prerequisites
You need:
* A **Fireblocks API key** — obtained from the Fireblocks Console under **Developer Center > API Users**
* An **RSA private key** — the `.key` file generated when creating the API user
See [Quickstart](/docs/quickstart) for instructions on creating an API user and generating a key pair.
## Credential Resolution Order
The CLI resolves credentials in priority order:
1. **CLI flags** — `--api-key` and `--secret-key` passed directly on the command line
2. **Environment variables** — `FIREBLOCKS_API_KEY` and `FIREBLOCKS_SECRET_KEY` (or `FIREBLOCKS_SECRET_KEY_PATH`)
3. **Config file profile** — stored in `~/.config/fireblocks/config.json`
If no credentials are found, the CLI exits with an error and instructions for how to configure them.
## Interactive Setup
The easiest way to configure credentials is the interactive `configure` command:
```bash theme={"system"}
fireblocks configure
```
This prompts for your API key, the path to your private key file, and optionally a base URL override. Credentials are written to `~/.config/fireblocks/config.json` with file permissions `0600`.
To configure a named profile:
```bash theme={"system"}
fireblocks configure --profile staging
```
To switch the default profile:
```bash theme={"system"}
fireblocks configure --set-default=staging
```
### Config File Format
```json theme={"system"}
{
"defaultProfile": "default",
"profiles": {
"default": {
"apiKey": "your-api-key",
"privateKeyPath": "/path/to/fireblocks_secret.key"
},
"staging": {
"apiKey": "staging-api-key",
"privateKeyPath": "/path/to/staging_secret.key",
"baseUrl": "https://sandbox-api.fireblocks.io"
}
}
}
```
## Environment Variables
For CI/CD pipelines and non-interactive environments, set credentials as environment variables:
| Variable | Description |
| ---------------------------- | -------------------------------------------------------------------------- |
| `FIREBLOCKS_API_KEY` | Your Fireblocks API key |
| `FIREBLOCKS_SECRET_KEY` | RSA private key — inline PEM content or a file path |
| `FIREBLOCKS_SECRET_KEY_PATH` | File path to your RSA private key (alternative to `FIREBLOCKS_SECRET_KEY`) |
| `FIREBLOCKS_BASE_URL` | Base URL override (default: `https://api.fireblocks.io`) |
```bash theme={"system"}
export FIREBLOCKS_API_KEY="your-api-key"
export FIREBLOCKS_SECRET_KEY_PATH="/path/to/fireblocks_secret.key"
fireblocks vaults get-paged-vault-accounts
```
You can also pass inline PEM content directly — useful when pulling key material from a secrets manager:
```bash theme={"system"}
export FIREBLOCKS_SECRET_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAK...
-----END RSA PRIVATE KEY-----"
```
## CLI Flags
Pass credentials directly on the command line to override environment variables and the config file:
```bash theme={"system"}
fireblocks vaults get-paged-vault-accounts \
--api-key "your-api-key" \
--secret-key "/path/to/fireblocks_secret.key"
```
`--secret-key` accepts either a file path or an inline PEM string.
## Multiple Profiles
Use profiles to manage multiple workspaces or environments:
```bash theme={"system"}
# Configure a sandbox profile
fireblocks configure --profile sandbox
# Use the sandbox profile for a command
fireblocks vaults get-paged-vault-accounts --profile sandbox
```
## API Base URL
The default base URL is `https://api.fireblocks.io`. Override it per command, in a profile, or via `FIREBLOCKS_BASE_URL`.
| Environment | Base URL |
| --------------------- | ------------------------------------- |
| US Mainnet / Testnet | `https://api.fireblocks.io` (default) |
| US Sandbox | `https://sandbox-api.fireblocks.io` |
| EU Mainnet / Testnet | `https://eu-api.fireblocks.io` |
| EU2 Mainnet / Testnet | `https://eu2-api.fireblocks.io` |
```bash theme={"system"}
fireblocks vaults get-paged-vault-accounts \
--base-url https://sandbox-api.fireblocks.io
```
## Verify Your Setup
Run `whoami` to confirm credentials are configured correctly and that the API key can authenticate:
```bash theme={"system"}
fireblocks whoami
```
This calls `GET /v1/users/me` and returns the masked API key, base URL, and user details on success.
To preview the resolved auth context without making a network call:
```bash theme={"system"}
fireblocks whoami --dry-run
```
# CLI Usage Guide
Source: https://developers.fireblocks.com/docs/cli-usage
Commands, flags, examples, and error handling for the Fireblocks CLI.
## Command Pattern
Every Fireblocks API operation is available as a command organized under a namespace:
```bash theme={"system"}
fireblocks [flags]
```
Namespaces correspond to Fireblocks API resource groups (e.g. `vaults`, `transactions`, `assets`, `staking`). Examples:
```bash theme={"system"}
fireblocks vaults get-paged-vault-accounts
fireblocks transactions create-transaction --data '...' --no-confirm
fireblocks staking get-chains
```
## Discover Commands
### Full Command Index
```bash theme={"system"}
fireblocks help-index
```
### List Actions in a Namespace
```bash theme={"system"}
fireblocks vaults --help
```
### Show All Flags for a Command
```bash theme={"system"}
fireblocks vaults get-vault-account --help
```
### Preview a Request
Use `--dry-run` on any command to see the exact request that would be sent — without executing it:
```bash theme={"system"}
fireblocks transactions create-transaction \
--data '{"assetId":"BTC","amount":"0.001"}' \
--dry-run
```
Output:
```json theme={"system"}
{
"method": "POST",
"url": "https://api.fireblocks.io/v1/transactions",
"body": { "assetId": "BTC", "amount": "0.001" }
}
```
## Flags
### Path Parameters
OpenAPI path parameters (e.g. `{vaultAccountId}`) become required flags with kebab-case names:
```bash theme={"system"}
# GET /v1/vault/accounts/{vaultAccountId}
fireblocks vaults get-vault-account --vault-account-id 0
```
### Query Parameters
Query parameters become optional flags with the same kebab-case conversion:
```bash theme={"system"}
# GET /v1/vault/accounts/paged?limit=50&namePrefix=hot
fireblocks vaults get-paged-vault-accounts --limit 50 --name-prefix hot
```
### Request Body
Write operations (POST/PUT/PATCH/DELETE) accept a JSON request body via `--data`:
```bash theme={"system"}
fireblocks transactions create-transaction \
--data '{"assetId":"ETH","amount":"0.1","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"VAULT_ACCOUNT","id":"1"}}' \
--no-confirm
```
### Global Flags
These flags are available on every command:
| Flag | Env Var | Description |
| -------------- | ------------------------------------------------------ | ------------------------------------------ |
| `--api-key` | `FIREBLOCKS_API_KEY` | Fireblocks API key |
| `--secret-key` | `FIREBLOCKS_SECRET_KEY` / `FIREBLOCKS_SECRET_KEY_PATH` | RSA private key — PEM content or file path |
| `--base-url` | `FIREBLOCKS_BASE_URL` | Override the API base URL |
| `--profile` | | Use a named credential profile |
| `--dry-run` | | Preview the request without executing it |
| `--no-confirm` | | Skip write-operation confirmation prompts |
| `--debug` | | Log request and response details to stderr |
| `-o, --output` | | Output format: `json` (default) or `yaml` |
## Write Operations
POST, PUT, PATCH, and DELETE commands prompt for confirmation before executing:
```text theme={"system"}
About to execute POST /v1/transactions. Continue? (y/N)
```
Skip the prompt for scripting and automation — either pass `--no-confirm` or pipe stdin from a non-TTY source:
```bash theme={"system"}
fireblocks transactions create-transaction --data '...' --no-confirm
```
### Idempotency Keys
Endpoints that support idempotency accept `--idempotency-key`. Use this for safe retries on write operations to guarantee at-most-once execution:
```bash theme={"system"}
fireblocks transactions create-transaction \
--data '{"assetId":"ETH","amount":"1.0","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"ONE_TIME_ADDRESS","oneTimeAddress":{"address":"0xABC"}}}' \
--idempotency-key "$(uuidgen)" \
--no-confirm
```
## Output
* **stdout** — JSON response data only
* **stderr** — warnings, beta notices, errors, and debug logs
### Debug Logging
Pass `--debug` to log request and response details to stderr:
```bash theme={"system"}
fireblocks vaults get-vault-account --vault-account-id 0 --debug
```
```text theme={"system"}
[DEBUG] GET https://api.fireblocks.io/v1/vault/accounts/0
[DEBUG] Response: 200
[DEBUG] Request-ID: a1b2c3d4-...
```
### Beta Commands
Some commands are marked as beta. They print a warning to stderr before executing:
```text theme={"system"}
Warning: This command is in beta and may change in future releases.
```
This is informational — the command still runs and produces output on stdout.
## Exit Codes
| Code | Meaning | Recovery |
| ---- | ------------------------------------- | ---------------------------------------------------------- |
| `0` | Success | |
| `1` | Client error (400 / 409 / 422) | Check request body or parameters |
| `2` | Usage error (missing or invalid flag) | Check flag names and types |
| `3` | Auth error (401 / 403) | Verify credentials with `fireblocks whoami` |
| `4` | Not found (404) | Verify the resource ID exists |
| `5` | Rate limited (429) | Wait `retry_after` seconds from the error JSON, then retry |
| `6` | Server error (5xx) | Retry after a brief delay |
| `7` | Timeout (30s) | Retry; the timeout is not configurable |
## Error Format
Errors are written as JSON to **stderr**:
```json theme={"system"}
{
"code": 5,
"status": 429,
"message": "Rate limit exceeded",
"request_id": "a1b2c3d4-5678-...",
"retry_after": 30
}
```
`request_id` and `retry_after` are included only when applicable.
## Examples
```bash theme={"system"}
# List vault accounts
fireblocks vaults get-paged-vault-accounts
# Get a specific vault
fireblocks vaults get-vault-account --vault-account-id 0
# Create a transaction
fireblocks transactions create-transaction \
--data '{"assetId":"BTC","amount":"0.001","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"VAULT_ACCOUNT","id":"1"}}' \
--no-confirm
# Idempotent transaction with retry safety
fireblocks transactions create-transaction \
--data '{"assetId":"ETH","amount":"1.0","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"ONE_TIME_ADDRESS","oneTimeAddress":{"address":"0xABC"}}}' \
--idempotency-key "$(uuidgen)" --no-confirm
# Preview a request without executing
fireblocks transactions create-transaction \
--data '{"assetId":"BTC","amount":"0.001"}' \
--dry-run
# Use the sandbox environment
fireblocks vaults get-paged-vault-accounts \
--base-url https://sandbox-api.fireblocks.io
# Debug a failing request
fireblocks vaults get-vault-account --vault-account-id 0 --debug
# Pipe output to jq
fireblocks vaults get-paged-vault-accounts | jq '.accounts[].name'
```
## Shell Autocomplete
The CLI supports tab completion for Bash and Zsh. Run the autocomplete command for your shell and follow the printed setup instructions:
```bash theme={"system"}
# Bash
fireblocks autocomplete bash
# Zsh
fireblocks autocomplete zsh
```
# API Co-signer Security Checklist and Recommended Defense and Monitoring Systems
Source: https://developers.fireblocks.com/docs/co-signer-security-checklist-defense-monitoring
## Co-signer security checklist
* Only **authorized personnel** with **high-level privileges** and **full trust** from your organization may perform the Co-signers installation.
* Use a clean, hardened machine for the Callback Handler server, restricting access exclusively to authorized personnel or service accounts.
* Configure your network rules, cloud resources, and required policies according to the instructions provided in each API Co-signer installation guide.
* Use the Callback Handler to log all approval requests, and consider utilizing it to implement additional programmatic protection logic against malicious withdrawals.
* Create Policy rules that prevent API users from initiating transfers above a specific amount threshold within a certain timeframe, and require additional manual approval. These rules should apply globally to all withdrawals and withdrawals from specific external user wallets.
* Fireblocks advises against disabling Linux UEFI secure boot on your API Co-signer virtual machine, as this goes beyond the security risks introduced by not validating kernel code. We recommend working around any issues you have instead. Using TrendMicro Deep Security agent on Ubuntu 20.04 is one option for secure boot support.
## Co-signer recommended defense and monitoring systems
Although a quorum can be configured to approve requests, and a single MPC key share cannot be used to compromise the system, we recommend adding multiple defense and monitoring systems on Fireblocks API Co-signer instances.
Implementing the recommended defense and monitoring systems can significantly improve the security of the Fireblocks API Co-Signer and reduce the risk of security incidents.
* **Cloud Workload Protection**: A solution that actively monitors the instance running on the Fireblocks AWS API Co-Signer and provides real-time protection against known and unknown threats.
* **Event Detection and Response (EDR)** or **Extended Detection and Response (XDR)**: A solution that actively monitors the instance running on the Fireblocks AWS API Co-Signer and detects and responds to potential security threats in real-time.
* **Security Information and Event Management (SIEM)**: A solution to collect all login attempts to the instance running on the Fireblocks AWS API Co-Signer and provides real-time alerting and reporting on potential security incidents.
* **Privileged Access Management (PAM)**: A solution that actively controls and monitors access to privileged accounts, such as root access to the instance running on the Fireblocks AWS API Co-Signer. A PAM solution can also provide real-time monitoring and alerting on privileged account activity, and enforce security policies, such as password management and least privilege access.
* **Multi-Factor Authentication (MFA)**: An MFA solution can enforce secure authentication and access control to the instance running on the Fireblocks AWS API Co-Signer. An MFA solution can also help prevent unauthorized access and reduce the risk of account compromise.
## AWS Nitro Recommendations
* **EC2 - EBS Volume Encryption**\
Enabling encryption for all EBS volumes is strongly recommended to ensure data security and compliance with best practices. While Fireblocks uses AWS Nitro to safeguard sensitive workloads, customers are advised to configure EBS encryption based on their organization’s compliance requirements and data protection policies. Encryption can be managed seamlessly through AWS Key Management Service (KMS).
* **CloudTrail - Enabling Service for all Regions**\
Fireblocks utilizes an organizational structure incorporating AWS Control Tower, a dedicated log-archive account, and automated processes to ensure comprehensive multi-region coverage for CloudTrail. While this approach is recommended, customers retain the flexibility to operate in single or multi-region modes based on their operational and regulatory requirements. Enabling CloudTrail for all applicable regions is crucial, however, to maintain visibility into account activities and meet audit requirements.
* **S3 - Enabling MFA Delete**\
MFA Delete for S3 buckets is a security best practice for protecting against accidental or unauthorized data deletion. However, Fireblocks does not enforce specific bucket policies, which must align with each customer’s internal security frameworks. Customers are encouraged to evaluate and implement MFA Delete which supports their risk management strategy.
* **S3 - Enabling Versioning**\
S3 versioning provides added protection for data backup and replication. However, Fireblocks' Co-Signer architecture does not require backup or replication of data stored in S3. Customers should assess the need for versioning based on their internal data resilience and disaster recovery policies.
* **S3 - Enabling Access Logging**\
Enabling S3 access logging requires a dedicated logging bucket. Fireblocks recognizes that customers often have centralized logging infrastructures, forwarding logs to SIEM platforms for analysis and archiving. In such cases, enabling S3 access logging may result in redundancy. Customers must ensure their existing logging solutions sufficiently cover S3 access patterns for security monitoring and compliance.
* **VPC - Enabling Subnet Flow Logs**\
While VPC Flow Logs are a valuable tool for monitoring network traffic, they can incur significant costs. Customers should evaluate the necessity of enabling VPC subnet flow logs based on their security posture, budgetary considerations, and compliance obligations. Fireblocks recommends allowing this feature to where granular network activity monitoring is required.
## GCP Confidential Space Recommendations
* **Enabling Cloud Audit Logging**\
Cloud Audit Logging is critical for tracking administrative and data-access operations at the project level. As Fireblocks’ Co-Signer is deployed within customer-managed environments, customers are responsible for enabling and managing Cloud Audit Logging to meet their governance and monitoring needs.
* **Cloud IAM - Service Account with Admin Privileges**\
GCP creates a default administrative service account during the initial setup. To reduce the attack surface and adhere to the principle of least privilege, customers should delete this service account after installation unless explicitly required for operational purposes.
* **Cloud Storage - Enabling Buckets with Versioning**\
Versioning is primarily designed for backup and replication use cases. Fireblocks’ Co-Signer solution does not require this feature, and this configuration has no associated security risk. Customers may enable versioning based on their organizational backup and recovery strategies.
* **VPC Enabling Subnet Flow Logs**\
As with AWS, enabling VPC subnet flow logs in GCP provides visibility into network traffic but may incur additional costs. Customers should consider enabling this feature if their security or compliance policies necessitate detailed network traffic analysis.
* **API Event Monitoring**\
The Fireblocks Co-Signer is hosted within customer environments, and customers are responsible for implementing and managing API event monitoring. Fireblocks recommends monitoring API activity to detect anomalies and ensure compliance with security standards.
* **Firewall Rules**\
GCP creates default firewall rules during project setup, which may not align with security best practices. Customers are strongly encouraged to delete these default rules and implement custom firewall rules that adhere to the principle of least privilege and align with their security requirements.
# Configure Gas Station Values
Source: https://developers.fireblocks.com/docs/configure-gas-station-values
You can configure the Fireblocks Gas Station with a gas threshold, a gas cap, and a maximum gas price for each blockchain network according to its base asset by using the Fireblocks API.
* **Gas threshold (gasThreshold):** The gas threshold represents the minimum balance allowed in the Gas Station account. If the balance is below the minimum gas threshold, the Gas Station fuels the vault account automatically with the set maximum gas cap.
* **Gas cap (gasCap):** The gas cap represents the maximum balance allowed in the Gas Station account.
* **Maximum gas price (maxGasPrice):** The maximum gas price allows you to limit the maximum transaction fee for Gas Station transactions. The funding transaction will be sent in gwei with this maximum value gas price or less. A null value for the maximum gas price means the fee will be paid at any cost, without limitations. If you changed the maximum gas price settings and want to revert to the default settings of null, you can enter an empty string as `""`.
When an incoming token deposit or an outgoing token withdrawal is detected, the Gas Station checks the gas balance of the vault account. If the balance is below the minimum gas threshold, it automatically fuels the vault account with the set maximum gas cap.
### Learn more about Gas Station configuration in the Fireblocks Gas Station [developer guide](/reference/set-the-gas-station-values)
# Connect to Exchanges and Fiat Providers
Source: https://developers.fireblocks.com/docs/connect-to-exchanges-and-fiat-providers
Fireblocks enables clients to connect their own (supported by Fireblocks) exchange and fiat accounts directly within the workspace.
Customers can bring their API credentials from the supported exchange or fiat account and integrate them into the Fireblocks workspace. Once connected, clients can seamlessly transfer funds to and from the connected exchange account via the Fireblocks console or the API.
Additionally, clients can view the balances of their connected exchange accounts and set Policies and automated processes around these accounts, enhancing both control and efficiency in managing their assets.
### Learn more about connecting Exchange or Fiat accounts in the following guides:
1. [Supported Exchange Accounts and configuration guides](https://support.fireblocks.io/hc/en-us/articles/13430566220572-Enabling-withdrawals-from-your-exchange-accounts)
2. [Supported FIAT Accounts and configuration guides](https://support.fireblocks.io/hc/en-us/articles/360018286760-Fiat-accounts)
### Check out the [Exchange Accounts](/reference/getexchangeaccounts) and [Fiat Accounts](/reference/getfiataccounts) management APIs in the Firebocks API Reference
### Check out the Exchange and Fiat Accounts Developer Guide [here](/reference/connect-to-exchanges-fiat-providers)
# Connect to the Fireblocks Network
Source: https://developers.fireblocks.com/docs/connect-to-the-fireblocks-network
The Fireblocks Network is a peer-to-peer, institutional liquidity and transfer network of 1,500+ liquidity providers, lending desks, and trading counterparties. Members can discover, connect, and settle with other Fireblocks Network members quickly, easily, and securely using features available only to Network members.
# Fireblocks Network features
To use Fireblocks Network features with a counterparty, connect to each other on the Network. Whether you prefer to make your Network profile discoverable or not, you can connect with other members in several ways.
Discoverable members show up in searches for connections. You can then request to add them as a connection from the search results. To connect with non-discoverable Network members you need to know their unique Network ID. If your profile is not discoverable, you can still search for other discoverable members and request to connect with them. Both your Admin Quorum as well as your counterparty’s Admin Quorum must approve new Network connections.
When you make transfers on the Fireblocks Network, you benefit from these Network features:
## Automated Address Authentication (AAA)
All Fireblocks Network transfers route through an encrypted tunnel within a secure hardware enclave. With AAA, you never have to store or share deposit addresses in poorly secured and error-prone ways, such as messenger apps or copying and pasting, which means you can:
* **Transfer faster:** Avoid time-consuming processes like manually whitelisting new deposit addresses, sending test transfers, and finding, copying, and pasting deposit addresses to send or receive a digital asset transfer.
* **Prevent errors:** Avoid manual, error-prone processes like tracking and copying and pasting addresses that can cause your assets or your counterparty’s assets to go to the wrong address.
* **Secure transfers:** Prevent Man-in-the-Middle and Address Spoofing attacks, where hackers use malware to replace addresses on infected devices, and intercept and replace addresses while you share them over messenger apps or copy and paste them. With AAA, you don’t need to manually manage or share deposit addresses.
* **Future-proof connections:** With AAA, connected counterparties stay connected even if your deposit address changes. AAA will automatically remap it without resharing or reconnecting.
## Flexible Network Routing
When you add new Network connections, you can define how incoming deposits are routed. You can tailor routing for Network deposits of both crypto and fiat in two ways
* **Route by Network profile:** Send all deposits from connections to your Network profile to a designated vault account, exchange account, or fiat account in your workspace.
* **Route by connection:** Tailor routing per connection. Each connection’s deposits can go to their own specific designated vault account, exchange account, or fiat account.
You can also execute all Flexible Network Routing configuration actions using the Fireblocks API. With maximum flexibility for routing and managing deposit addresses for Network transfers, you can capitalize on more opportunities faster and more easily using the Fireblocks Network.
## Automatic Address Rotation
When you transfer Bitcoin or other UTXO-based tokens with Fireblocks Network connections, your deposit addresses can rotate automatically for every incoming transfer. For certain tokens, a different unique identifier is rotated on every Network transfer instead of rotating addresses.
* For Ripple transfers on the Network, the deposit address stays the same, but the unique XRP tag is rotated every transfer.
* For EOS, Hedera, and Stellar transfers on the Network, the deposit address stays the same, but the unique memo ID is rotated every transfer.
For Network transfers on account-based blockchains like Ethereum, Automatic Address Rotation isn’t supported and there is no other unique identifier. You can transfer account-based assets on the Fireblocks Network. However, you can’t create unique identifiers like a deposit address, tag, or memo ID for each transfer for pseudo-anonymity on the blockchain.
Since Network transfers also use Automated Address Authentication, you don’t have to track or share the new addresses. This enables you to:
* Preserve privacy on the blockchain by preventing your transaction history from being easily discovered by someone searching for a deposit address.
* Avoid errors from manual address rotation, like forgetting to update a connection with your new address or a copy-and-paste error while tracking or sharing.
### Learn how to connect over the Fireblocks Network in the Web Console [here](https://support.fireblocks.io/hc/en-us/articles/6107078528540-Configuring-your-Fireblocks-Network-profile)
### Check out the [Fireblocks Network APIs](/reference/getnetworkconnections) in the Fireblocks API reference
# API Co-signers Architecture Overview
Source: https://developers.fireblocks.com/docs/cosigner-architecture-overview
## How automated MPC signing works
### Overview
Similar to how the MPC-CMP algorithm is used to sign transactions and approve workspace configuration requests via a mobile device, the API Co-signer participates in a multi-signer MPC process. This process involves a set of independent Co-signers operated by Fireblocks, known as Cloud Co-signers, each of which holds a private key share. Refer to [this MPC-CMP article](https://support.fireblocks.io/hc/en-us/articles/6984668676124-MPC-CMP) to learn more about the API Co-signer's role in implementing the Fireblocks MPC signing algorithm.
The Co-signer eliminates the need for manual user input through the Fireblocks mobile application by automatically signing transactions and approving requests. By hosting the Co-signer in your environment and connecting it to your workspace using API users, you can configure the [Policies](https://support.fireblocks.io/hc/en-us/articles/7354983580316-About-the-TAP) to [designate the API user](https://support.fireblocks.io/hc/en-us/articles/7365877039004-Rule-parameters#h_01HGBN9QQ0T42NR8XT4Y96V7YH) that is paired with the Co-signer to automatically sign transactions that meet the criteria defined in the policy.
To automate transaction signing, host the API Co-signer in your environment on a machine or virtual machine (VM) that supports enclaves. Fireblocks API Co-signers operate on Intel SGX, AWS Nitro, or Google Cloud Confidential Spaces enclaves. They can be deployed on major cloud platforms such as Azure, AWS, Google Cloud, IBM Cloud, and Alibaba Cloud, as well as on-premises with Intel SGX-capable servers.
> Fireblocks has fully integrated AWS Nitro Enclave technology. If you are currently using KMS-based AWS API Co-signers, it is recommended to upgrade to the latest Nitro version for enhanced security and performance.
Observe the diagram below, which illustrates the relationship between the customer's API Co-signer, mobile device, API users, and the Fireblocks Cloud Co-signers #1 and #2.
Refer to the articles below for detailed information on the specific architecture of each type of enclaved Co-signer:
* [Intel SGX Co-signer architecture running in Azure, IBM Cloud or Alibaba Cloud](/docs/intel-sgx-api-co-signer)
* [Nitro Co-signer architecture running in AWS](/docs/aws-nitro-api-co-signer)
* [Confidential Space Co-signer architecture running in Google Cloud](/docs/gcp-confidential-space-api-co-signer)
### Using API users to connect the Co-signer to your workspace
To connect a new or existing Co-signer to your workspace, pair it with an API user from the workspace. Existing Co-signers are typically associated with another workspace within your organization.
Pairing the Co-signer is performed using a JWT-encoded Pairing Token obtained from the Console for a specific API user. This token is used during Co-signer installation to pair the initial API key, enabling communication with Fireblocks' SaaS. The Co-signer is identified exclusively by the workspace and the API user used to establish the connection.
The pairing process for the first API user requires admin-level access to the Fireblocks Console and root access to the Co-signer’s VM. During this process, you will provide the Co-signer with a pairing token linked to the API user, enabling the platform to recognize the Co-signer and associate it with the Workspace.
You can pair multiple API users to a single Co-signer. Additionally, API users from different Workspaces can be paired with the same API Co-signer, except when using the GCP Confidential Space Co-signer.
### Connecting your business logic to the Co-signer
You can optionally connect your business logic to the Co-signer through a feature called a Callback Handler, configured per API user. The Callback Handler is an HTTPS server that receives requests from the Co-signer at a designated endpoint whenever a transaction signing or configuration approval is triggered for an API user. The Callback Handler responds with an action, such as approving or denying the request. If no Callback Handler is configured, the Co-signer will automatically sign or approve all requests for that API user.
Within a single Co-signer, some API users can operate with a configured Callback Handler, while others can function without it. When configuring a Callback Handler for a paired API user, you specify the URL of the Callback Handler server and select a secure communication method to establish a secure channel.
Refer to [Setup API Co-signer Callback Handler](/docs/create-api-co-signer-callback-handler) to learn more about it.
### Callback best practices
When a signing or authorization request reaches the API Co-Signer, a callback is invoked with the transaction details. We recommend closely monitoring this communication to ensure the callback responds quickly and reliably, as MPC signing will not begin until the callback approves the request.
## Installing an API Co-signer
### Available API Co-signer types
Fireblocks provides multiple deployment options for API Co-signers, available in both cloud environments and on-premises, in regions that meet the necessary enclave technology requirements. These deployment options leverage various enclave technologies to safeguard your MPC key shares, allowing you to select the solution that aligns best with your production environment requirements.
For detailed step-by-step installation guides for each Co-signer type, refer to the articles below:
* [Installing an SGX API Co-signer in Azure](/reference/install-api-cosigner-azure)
* [Installing an SGX API Co-signer via Azure Marketplace](/reference/install-api-cosigner-azure-marketplace)
* [Installing an SGX API Co-signer in IBM Cloud](/reference/install-api-cosigner-ibm)
* [Installing an SGX API Co-signer in Alibaba Cloud](/reference/install-api-cosigner-alibaba)
* [Installing an SGX API Co-signer on-prem](/reference/install-api-cosigner-onprem)
* [Installing a Nitro API Co-signer in AWS](/reference/install-api-cosigner-aws)
* [Installing a Confidential Space API Co-signer in Google Cloud](/reference/install-api-cosigner-gcp)
### High-throughput workspaces
For high-throughput workspaces, we recommend setting up more than one API Co-Signer. This setup enables both high availability and load balancing between Co-Signers, allowing for higher overall throughput.
The required number of Co-Signers is determined by the number of in-flight transactions in the signing phase. As a rule of thumb, maintain one Co-Signer (with a single vCPU) per every 2.5 TPS.
**Learn more**
* [Configuring Multiple API Co-signers in High Availability](/docs/multiple-cosigners-high-availability)
* [API Co-signers Architecture Overview](/reference/api-cosigner-installation-flow)
### Host type recommendations
We recommend using at least a **Standard\_D4\_v3** instance on Azure. AWS and GCP instance recommendations are TBD. In addition, we recommend using Co-signer **version 3.7.1 or newer**.
The table below summarizes key considerations per cloud provider:
| Provider | Key Considerations |
| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Azure (SGX-based)** | Provides hardware security at the highest security level, relying only on Fireblocks and Intel. Because SGX is CPU-based, it has performance limitations including reduced speed, limited memory, and a fixed number of threads. As a result, it is the slowest option. |
| **AWS Nitro** | Requires trust in AWS for both hardware and security. This is still a confidential computing solution, but the cloud provider is part of the threat model. AWS is a highly reputable, publicly traded company with strong engineering practices. |
| **GCP** | Recommended only if you are required to use Google Cloud. This version has the fewest deployments and the least field experience. |
**Best practices**
* For **maximum security:** select Azure + SGX
* For **best performance:** select AWS + Nitro
### Available enclave types
Learn more about the enclave technologies Fireblocks uses by referring to the following resources:
* [Microsoft Azure SGX Enclave-capable Confidential Compute VM](https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-computing-enclaves)
* On-Premise [Intel SGX-enabled Processors](https://www.intel.com/content/www/us/en/architecture-and-technology/software-guard-extensions-processors.html)
* [AWS Nitro Enclave-capable EC2 instance](https://aws.amazon.com/ec2/nitro/nitro-enclaves/)
* [Google Cloud Confidential Space workload container](https://cloud.google.com/confidential-computing/confidential-space/docs/confidential-space-overview)
* [IBM Cloud Bare Metal Servers SGX-capable machine](https://cloud.ibm.com/docs/bare-metal?topic=bare-metal-bm-server-provision-sgx)
* [Alibaba Cloud Intel SGX-capable Elastic Compute Service (ECS) instance](https://www.alibabacloud.com/help/en/ecs/user-guide/build-an-sgx-encrypted-computing-environment)
## Configuring your workspace to sign using an API Co-signer
To enable the API Co-signer to participate in MPC signing and configuration change approvals, it must be paired with an API user from your workspace. Once the pairing process is completed successfully, a unique set of MPC key shares and workspace configuration keys is generated for the API user. These keys are securely stored within your Co-signer and Cloud Co-signers #1 and #2. The key shares facilitate automatic signing for transactions initiated by you.
> Note that it must be an API user with the role of [Signer](https://support.fireblocks.io/hc/en-us/articles/360012832959-User-roles#h_01H9P4D2W1436XZYXESPTQE2J7) or [Admin](https://support.fireblocks.io/hc/en-us/articles/360012832959-User-roles#h_01H9P4D2W138W3F36TX45S8WFX), so it will have MPC key shares and be able to sign.
To activate automatic signing through the Co-signer, configure the [Policies](https://support.fireblocks.io/hc/en-us/articles/7354983580316-About-the-TAP) to [designate the API user](https://support.fireblocks.io/hc/en-us/articles/7365877039004-Rule-parameters#h_01HGBN9QQ0T42NR8XT4Y96V7YH) paired with the Co-signer as the signer. When a transaction you initiate meets the criteria defined in the policy, it will be automatically signed by the Co-signer associated with the configured API user.
The process of generating and signing a Fireblocks transaction using the Fireblocks REST API, the API Co-signer, and the optional Callback Handler proceeds as follows:
1. A new transaction is initiated using the Fireblocks API and generated on the backend.
2. The transaction is evaluated against your Policies to determine if it is authorized.
3. If an API user paired with the API Co-signer is configured in the Policy as a designated signer, the transaction will be sent to the API Co-signer associated with that API user.
4. The API Co-signer, hosted in your secure environment, polls the Fireblocks SaaS for transactions requiring signing. If a transaction is available, the SaaS immediately provides the transaction details.
5. If a Callback Handler is configured for the API user designated as the signer, the API Co-signer sends a secure approval request to the Callback Handler.
6. If the Callback Handler responds with "approved," the transaction is signed in coordination with Fireblocks' Cloud Co-signers. If the response is "rejected," the transaction is declined. If the Callback Handler does not respond within 30 seconds or returns "retry," the request fails. Refer to [Setup API Co-signer Callback Handler](/docs/create-api-co-signer-callback-handler) to learn more about it.
## Manage the Co-signer's paired API users and Callback Handlers
### Configuring the Co-signer from the Console and Fireblocks API
Once the Co-signer is connected to the workspace, it can be managed through the [Co-signers Management tab](https://support.fireblocks.io/hc/en-us/articles/14492251068060-The-Co-signer-management-tab) located in the **Developer Center** of the Fireblocks Console.
You can also use the [Co-signer APIs (beta)](https://docs.fireblocks.com/api/swagger-ui/#/Cosigners%20\(Beta\)) for that.
Common Co-signer operations:
* **Pair an additional API User** - requires the workspace owner approval
* **Configure the Callback Handler of an API user** - requires the workspace owner approval
* **Unpair an API User** (formerly known as re-enroll API user) - requires admin approval
* **Rename the Co-signer**
* **Retrieve information about the Co-signer**
### The **Pair an additional API User** and **Configure the Callback Handler of an API user** are available from the Console and APIs only for users who installed the latest Co-signer versions.
Refer to [API Co-signers versions](/reference/api-cosigner-versions) for more details
### Configuring the Co-signer from its host machine
The AWS Nitro Co-signer and all types of SGX Co-signers can also be configured locally from the host machine using CLI commands. Refer to the [Operating the Co-signer](/reference/api-cosigner-operate) article for more details.
Due to Google Cloud's Workload container architecture, the GCP Confidential Space Co-signer can only be managed through Fireblocks' SaaS. Configuration operations must be performed within the workspace to which the Co-signer is connected, using either the Console or APIs. Consequently, the GCP Confidential Space Co-signer is restricted to a single workspace.
## Using the Communal Test Co-signer
> Due to legal regulations, Fireblocks can not take custodial responsibility for Mainnet workspaces. Therefore, this option is available only to Testnet workspaces.
Setting up a new Co-signer from scratch can be time-consuming. To accelerate development and prepare your workspace for automation and API-driven workflows, Fireblocks offers the option to use a Communal Test Co-signer before installing and configuring your own.
The Communal Test Co-signer is hosted and managed by Fireblocks and serves all customers with Testnet workspaces. Any workspace owner can approve pairing API users with it, generate MPC key share sets, and use it to sign transactions. Please refer to [this guide](/reference/use-communal-cosigner) to learn how to use the Communal Test Co-signer.
When you start testing and verifying your signing or approval automation workflows, we recommend setting up your self-hosted API Co-signer instance and replacing the Communal Test Co-signer as soon as your instance is ready. To stop using the Communal Test Co-signer, unpair or delete the API users that are paired with it.
Once an API user is created in a Sandbox workspace, it is automatically paired to the Fireblocks Communal Test Co-signer, which holds the MPC key shares of all the API users in the Sandbox environment across all the workspaces.
# Setup API Co-signer Callback Handler
Source: https://developers.fireblocks.com/docs/create-api-co-signer-callback-handler
## Overview
### The API Co-signer Callback Handler is an optional feature
If a Callback Handler is not configured for an API user, the Co-signer will automatically sign or approve all requests it receives for that API user.
The Fireblocks API Co-signer can connect to a user-hosted web server called the API Co-signer Callback Handler. This handler plays a critical role by receiving signing or approval requests from the Co-signer.
An optional connection to a Callback Handler can be configured for each API user paired with the Co-signer. This enables the application of custom business or security logic before transactions associated with the paired API user are automatically signed or approved.
Implementing the Callback Handler provides several benefits:
* **Enhanced control**: integrate your specific business rules and security protocols.
* **Improved compliance**: transactions are vetted to meet internal compliance standards.
* **Increased security**: the additional validation layer reduces the risk of unauthorized transactions.
This integration ensures secure, compliant and customized transaction management.
## Establishing a secure communication between the Co-signer and the Callback Handler
When configuring the Callback Handler server for an API user that is paired with the Co-signer, you can select one of the following options to secure the communication between the Co-signer (which acts as a client) and the Callback Handler server.
### Option 1: Public key authentication
In this option, the Co-signer and the Callback Handler exchange JSON Web Token (JWT) encoded messages, each signed with their respective private keys. The Co-signer's POST request to the Callback Handler server and the Callback Handler's response to the Co-signer are authenticated using their corresponding public keys.
While you can retrieve the Co-signer's public key directly from the Co-signer, you should provide the Callback Handler public key to the Co-signer during installation or while configuring the Callback Handler for an API user. This public key corresponds to the private key used by the Callback Handler to sign JWT-encoded response messages.
For development and testing purposes, the Callback Handler can be run over HTTP. However, for production environments, we strongly recommend using HTTPS with a valid TLS certificate from a trusted Certificate Authority (CA) to ensure secure communication between the Co-signer and the Callback Handler.
### Option 2: Certificate-based communication
In this option, a self-signed certificate or a certificate signed by a trusted Certificate Authority (CA) is used to establish certificate-pinning-based secure communication between the Co-signer and the Callback Handler. TLS certificate authentication occurs during SSL negotiation and is based on the certificate you provide to the Co-signer.
You provide the certificate to the Co-signer during installation or when configuring the Callback Handler for a specific API user. In this setup, both the Co-signer's POST request to the Callback Handler server and the server's response uses JSON format instead of signed JWTs.
### Learn more about setting the API Co-signer Callback Handler in the [following Developer Guide](/reference/cosigner-callbackhandler-secure-communication-authentication).
# Create Direct Custody Wallets
Source: https://developers.fireblocks.com/docs/create-direct-custody-wallets
# Overview
The Fireblocks platform consists of workspaces, vault accounts, asset wallets, and deposit addresses. This diagram shows the overall account structure in Fireblocks and the underlying wallet structure.
At the top level, your various Fireblocks workspaces are contained within the logical group called the Customer Domain. These workspaces may be "hot" (online) or "cold" (offline).
In your Fireblocks workspace, you can create and manage multiple vault accounts. These vault accounts contain your asset wallets. Each vault account can have a single wallet per base asset (e.g., BTC, ETH, SOL), but each wallet can have one or more deposit addresses.
For UTXO-based assets, such as Bitcoin, a single wallet may generate one or more deposit addresses. For account-based assets, there are two options:
* Account-based assets without tag/memo support, such as ETH, can only generate one deposit address.
* Account-based assets with tag/memo support, such as XRP, can generate one or more deposit addresses. Each deposit address has the same on-chain address. However, they differ by their tag/memo.
## Automatically generated asset wallets
### EVM
* On EVM chains, a single deposit address is shared across all EVM asset wallets in the vault account, regardless of chain or token.
* Asset wallets are auto-created when an asset is transferred to a deposit address in a vault account that doesn't yet contain that asset wallet. Applies to all globally listed EVM assets.
* For non-globally-listed assets: user must first add the asset via the Add Asset API endpoint, after which auto-creation applies.
### Solana
* Each token requires its own on-chain token account in addition to the Fireblocks asset wallet.
* The vault account uses the base Solana address as deposit address.
* When a token wallet is created via API or Console, Fireblocks creates an internal representation only; there is no on-chain transaction at that point. This saves rent expenses and follows common Solana practices in which the sender of a token creates the address.
* Token account is created on-chain on the first incoming transaction; sender covers the rent cost.
* When the asset wallet is created due to an incoming transfer, the token account already exists on-chain.
* Asset wallets are auto-created when an asset is transferred to a deposit address in a vault account that doesn't yet contain that asset wallet. Applies to all globally listed Solana assets.
* For non-globally-listed assets: user must first add the asset via the Add Asset API endpoint, after which auto-creation applies.
# Types of vault structures
Fireblocks recommends structuring your vault accounts using one of two methods: omnibus or segregated. The diagram below describes the advantages and disadvantages of each structure.
## Omnibus structure
The omnibus structure consists of a central vault account, deposits vault account for UTXO and Tag/Memo based assets and vault accounts for each end-client for account based assets.
Funds are deposited into the individual vault accounts or to the deposits vault account, depending on the asset type, and then swept to the central vault account, where the funds can be invested.
### Address creation flows
For extended documentation, see [Best Practices for Structuring Your Fireblocks Vault](https://support.fireblocks.io/hc/en-us/articles/5253421857564-Fireblocks-Vault-structure-best-practices) . Some notes on the information presented in the Help Center article:
* Omnibus and segregated account structures are independent of whether you have a hot or cold workspace. Both account structures can be implemented in either workspace type.
* Workspaces can contain both an omnibus and segregated account models. There is no limitation for a workspace to contain one specific account model.
#### Omnibus address creation (UTXO)
* The end user, Alice, asks to deposit a UTXO asset, such as Bitcoin (BTC).
* The customer's application creates a new deposit address in the Omnibus vault account.
* This deposit address is assigned to Alice and mapped accordingly within the customer’s private ledger.
* Alice receives a notification from the application with her assigned deposit address, where she can start depositing funds.
#### Omnibus address creation (account-based with tag/memo support)
* The end user, Alice, asks to deposit an account-based asset that supports tag/memo fields, such as Ripple (XRP).
* The customer's application creates a new deposit address in the Omnibus vault account.
* This deposit address is assigned to Alice and mapped accordingly within the customer’s private ledger.
* Alice receives a notification from the application with her assigned deposit address, where she can start depositing funds.
#### Omnibus address Creation (account-based)
* The end user, Alice, asks to deposit an account-based asset, such as Ethereum (ETH).
* The customer's application creates a new intermediate vault account and a wallet with a deposit address within it.
* This deposit address is assigned to Alice and mapped accordingly within the customer’s private ledger.
* Once mapped and credited, Alice receives a notification from the application with her assigned deposit address, where she can start depositing funds.
## Segregated structure
The segregated structure consists of individual vault accounts for each end client. Funds are stored in and invested from these individual accounts.
### Address creation flows
There’s no difference between UTXO and account-based assets when dealing with the segregated account structure. For both, the process is as follows:
* The end user, Alice, asks to deposit some assets.
* The customer's application creates or reuses a vault account dedicated to Alice, then creates at least one asset wallet to generate a deposit address (if one doesn't already exist). After that, Fireblocks automatically creates an asset wallet for any globally listed asset sent to that address.
* Alice receives a notification from the application with her assigned deposit address, where she can start depositing funds.
# Hiding vault accounts
When you create intermediate vault accounts for end users, your workspace can quickly accumulate a large number of them. Sometimes tens of thousands, sometimes millions.
Having all of these accounts visible in the Fireblocks Console creates two problems. First, it degrades console performance. Second, every transaction to or from these accounts appears in the Recent activity panel, which can flood the interface with notifications when deposits are frequent. Since intermediate vault accounts are managed through the API anyway, it makes sense to hide them from the Console.
You have two ways to do this, both through the Fireblocks API:
* **Hide a vault account at creation.** Pass the optional `hiddenOnUI` parameter when calling the [Create a new vault account](/reference/createvaultaccount)a endpoint.
* **Hide an existing vault account.** Use the [Hide a vault account in the Console](/reference/hidevaultaccount) endpoint for any account that wasn't hidden at creation.
Hidden vault accounts are not gone. All transactions and balances remain fully accessible through the API.
# Overview
Source: https://developers.fireblocks.com/docs/create-payouts
### Note
Fireblocks provides technology infrastructure only. All payment and financial services described on this page are delivered by our customers under their own regulatory licenses. Fireblocks does not provide regulated services in the EEA.
# Overview
The Payout Service API allows you to create and execute payout instruction sets.
A payout instruction set describes how to distribute payments from a payment account to multiple payee accounts.
* **Payment account:** Any valid Fireblocks-supported vault account, exchange account, or fiat account.
* **Payee account:** A valid address in Fireblocks for receiving funds. This can be a vault account, exchange account, whitelisted address, fiat account, or merchant account.
The payout process can only be executed if the payment account has a sufficient balance for the entire payout instruction set. If the payout account doesn't have a sufficient balance, the payout remains in an Insufficient Balance state until the payment account has a sufficient balance to perform the payout instructions. Payouts in an Insufficient Balance state expire at midnight UTC and are moved to Failed status.
A payout instruction set can only be executed once. Re-executing a payout instruction set results in an error.
# Payouts Flow
When a user wants to send a payment to one or more of their merchants, they can use the Payout Service API to send the payout from their exchange account.
The flow consists of 3 main steps:
1. [Creating a payout instruction set](/reference/executing-payouts#creating-a-payout-instruction-set)
2. [Executing a payout instruction set](/reference/executing-payouts#executing-a-payout-instruction-set)
3. [Monitoring Payouts](/reference/executing-payouts#executing-a-payout-instruction-set)
# Data Model
Source: https://developers.fireblocks.com/docs/data-model
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
Fireblocks end user wallets (EUWs) are hierarchical deterministic (HD) wallets. With our REST API, customers can easily create new wallets for their end users and add multiple accounts under them. Each account can contain different assets, and all transactions are signed using the end-user key generated for a specific wallet.
# Data Model
* **User:** Represents the end user of your application. Kindly note that this entity is external to Fireblocks and is reflected only on the customer's side.
* **Device:** A logical identifier representing an entity that stores an end-user key share and can participate in MPC operations for a given wallet.
* **Wallet:** Represents an end user wallet created via the Fireblocks API.
* **Transaction:** Represents the transactions created in Fireblocks.
* **Account:** Represents the different accounts under a single end user wallet.
* **Asset:** Represents the different assets under a single account.
# Relationships
* User > Device: **One to Many** relation
* Wallet > Device: **One to Many** relation
* Wallet > Account: **One to Many** relation
* Wallet > Transaction: **Many to Many** relation
* Device > Message: **One to Many** relation
* Account > Asset: **One to Many** relation
### Device ID and wallet correlation
Each user can have multiple `deviceId` values, each correlating to a different end user wallet in Fireblocks. Each `deviceId` represents an entity that stores an end-user key share.
# Data Privacy and Protection
Source: https://developers.fireblocks.com/docs/data-privacy-and-protection
Fireblocks does not store or process any client Personal Identifiable Information (PII). To achieve this, the customer is required to strictly use anonymized tokens, such as (UUID) to reflect client data. These anonymous tokens are mapped internally by the customer to actual client identifiers stored on the customer's end.
Since the customer processes and manages its wallet infrastructure using the Fireblocks Console or Fireblocks API, these anonymous tokens should be used when using the Fireblocks REST API endpoints. The following table lists the relevant fields that allow persistent information to be stored in Fireblocks–for which the anonymous tokens should be used.
| API Endpoint | Method | Parameter |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- |
| Vault | [Create a new vault account](/api-reference/vaults/create-a-new-vault-account) | name |
| Vault | [Create a new asset deposit address](/reference/createvaultaccountassetaddress) | description |
| Vault | [Rename a vault account](/api-reference/vaults/rename-a-vault-account) | description |
| Internal Wallet | [Create an internal wallet](/api-reference/internal-wallets/create-an-internal-wallet) | name |
| Internal Wallet | [Set an AML/KYT customer reference ID for an internal wallet](/api-reference/internal-wallets/set-an-amlkyt-customer-reference-id-for-internal-wallet) | customerRefId |
| External Wallet | [Create an external wallet](/api-reference/external-wallets/create-an-external-wallet) | name |
| External Wallet | [Set an AML customer reference ID for an external wallet](/api-reference/external-wallets/set-an-aml-customer-reference-id-for-an-external-wallet) | customerRefId |
| Contracts | [Create a contract](/api-reference/contracts/add-a-contract) | name |
| Transactions | [Create a new transaction](/api-reference/transactions/create-a-new-transaction) | note |
| Transactions | [Estimate a transaction fee](/api-reference/transactions/estimate-transaction-fee) | note |
# Overview
Source: https://developers.fireblocks.com/docs/define-aml-policies
Since privacy is a key principle of blockchain technology, transactions on the blockchain do not contain any information about the people or organizations involved. However, criminals may try to use this anonymity to hide illicit fund transfers. To prevent funds from being sent to criminals or sanctioned parties, regulators in many jurisdictions have begun mandating the collection of personal data for users transacting on the blockchain.
The Fireblocks AML feature allows you to automate real-time monitoring of your crypto transactions in order to ensure compliance with Anti-Money Laundering/Counter Financing of Terrorism (AML/CFT) regulations, prevent interactions with sanctioned entities, and identify customer behavior. You can integrate your Fireblocks account with Chainalysis or Elliptic, our third-party transaction monitoring providers, to retrieve AML/CFT information on your incoming and outgoing transactions. You can also implement your own custom screening logic for AML providers that are not natively supported.
In either case, your AML provider analyzes your transactions in real time and screens them based on the policy you create. The provider then returns a risk profile based on the transaction details (including addresses). You can approve, reject, or receive alerts for transactions in response to the provided risk information.
You, the transaction owner, are responsible for compliance reporting. Fireblocks and the AML provider make reporting easy with auditable risk information available for export. In the event of a risky transaction in a jurisdiction that requires reporting, your compliance officer will need to file any regulatory requirements with the appropriate authorities.
# Transaction Screening Flow
## Outgoing
1. You initiate a transaction in your Fireblocks workspace.
2. The transaction passes through your AML Transaction Screening Policy to determine whether it should then be sent to your AML provider for screening.
3. If the transaction should be screened according to your policy, Fireblocks sends the transaction’s details to the provider to receive the transaction’s risk information and to be registered for further monitoring. Fireblocks shares the following transaction information with your AML provider:
1. Asset
2. Amount
3. Origin address
4. Beneficiary address
5. Blockchain hash
4. Your AML provider determines the transaction’s risk score and sends the result to your Fireblocks workspace. [Learn how Fireblocks handles outgoing transactions when risk scores are not available immediately](https://support.fireblocks.io/hc/en-us/articles/8332157003676-AML-Advanced-Configuration-settings#h_01H825711H0J4DQR4M53YMVY0Z) .
5. The integration approves or rejects the transaction based on its risk information and your Post-Screening Policy.
You can configure your Post-Screening Policy so that you receive alerts when the transaction’s risk information becomes available from your AML provider. After the screening, recorded information can be viewed in your Transaction History, the Audit Log, and your provider’s interface for auditing by your compliance team.
## Incoming
1. Fireblocks detects an incoming transaction to your workspace.
2. The transaction passes through your AML Transaction Screening Policy to determine whether it should then be sent to your AML provider for screening.
3. If the transaction should be screened according to your policy, Fireblocks sends the transaction’s details to the provider to receive the transaction’s risk information and to be registered for further monitoring. Fireblocks shares the following transaction information with your AML provider:
1. Asset
2. Amount
3. Origin address
4. Beneficiary address
5. Blockchain hash
4. Your AML provider determines the transaction’s risk score and sends the result to your Fireblocks workspace. [Learn how Fireblocks handles incoming transactions when risk scores are not available immediately](https://support.fireblocks.io/hc/en-us/articles/8332157003676-AML-Advanced-Configuration-settings#h_01H8256NXQ4HW6ERG72686CF30) .
5. The integration approves or rejects the transaction based on its risk information and your Post-Screening Policy.
You can configure your Post-Screening Policy so that you receive alerts when the transaction’s risk information becomes available from your AML provider. After the screening, recorded information can be viewed in the Transaction History, the Audit Log, and your provider’s interface for auditing by your compliance team.
### Learn more about AML:
1. Check out the [following guide](https://support.fireblocks.io/hc/en-us/articles/360014290380-AML-Transaction-Screening-Monitoring) for more information about Fireblocks AML integration
2. Check out the [AML API endpoints](/reference/updateamlscreeningconfiguration) in the API Reference
# Best Practices
Fireblocks supports native integrations with AML providers such as Chainalysis and Elliptic. Alternatively, you can use your own integration. Regardless of your provider, the following recommendations will help you configure a reliable and effective AML setup.
* **Keep your policies as simple as possible.** Overly complicated rules can make it difficult to understand what is being screened.
* **Configure AML provider risk rating parameters to align with your compliance needs.** Be aware that risk ratings vary by provider.
* For example, a risk rating of 4 might be considered high risk by one provider, but only moderate risk by another.
* Some providers also allow the option to ignore risk rating entirely and focus only on categories.
* **Use the "Skip on failure" option** to control the screening process when an AML provider service is down or unreachable.
## Screening Timeouts
Fireblocks applies different timeout windows depending on the direction of the transaction:
* **Incoming transactions:** 10 minutes
* **Outgoing transactions:** 1 minute
This difference exists because AML providers need time to index transactions. Incoming transactions are resolved by transaction hash, while outgoing transactions are resolved by address. The indexing process only begins after a [certain number of blockchain confirmations](https://docs.chainalysis.com/api/kyt/guides/#polling-the-summary-endpoints-transfers-without-confirmation) is completed, which means incoming transactions require more time before a risk score can be returned.
# Custom 3rd party AML Providers
Fireblocks offers direct integrations with AML providers Chainalysis and Elliptic. If you prefer to use a different provider, we recommend setting up workflows for integrating third parties with your workspace as described in the [following guide](/docs/integrating-third-party-aml-providers).
# Freeze & Unfreeze Transactions
Auto Freeze allows you to set rules to automatically freeze an incoming transaction’s assets in your workspace for further review upon receiving funds from a suspicious sender. Fireblocks allows you to automatically freeze incoming transactions based on the default policy or a custom policy. You can also manually freeze an incoming transaction using the Freeze Transaction API endpoint.
* For UTXO-based assets, Fireblocks marks the specific transaction's inputs as unspendable.
* For account-based assets, Fireblocks marks the transaction's balance as unspendable. This means you can still use the rest of your wallet or vault account's balance for other transactions.
Once Auto Freeze takes place, the transaction does not continue to other steps in transaction screening. For example, if you have both AML and Travel Rule enabled and an incoming transaction is automatically frozen during the AML Transaction Screening Policy, the transaction does not proceed to Travel Rule transaction screening.
Users assigned an Owner or Admin role can unfreeze these funds using the Fireblocks Console or the Fireblocks API.
### Check out the [Unfreeze Transaction API](/reference/freezetransaction) in the Fireblocks API Reference
# Define Approval Quorums
Source: https://developers.fireblocks.com/docs/define-approval-quorums
# Admin Quorum
The Admin Quorum lists all users with Admin privileges (users assigned to either an Owner, Admin, or Non-Signing Admin role).
The Admin Quorum threshold defines the number of Admins required to approve new workspace connections and changes. Any Admin can deny a request to reject it before the threshold is met. Requests have different expiration times depending on the action.
Activities that require Admin Quorum approval include:
* Whitelisting addresses
* New Fireblocks Network connections
* New exchange accounts
* Other external destination addresses
* Adding new workspace users
* Changes to Policies
* Configuring approval groups
* Other workspace configuration changes
### Learn more about setting Admin Quorum in the [following guide](https://support.fireblocks.io/hc/en-us/articles/360017665119-Admin-Quorum)
## Admin Quorum API
Check the Admin Quorum API reference [here](/reference/setadminquorumthreshold)
# Approval Groups
Approval groups consist of users from a designated user group. They are designed to facilitate the approval of various workspace configuration changes within different workspace domains, such as security and compliance, user management, the Fireblocks Network, and external accounts.\
These groups operate similarly to the Admin Quorum and can be used in its place for approving specific actions of your choice.
### Learn more about defining Approval Groups in the [following guide](https://support.fireblocks.io/hc/en-us/articles/11500062124188-Approval-groups)
This feature allows you to designate a specific group of people to approve tasks, regardless of their roles or permissions. Approval groups provide the flexibility to segregate and delegate responsibilities, which is crucial for scaling and accelerating your business operations while maintaining security.
Here are a few tips for setting up your approval groups:
* Approval groups are distinct from regular user groups and are not related to Policies
* While you can remove owner approval from certain actions, key changes in your workspace will still require owner involvement
* A threshold for the chosen group is required
# Overview
Source: https://developers.fireblocks.com/docs/define-confirmation-policy
Blockchain confirmations are crucial for maintaining the security and integrity of the blockchain. This process ensures that transactions are securely verified, thereby preventing fraud and double-spending. However, the number of confirmations also directly impacts the time it takes for a transaction to complete and for the funds to become available in your wallet. The higher the number of required confirmations, the longer it takes for the transferred amount to be accessible.
Whether you aim to speed up transaction flow by reducing the number of confirmations or enhance security by increasing them, follow the recommendations below for an effective setup.
## When to reduce the number of confirmations
A low number of blockchain confirmations should only be set for transactions coming from well-known and trusted sources. This is advisable when the origin of the transaction is your connected exchange account, a trusted counterparty, or even a transaction between two vault accounts within your workspace.
## When to increase the number of confirmations
A low number of blockchain confirmations should *not* be set for transactions arriving from unknown external addresses, or from addresses that you do not control or do not have a well-established, trusted business relationship with.
## Fireblocks Deposit Control & Confirmation Policy
The Deposit Control and Confirmation Policy allows you to specify the number of blockchain network confirmations required for incoming and outgoing transactions to clear, ensuring that their funds are credited to a wallet.
After the transaction clears, its deposit amount is accounted for in the wallet’s currently available balance. Additionally, for UTXO-based blockchain networks, the transaction's outputs become immediately spendable.
### Default Confirmation Policy
Each workspace in Fireblocks has a default configuration policy that specifies the number of confirmations required for each blockchain to complete transactions and make the funds available in the wallet.
To learn about the default values for each supported blockchain, refer to this [Help Center article](https://support.fireblocks.io/hc/en-us/articles/10883496786204-Default-Deposit-Control-and-Confirmation-Policy)
### Custom Confirmation Policy
You can define your own confirmation policy based on your organization’s business needs. Learn more about the Custom Confirmation Policy in this [Help Center article](https://support.fireblocks.io/hc/en-us/articles/10883650908572-Build-a-custom-Deposit-Control-and-Confirmation-Policy).
## Dynamically overriding the required number of confirmations
Fireblocks allows you to manually/dynamically confirm transactions and override your workspace's confirmation policy for specific transactions. This immediately updates the transaction status to Completed in your Fireblocks workspace.
* To do so manually via the Console, refer to this [Help Center article](https://support.fireblocks.io/hc/en-us/articles/360015491419-Confirming-transactions-manually).
* To do so via the API, refer to this [guide](/reference/settransactionconfirmationthreshold).
# Define Travel Rule Policies
Source: https://developers.fireblocks.com/docs/define-travel-rule-policies
The recommended the Travel Rule in order to combat money laundering and terrorist trafficking activity. The rule states that Virtual Asset Service Providers (VASPs), which include businesses that exchange virtual assets, must provide additional data on the senders and recipients of certain transactions. Each jurisdiction decides which transactions must adhere to the Travel Rule and what data must be included.
### Fireblocks does not permanently store any transaction data needed specifically for the Travel Rule.
All Travel Rule data is encrypted and stored with Notabene if needed. Fireblocks does not hold the keys for decrypting the information.
To help you comply with the Travel Rule, Fireblocks provides integration with Travel Rule provider [Notabene](https://notabene.id/). Notabene analyzes your incoming and outgoing transactions in real time and screens them based on your workspace’s Travel Rule policy. After Notabene screens a transaction and determines its compliance with the Travel Rule, the appropriate action can be taken automatically.
After integrating Notabene with your Fireblocks workspace, you can configure and manage various settings and policies. In your Notabene dashboard, you can configure settings related to your Notabene account. In your Fireblocks workspace, you can create a Travel Rule policy to determine which transactions should be screened and what post-screening actions should be taken based on the screening status.
[You can read Notabene's documentation for more information on how they integrate with Fireblocks.](https://devx.notabene.id/docs/using-notabene-and-fireblocks)
### Learn more about Travel Rule Integration in the following [guide](https://support.fireblocks.io/hc/en-us/articles/8271611252764-Setting-up-Travel-Rule-integration)
### Check out the [Travel Rule APIs](/reference/validatetravelruletransaction) in the Fireblocks API Reference
# Developer Center
Source: https://developers.fireblocks.com/docs/developer-center
# Overview
The Developer Center page lets your organization view and monitor your workspace's API activity in the Fireblocks Console.
The **Overview** tab lets you view a bar graph showing the distribution of your workspace's API requests. The default view is a seven-day distribution, but you can toggle it to view the last 24 hours of activity in one-hour windows.
Below the graph, you can view the category of each API request and what percentage that category makes up of the total distribution. Next to the percentage is the actual number of requests made within each category.
# API monitoring
The **API monitoring** tab lets you view a line graph of the types of requests made over the last seven days. Like on the Overview tab, you can switch the view to a 24-hour format divided into one-hour windows.
Below the graph, a table shows a breakdown of each request by date and time, method, category, endpoint, response code, and the number of requests made. If your workspace has numerous requests, you can search the table using the search bar above it or filter the graph and the table using the Filters tree list on the left side of the page. You can filter by response code, method, and category.
### Response code 429
Response code 429, typically reserved for rate limited responses, is an upcoming feature that is not currently available to view or filter by.
# API users
### Only available to Admin-level workspace users
The **API users** tab is only available to Admin-level workspace users such as the Owner, Admins, and Non-Signing Admins. The tab does not appear to any other user roles.
The **API users** tab lets you create and manage your workspace's API users. A table shows a list of the workspace's API users by name, role, API key, what user group (or groups) they're in, and their current status.
Visit our Help Center to learn more about:
* [Adding API users](https://support.fireblocks.io/hc/en-us/articles/4407823826194-Adding-new-API-users)
* [Re-enrolling API users](https://support.fireblocks.io/hc/en-us/articles/4412016177554-Re-enrolling-API-users)
* [Deleting users](https://support.fireblocks.io/hc/en-us/articles/4404971260050-Deleting-Users) (Owner only)
# Overview
Source: https://developers.fireblocks.com/docs/dynamic-embedded-wallets
Fireblocks has acquired Dynamic, a developer platform powering millions of onchain user accounts across web, iOS, and Android.
Dynamic's non-custodial embedded wallets enable users to tap into stablecoin rails, earn yield, spend from cards, and access DeFi protocols directly within your application.
With sub-second signing, extensive cross-chain support, and flexible recovery options, Dynamic's infrastructure integrates seamlessly alongside Fireblocks to deliver the most complete production-grade wallet experiences at scale.
Try the [live demo](https://demo.dynamic.xyz/) and [contact us](https://fireblocks.com/dynamic) for a detailed walkthrough.
## Looking for more?
* For an overview of Dynamic embedded wallets, visit [here](https://www.dynamic.xyz/docs/overview/introduction/welcome).
* For migration guides, visit [here](https://www.dynamic.xyz/docs/overview/migrations/migration-guide).
# Overview
Source: https://developers.fireblocks.com/docs/embedded-wallet-android-core-sdk
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# What's new in 2.9.14
* Added ability to control console logging when needed, particularly for network call logging. This provides better flexibility for debugging while maintaining production performance.
* Enhanced data masking with new patterns for encryptedKey and iv fields in MaskSensitiveData functionality, providing better protection of sensitive cryptographic information.
* Enhanced error handling in WalletRepo registration process, providing more reliable wallet initialization and better error reporting.
# What's new in 2.9.9
* Android 15+ Page Size Support: Native libraries now support Android's 16 KB page sizes, fulfilling a requirement for new apps and updates targeting Android 15 and above. (Refer to the [Android Developers documentation](https://developer.android.com/guide/practices/page-sizes) for more details.)
# What's new in 2.9.8
* Improved request join wallet flow for multiple algorithms.
# What's new in 2.9.7
* Fixed an issue that prevented key generation on Android devices with non-English locales.
# What's new in 2.9.6
* Improved transaction's signature timeouts handling on wallets with multiple devices.
# What's new in 2.9.5
* We now have more accurate error events for scenarios where functionality fails due to incomplete device setup or involving invalid physical device IDs.
# What's new in 2.9.4
* We've improved how we handle failed requests by adding a short delay, ensuring faster issue resolution and reducing unnecessary retries.
# What's new in 2.9.3
* In cases where a signature verification error is detected, the system will now proactively check the integrity and status of its downloaded certificates. If these certificates are found to be outdated or invalid, they will be refreshed to ensure that signature verification can proceed correctly.
# What's new in 2.9.2
* Added `FireblocksError` `MaxDevicesPerWalletReached` (111) when the maximum number of devices in a wallet is reached while trying to add a new device. This ensures users are informed about the limit and can take appropriate actions.
* Enhanced the stability of the native code involved in Multi-Party Computation (MPC) flows. This update aims to provide a more reliable and robust experience during MPC operations.
# What's new in 2.9.1
* Added a new `internalErrorCode` field in the `FireblocksError` class to provide additional information on specific errors.
# What's new in 2.9.0
* Resolved an issue that occurred during key generation when a device setup was incomplete.
* Resolved a concurrency issue that arose when attempting to join a wallet containing multiple keys.
* Implemented a restriction to prevent the usage of internal classes, enhancing security and code integrity.
# What's new in 2.8.2
* Fixed an issue where key generation could fail if initiated immediately after SDK initialization.
# What's new in 2.8.1
* Resolved an issue when verifying certificates concurrently.
# What's new in 2.8.0
* Resolved a minor issue in the MPC code.
# What's new in 2.7.0
In version 2.7.0, we've introduced a few enhancements:
* Improved log collection.
* Resolved an issue when trying to sign a transaction that has failed or will fail before it can even be signed.
* Improved error visibility: wrong passphrase in the recovery process is now explicitly mentioned in the returned error as `WRONG_RECOVERY_PASSPHRASE` (603)
* The SDK is now being built with Android 14 (API Level 34). For more information please see [here](https://developer.android.com/google/play/requirements/target-sdk).
# What's new in 2.6.0
In version 2.6.0, we've introduced a few major enhancements.
1. Direct reporting of errors to Fireblocks. This will ease the process of supporting and debugging issues in the future. More information can be found [here](https://ncw-developers.fireblocks.com/docs/ncw-sdk-telemetry-collection).
2. Our MPC ceremony processes have been enhanced for greater robustness. MPC messages will now undergo multiple retry attempts before failing.
3. Unexpected device errors, as seen in [Common Errors](/reference/common-errors) will now result in the expected messaging, and not in a timeout.
4. You can now dynamically extend wallets! Expand the range of algorithms available in a wallet by adding, for instance, EdDSA alongside ECDSA. Learn more [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms).
# What's new in 2.5.0
In version 2.5.0, we've introduced several enhancements and additions to the SDK functionality:
1. New Functionality: We've added a new function called `stopSignTransaction` to the SDK interfaces. This function enables users to stop and cancel transactions that were initiated for signing by the SDK.
2. Enhanced error handling for quick transaction signing failures caused by invalid messages from the backend, such as schema changes in the message response from the backend.
3. We've addressed a few edge cases in the mpcKeyGeneration process that could potentially result in key generation failures. These improvements enhance the overall stability and reliability of the SDK.
## Upgrade guidelines
1. In case of an exception, GenerateMPCKeys is no longer returning an empty Set, but a Set with keys and their appropriate statuses. You will need to validate that the keys are all in status Ready in order to verify that the setup is complete. Please See the following example for [clarifications.](https://github.com/fireblocks/ncw-ios-demo/commit/5a1f3318974a28aee7cd9cbf92406cf31f2ebb0a#diff-3ae2d84b992c8e9c9fd4f787b4c0fa44c9e601083e7d1ee0892acd8fb913ef14L90)
2. All `KeyRecovery` properties are now optional. This may come into effect in a similar code to this [one](https://github.com/fireblocks/ncw-ios-demo/commit/5a1f3318974a28aee7cd9cbf92406cf31f2ebb0a#diff-3ae2d84b992c8e9c9fd4f787b4c0fa44c9e601083e7d1ee0892acd8fb913ef14L162).
3. All `KeyDescriptor` properties are now optional. This may come into effect in a similar code to this [one](https://github.com/fireblocks/ncw-ios-demo/commit/5a1f3318974a28aee7cd9cbf92406cf31f2ebb0a#diff-3ae2d84b992c8e9c9fd4f787b4c0fa44c9e601083e7d1ee0892acd8fb913ef14L162).
# What's new in 2.4.0
In version 2.4.0, we've expanded the capabilities of the NCW SDK to support Solana and Algorand, now including the EdDSA algorithm alongside our existing ECDSA support. This enhancement enables a single wallet to seamlessly interact with Bitcoin, various EVMs, and Solana.
More information about the supported NCW networks may be found [here](https://ncw-developers.fireblocks.com/docs/supported-networks) .
Additionally, we're excited to announce that support for more blockchains, including Stellar, is on the horizon. Stay tuned for further updates!
## Upgrade guidelines
To successfully utilize the generateMPCKeys function with MPC\_EDDSA\_ED25519, it's essential that your workspace supports EdDSA. Learn more about supporting multiple algorithms within a single wallet [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms).
# What's new in 2.3.0
In version 2.3.0, we made significant performance improvements in transaction signing.
For additional tips on enhancing overall performance, refer to our documentation [here](https://ncw-developers.fireblocks.com/docs/boosting-ncw-client-performance).
# What's new in 2.2.8
In version 2.2.8, we made significant performance improvements in key generation and transactions.
For additional tips on enhancing overall performance, refer to our documentation [here](https://ncw-developers.fireblocks.com/docs/boosting-ncw-client-performance).
# What's new in 2.2.5
In version 2.2.5, we have added the ability to work with multiple devices in a single wallet.
For more information about multiple devices, refer to our documentation [here](https://ncw-developers.fireblocks.com/docs/multiple-devices).
# What's new in 2.1
In version 2.1, we added a safer backup and recovery mechanism.
## Breaking change
Version 2.1 introduces a breaking change since the following two functions in the interface will receive different parameters:
* `backupKeys`
* `recoverKeys`
You can find details about the implementation in our [android-ncw-demo repo](https://github.com/fireblocks/android-ncw-demo/) and more information about the backup procedure [here](https://ncw-developers.fireblocks.com/v4.0/docs/backup-recovery).
## Upgrade guidelines
When upgrading to version 2.1 and later, you should require the user to run another backup procedure so that the new encrypted backup share on the Fireblocks servers will be associated with a `passphraseId`.
# Embedded Wallet SDK
Source: https://developers.fireblocks.com/docs/embedded-wallet-android-sdk
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# What's new in 1.0.2
* Improved error reporting and logging capabilities
# Asset Management
Source: https://developers.fireblocks.com/docs/embedded-wallet-asset-management
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Getting the asset list
Call the [Retreive supported assets endpoint](/reference/getsupportedassets) to view the list of assets available to your workspace. The response includes the Fireblocks assetId which is used when you add assets.
If you're looking into quickly viewing the supported asset list, you can view the [Supported Networks](doc:supported-networks) page.
# Adding assets
You add assets via the Fireblocks SDK. Unless your Fireblocks Customer Success Manager and Fireblocks Support allow an exception, Fireblocks requires you to complete the backup procedure for each wallet before you can add any assets.
### A note on Backup Enforcement
If your workspace is already running in a Production environment, key backup enforcement is enabled by default. However, it is not enabled by default in Sandbox environments to allow for an easier integration process.
Due to the above, when you attempt to call the [Active a wallet in a vault account endpoint](/api-reference/vaults/activate-a-wallet-in-a-vault-account), you must first go through [this backup flow](https://ncw-developers.fireblocks.com/docs/backup-recovery-1#backup-procedure).
# Example
```typescript TypeScript theme={"system"}
const address = await ew.addAsset(accountId, assetId);
```
```bash Shell theme={"system"}
curl --request POST \
--url https://sandbox-api.fireblocks.io/v1/ncw/wallets/walletId/accounts/accountId/assets/assetId \
--header 'accept: application/json'
```
Note in the code example above that the `accountId` parameter runs an index created by the `await ew.createAccount()` function. In our demo, we always use **accountId 0** for simplicity.
## Adding Solana Tokens
On the Solana blockchain, receiving tokens requires creating a dedicated token account derived from your main account. This is usually handled automatically when someone sends you tokens, but your customer can pre-create the account if needed.
In order to create the dedicated token account, you can still invoke the [add asset](/reference/addasset) endpoint which in turn will create a transaction on behalf of the customer, for signing.
Within the response of the request, or later on, using the [retrieve asset](/reference/getasset) endpoint you can query for the `state` of the asset.
* `PENDING_ACTIVATION`
* `ACTIVATION_FAILED`
* `READY`
In case the asset is under `PENDING_ACTIVATION`, a pending transaction still awaits the end user for signing. Once he signs the transaction, the asset status should now appear as `READY`.
In case the end user failed to sign the transaction, the status will appear as `ACTIVATION_FAILED` and the asset will require adding it again.
# Backup and Recovery
Source: https://developers.fireblocks.com/docs/embedded-wallet-backup-and-recovery
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
As outlined in the [Backup and Recovery Overview](https://ncw-developers.fireblocks.com/docs/backup-recovery), the backup and recovery features enable the creation of an encrypted copy of the end-user key share, which is then sent to Fireblocks for safekeeping. This process becomes essential when a user may lose access to their device or need to transition to a new one.
The application or the user must generate the recovery passphrase for AES encryption of the end-user key share. The end user *must* securely preserve this passphrase. This precaution ensures that the private key share can be decrypted in a recovery situation, granting the user access to their key and enabling them to operate as usual.
Backing up the passphrase can be accomplished through various methods, and Fireblocks does not mandate any specific approach. For example, the end user can store the recovery passphrase in their iCloud account or Google Drive, or they may download and keep it locally on their device.
## Terms to know
* **`passphrase`:** The chosen passphrase for the backup. MPC key share #2 is encrypted using this passphrase and saved/encrypted along with the `passphraseId` from the Fireblocks cloud servers.
* **`passphraseId`:** The UUID created by the application.
* **`passphraseResolver`:** A callback that knows how to fetch the passphrase from its saved location when given a `passphraseId` value. For example, if you saved the passphrase on the end user's iCloud account, then when given the `passphraseId` value, the `passphraseResolver` callback fetches the passphrase from the iCloud account so that the `recoverKeys` function can decrypt the MPC key share.
# Backup procedure
### Prerequisites
Before running a backup procedure, you will need to have an MPC key share on the device.
This can be obtained by either:
* Generating an MPC key share (new wallet scenarios) as shown [here](https://ncw-developers.fireblocks.com/docs/mpc-key-generation).
* Running a recovery flow, as later described in this article.
```typescript TypeScript theme={"system"}
await ewCore.backupKeys(passphrase, passphraseId);
```
```kotlin Kotlin theme={"system"}
// create a symmetric key for the encryption of the backup
var backupEncryptionKey = fireblocksSdk.generateRandomPassPhrase();
// store the backupEncryptionKey somewhere (user’s iCloud/Google, d/l, convert to seed phrase or other)
// backup the keys (including encryption)
fireblocks.backupKeys(passphrase, passphraseId) {
Timber.d("Backup keys result: $it")
callback.invoke(it)
}
```
```swift Swift theme={"system"}
func backupKeys() async throws -> Set {
//Initialize and create the Core SDK instance
let instance = try getCore()
return try await instance.backupKeys(passphrase: , passphraseId: )
}
```
Please note that steps 1 and 2 are under your implementation, while step 3 calls the Fireblocks SDK backup.
1. Store the `passphrase` and `passphraseId` in your preferred user cloud (e.g., iCloud, Google Drive). The `passphraseId` must be a UUID, as required by Fireblocks.
2. Ensure the app can retrieve the `passphrase` during recovery on a different device. This is done via the `passphraseResolver` callback (supplied when calling `recoverKeys`): the SDK provides the `passphraseId`, and your implementation must return the corresponding `passphrase`.
* One approach is to deterministically calculate the path to the stored passphrase in the user's cloud.
* Alternatively, you can store and retrieve this data from another location of your choice.
3. Call the Fireblocks implementation for backup together with the `passphrase` and the `passphraseId`.
### Backing up your keys post extension
In case you have extended your key set, as elaborated [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms#extending-your-key-set), you must repeat the above steps again, in order to back up your new, extended key set, as well.
# Recovery procedure
```typescript TypeScript theme={"system"}
await ewCore.recoverKeys(passphraseResolver);
```
```kotlin Kotlin theme={"system"}
// recover the backed up keys. We will use the given backupEncryptionKey to decrypt the keys
Fireblocks.getInstance(deviceId).recoverKeys(passphraseResolver = passphraseResolver) {
Timber.d("Recover keys result: $it")
callback.invoke(it)
}
```
```swift Swift theme={"system"}
//Initialize and create the Core SDK instance
let instance = try getCore()
let keySet = try await instance.recoverKeys(passphraseResolver: passphraseResolver)
```
1. Call the Fireblocks SDK's `recoverKeys` function with a callback that implements a function that, when given a `passphraseId`, will fetch the associated `passphrase` for the user.
2. The Fireblocks SDK fetches the last encrypted key share with the associated `passphraseId` and then uses your callback to decrypt the private key share locally.
## Get the Device ID
The encrypted backup is associated with the end user's `deviceId`. Therefore, to recover and decrypt the key share saved on the Fireblocks cloud servers, the NCW SDK must be initialized with the same `deviceId` that created the backup. The NCW SDK cannot recover a key share of a different `deviceId`.
```typescript TypeScript theme={"system"}
await ew.getLatestBackup();
```
```bash Shell theme={"system"}
curl --request GET \
--url https://sandbox-api.fireblocks.io/v1/ncw/wallets/walletId/backup/latest \
--header 'accept: application/json'
```
If you want to let your end users go into recovery mode, you need to determine the `deviceId` that will run the recovery procedure. To support this, Fireblocks has provided a function within the Fireblocks SDK that fetches the latest details about the backup of the specified `walletId`.
Note: If no backup is found for the specified wallet, a 404 status will be returned.
# Post-Recovery Behavior
Following recovery, the previously associated device is invalidated and loses the ability to perform MPC-related operations such as signing transactions, creating backups, adding devices, or takeovers. **The new device that successfully performed the recovery becomes the active device**.
### Special Case: Same Device Recovery
Recovery may be performed on the same physical device that is still active and holds the key share. While this is technically redundant, it is supported. In this case, the device performing the recovery will remain active.
# Boosting Embedded Wallet Performance
Source: https://developers.fireblocks.com/docs/embedded-wallet-boosting-embedded-wallet-performance
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
At the heart of Fireblocks' security lies the MPC protocol, providing robust security while heavily relying on the network due to multiple rounds between your end-user client and Fireblocks. This implies that every enhancement between the end-user and Fireblocks is then multiplied by the number of rounds (when optimizing steps that are called during the MPC process). You can find more information about the MPC protocol here:
* [What is MPC?](https://www.fireblocks.com/what-is-mpc/)
* [Key generation explained](https://ncw-developers.fireblocks.com/docs/mpc-key-generation)
# Boosting Client Performance
During SDK initialization, the client will fetch a few certificates required to make calls to Fireblocks endpoints if it was not previously called. This process may take a few moments; therefore, it is highly suggested to initialize the SDK as early as possible. The initializations don't have to be adjacent to the call to `generateMPCKeys`.
On mobile, it is recommended to use a connection pool and maintain some connections. You can view an example of a connection pool in our [Android demo](https://github.com/fireblocks/android-ncw-demo/blob/6fdf025c7cc42c92bc36be5a97a3bf0b167cea26/app/src/main/java/com/fireblocks/sdkdemo/bl/core/server/Api.kt#L26).
# Create Transaction
Source: https://developers.fireblocks.com/docs/embedded-wallet-create-transaction
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
The transaction process is initiated with the Customer Application, where the end-user initiates the transaction via their user interface. Subsequently, the application must trigger a call to the customer backend, which invokes the Fireblocks API with all the necessary parameters to generate a new transaction. [Learn how to initiate the create transaction API call to Fireblocks](/reference/create-transactions).
Following this, the Fireblocks API will provide a unique transaction ID for the newly established transaction. As the transaction is submitted, its lifecycle begins, and its status updates based on its phase within the system. Fireblocks will dispatch a webhook notification for each transaction status update.
The most important status for this step is the **Pending Signature** status, which signifies that the transaction requires the end-user's signature. The client application needs to be notified for any transaction in the **Pending Signature** status. The most efficient way to achieve this is sending push notification to the client.
Once the application receives a transaction that requires signing, along with the transaction details, including the transaction identifier (**txId**), it should invoke the `signTransaction(txId)` method provided by the EW SDK to initiate the signing process.
It's important to note that the MPC signing process is asynchronous and involves multiple rounds of communication between Fireblocks and the end user. Therefore, the same protocol for managing outgoing and incoming messages should also be applied in this context.
# Example
```typescript TypeScript theme={"system"}
const txArgs: TransactionArguments = {
source: {
type: PeerType.END_USER_WALLET,
walletId: ',
id: '0',
},
destination: {
PeerType.ONE_TIME_ADDRESS,
oneTimeAddress: {
address: ''
}
},
assetId: 'ETH',
amount: '',
note: "My First EW Transaction"
};
const txId = await ew.createTransaction(txArgs);
```
```kotlin Kotlin theme={"system"}
// createOneTimeAddressTransaction
suspend fun createOneTimeAddressTransaction(assetId: String, destAddress: String, amount: String, feeLevel: FeeLevel): Result {
val transactionRequest = TransactionRequest(
assetId = assetId,
source = SourceTransferPeerPath(id = accountId.toString()),
destination = DestinationTransferPeerPath(type = TransferPeerPathType.ONE_TIME_ADDRESS, oneTimeAddress = OneTimeAddress(address = destAddress)),
amount = amount,
feeLevel = feeLevel)
return embeddedWallet.createTransaction(transactionRequest)
}
```
```swift Swift theme={"system"}
//createOneTimeAddressTransaction
//initialize EmbeddedWallet instance
let instance = try initialize()
let request = TransactionRequest(
assetId: assetId,
source: SourceTransferPeerPath(id: String(accountId)),
destination: DestinationTransferPeerPath(type: .oneTimeAddress, oneTimeAddress: OneTimeAddress(address: destAddress)),
amount: amount,
feeLevel: feeLevel
)
return try await instance.createTransaction(transactionRequest: request)
```
The transaction signing itself is done by calling `signTransaction(txId)` EW Core SDK method:
```typescript TypeScript theme={"system"}
// Transaction is in PENDING_SIGNATURE status, can be signed now:
await ewCore.signTransaction(txId);
```
```kotlin Kotlin theme={"system"}
Fireblocks.getInstance(deviceId).signTransaction(txId)
```
```swift Swift theme={"system"}
//Initialize and create the Core SDK instance
let instance = try getCore()
let result = try await instance.signTransaction(txId: transactionId)
```
# Data Objects
Source: https://developers.fireblocks.com/docs/embedded-wallet-data-objects
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
## NcwAssetBalanceUpdate
| Parameter | Type | Description |
| ------------ | ------ | ---------------------------------------------------------------- |
| walletId | string | The wallet's unique ID |
| accountId | number | The ID of the account |
| assetId | string | The ID of the asset |
| total | string | Total balance of the asset |
| pending | string | The cumulative balance of all pending transactions to be cleared |
| staked | string | Staked funds; returned only for DOT |
| frozen | string | Frozen by your workspace's AML policies |
| lockedAmount | string | Funds in outgoing transactions not yet published to the network |
| blockHeight | string | The height (number) of the block of the balance |
| blockHash | string | The hash of the block of the balance |
# Disaster Recovery
Source: https://developers.fireblocks.com/docs/embedded-wallet-disaster-recovery
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
### Note about the DR kit
The Disaster Recovery kit is designed specifically for the key share located exclusively on Fireblocks servers (Key Share #1).
In the event that Fireblocks ceases to exist and the customer wishes to empower the end-user to perform a full key takeover, the customer must establish an endpoint on their own system.
This endpoint will provide Key Share #1 (generated from the Disaster Recovery kit) to the SDK, enabling the reconstruction of the complete private key.
# Overview
The Fireblocks Non-Custodial Wallet (NCW) solution provides a disaster recovery feature to help businesses ensure continuity and minimize disruption to their operations. This feature allows businesses to regenerate the shares that Fireblocks manages, ensuring their operations continue uninterrupted.
The disaster recovery feature includes a toolkit that lets you provide your end users with access to their funds, even if something happens to the original shares.
# Initial Key Generation
Fireblocks NCW employs a 2-of-2 MPC signature scheme. The user's device generates one key share (Key Share #2 in the diagram below), and Fireblocks generates the other (Key Share #1).
Every Fireblocks workspace has a randomly generated master key that functions as a seed. When a new NCW is created, Fireblocks utilizes the master key alongside the freshly generated wallet identifier to calculate the corresponding key share for that specific wallet.
Key Share #1 and Key Share #2 combine to form the fundamental master key for the given NCW.
### Key Reconstruction
MPC technology relies on the absence of a single point in time when the complete master key of the NCW exists in its entirety. The only situation when the entire master key of a NCW consolidates into a complete key is when the end user chooses to initiate the Full Key Takeover process.
# Disaster Recovery Kit Generation
After the customer onboarding process with Fireblocks is complete, Fireblocks generates a recovery kit. This kit comprises the master key of the workspace (seed) and is subsequently transmitted to the customer.
The initiation of this procedure involves the customer generating an RSA4096 private and public key pair. The public component of this pair is shared with Fireblocks. Fireblocks then assembles a kit containing the master key for each workspace (seed).
Then, this kit is encrypted using the provided public key and dispatched to the customer. Fireblocks recommends securely storing this encrypted kit independently from the corresponding RSA private key, preferably on an offline, air-gapped machine.
# Disaster Recovery Process
The customer must set up the [Fireblocks Recovery Tool](https://github.com/fireblocks/fireblocks-key-recovery-tool) on an isolated offline machine. Once the tool is installed and a real-world situation demands its use, the customer must furnish the Fireblocks Recovery Tool with the recovery kit, the associated RSA private key, and the targeted wallet identifiers for recovery.
The Fireblocks Recovery Tool will decrypt the kit, leverage the specified wallet identifier, and generate the corresponding Key Share #1 as the output.
# Events Handler
Source: https://developers.fireblocks.com/docs/embedded-wallet-events-handler
You can choose whether to provide an events handler during the mobile and web Software Development Kits (SDKs) setup for the Fireblocks Embedded Wallet (EW). The events handler activates during different operations within the SDK and keeps you in the loop about significant occurrences, such as key generation, backup and recovery, and transaction signing.
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
The events handler can be tailored to match your application's needs. It can be designed to execute various actions, such as refreshing the user interface, recording events, dispatching notifications, or initiating other behaviors specific to your application's functionality.
The events handler object should be provided when initializing the EW SDK. It must implement the following method (following a defined interface):
`handleEvent(event: Event): void`: The method invoked whenever there's a new event.
```typescript TypeScript theme={"system"}
export interface IEventsHandler {
handleEvent(event: TEvent): void;
}
```
```kotlin Kotlin theme={"system"}
interface FireblocksEventHandler {
/**
* Listens to various Fireblocks events see [Event]. Each event has relevant information.
* In addition, in case of an error we will add the [FireblocksError] with the relevant error code
*/
fun onEvent(event: Event)
}
```
```swift Swift theme={"system"}
public protocol EventHandlerDelegate: AnyObject {
/// Listens to various Fireblocks events [FireblocksEvent]. Each event has relevant information.
/// In addition, in case of an error we will add the FireblocksError with the relevant error code
/// - Parameter event: FireblocksEvent
func onEvent(event: FireblocksEvent)
}
```
# Overview
Source: https://developers.fireblocks.com/docs/embedded-wallet-faq
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
## How do I know which Asset ID to provide when creating a new asset in a non-custodial wallet?
Any asset supported by Fireblocks has a unique identifier. This identifier is used when creating a new asset in a non-custodial wallet (NCW) or vault account via the Fireblocks API.
The Fireblocks NCW supports Bitcoin and any EVM-based network, including ERC-20, ERC-721, and ERC-1155 tokens. For a list of supported assets in Fireblocks, including their unique identifiers, use the [Get Supported Assets](/api-reference/blockchains-&-assets/list-assets-legacy) API endpoint.
## What can and cannot be done with a disabled non-custodial wallet?
A disabled non-custodial wallet (NCW) is available for read-only operations. Once the wallet is disabled [using the API](/reference/enablewallet), none of the following operations are available:
* Signing outgoing transactions
* MPC keys setup
* MPC keys backup
* Full key takeover
* Creating new accounts
* Creating new assets
The following operations still apply to a disabled wallet:
* Incoming transactions will show up in the Fireblocks Console and Transaction History
* Balance updates
* Fetching balance via the Fireblocks API
* AML rules
## Can we import full private keys created outside of Fireblocks?
Fireblocks does not support importing private keys generated outside of our platform, and this decision is rooted in security considerations.
The primary reason behind this limitation is that when a private key exists as a complete, standalone entity, it poses a heightened risk of potential compromise.
In contrast, Fireblocks employs Multi-Party Computation (MPC) technology in our wallets. With MPC, your private key is never in its entirety at any given moment. Instead, it is divided into multiple components that are securely distributed across different entities or parties. This design significantly reduces the risk associated with a single point of compromise.
# Overview
Source: https://developers.fireblocks.com/docs/embedded-wallet-full-key-takeover-export-private-key
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
### Takeover security considerations
While the Full Key Takeover feature provides end users with complete control over their funds, it also introduces some potential security risks. Once the private key is exported, Fireblocks no longer has control over the security of the key material. This means that the end user must take full responsibility for securing the private key and ensuring it is not lost or stolen.
# Overview
The Fireblocks Embedded Wallet solution provides a unique Full Key Takeover feature, which enables end users to export the entire private key. This optional feature makes the solution censorship-resistant since end users always have control over their private key. This is especially useful if Fireblocks or the customer goes out of business or discontinues the service. In this scenario, the end user can still access their funds and transact on the blockchain network.
The Full Key Takeover feature is optional, and not all businesses may want to implement it. For those who do, it is crucial to take all necessary precautions to ensure the security of the private key.
# What happens after the takeover?
Following the takeover, the app developer can decide how the app reacts to the new situation. For example, the app can function as usual afterward, or this action can change the overall end-user experience.
The complete private key that has been exported can be brought into any third-party wallet application that supports private key imports, such as MetaMask for Ethereum and Electrum Wallet for Bitcoin.
# Importing the Exported Keys
The SDKs expose a takeover function. This function returns the keys facilitated by the wallet, which can be ECDSA, EdDSA, or both. The result of the takeover includes extended public and private keys.
## ECDSA Extended Keys
The public and private ECDSA keys can be derived for each asset in the wallet. Our GitHub demos demonstrate how to derive the keys. After you derive them:
* You can import EVM keys to Metamask.
* You can import Bitcoin keys to [Electrum](https://electrum.org/) using the WIF format.
Note there is a slight difference in the exported formats between EVM and Bitcoin. Our demos show how to export the keys into the appropriate formats for Metamask and Electrum.
## EdDSA Extended Keys
There isn't a direct method to derive keys for EdDSA. To use the extended EdDSA keys, you must derive them for each asset and execute blockchain actions through your application.
We have an [Open Source guide](https://github.com/fireblocks/ncw-eddsa-signing) that shows how to use EdDSA keys with each of the assets currently supported by Fireblocks.
# Handling Returning End Users
Source: https://developers.fireblocks.com/docs/embedded-wallet-handling-returning-end-users
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
Let's say that your end user opens your web or mobile app, and you recognize after they log in that they have completed your onboarding (which included MPC key generation) and that their `walletId` is **walletId1** and their `deviceId` is **deviceId1**. What's next?
* Did they previously complete the MPC key generation process with this device?
* Does this device need to run the recovery process now?
* Does this device need to ask to join an existing wallet?
# How to find the status of a user's keys
After you initialize the EW SDK, you can call the `getKeysStatus` function. This function returns a `keyDescriptor`object that contains the status of every ECDSA and EdDSA key associated with that user.
* The **READY** status indicates that the user completed their onboarding and generated their MPC key shares, and their device is ready to perform all MPC-related actions.
* Any other status (e.g., **INITIATED**, **REQUESTED\_SETUP**, **SETUP**, **SETUP\_COMPLETE**) indicates that the user never completed MPC key share generation and that the `generateMPCKeys` function should be called again.
If the `keyDescriptor` object returns as empty, this means the user's mobile device doesn't have a key share and was never in the process of creating a key share for the specified `deviceId`. This indicates that the current device may need to go into recovery mode or join an existing wallet.
# High-Level Architecture
Source: https://developers.fireblocks.com/docs/embedded-wallet-high-level-architecture
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
The Fireblocks Embedded Wallet (EW), formerly Non-Custodial Wallet (NCW), architecture is designed with a minimalistic approach to provide maximum flexibility and ease of use.
Fireblocks provides Android, iOS, and Web SDKs for easily integrating EW functionality into your mobile and web applications. The mobile and web SDKs focus solely on MPC key provisioning, signing, and backup/recovery.
# Integration Components
There are two main components required for integrating the Fireblocks EW feature:
1. **Client-side application:** A mobile or web app with the EW SDK implemented.
2. **Fireblocks:** An EW-enabled workspace.
The current architecture uses a client-only approach, where the SDK communicates directly with Fireblocks APIs — no backend server is required.
# Optional: Backend Proxy Server
In the current architecture, a backend server is not required. However, some customers may choose to implement a backend proxy server for advanced use cases like request validation, rate limiting, or additional business logic.
## Example of EW creation
1. create a wallet (assign) -> `ew.assignWallet()`
* The client SDK calls the `assignWallet()` method, which communicates directly with Fireblocks to create the wallet if it doesn't exist yet.
* The client application can store the wallet ID and continue with other wallet operations.
# Initializing the SDKs
Source: https://developers.fireblocks.com/docs/embedded-wallet-initializing-the-sdks
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Initialize the EW SDK
1. Initialize a new `EmbeddedWallet` SDK instance
2. Call `ew.assignWallet()` - the wallet is created if doesn't exist yet.
When creating a new instance, provide the following parameters:
* **`authClientId`:** Your OAuth client ID configured in the Fireblocks Console
* **`authTokenRetriever`:** Provides a method to fetch the end user’s IDP token (via `getAuthToken()`).
* **`reporting`(optional):** When enabled, the SDK sends error reports to Fireblocks to help diagnose failures.
```typescript TypeScript theme={"system"}
const ew = new EmbeddedWallet({
env: ENV_CONFIG.NCW_SDK_ENV,
logLevel: 'INFO',
logger,
authClientId: ENV_CONFIG.AUTH_CLIENT_ID,
authTokenRetriever: {
getAuthToken: () => this._rootStore.userStore.getAccessToken(),
},
reporting: {
enabled: true,
},
});
const wallet = await ew.assignWallet();
```
```kotlin Kotlin theme={"system"}
val embeddedWallet = EmbeddedWallet(
context,
authClientId = authClientId,
authTokenRetriever = object : AuthTokenRetriever {
override suspend fun getAuthToken(): Result {
val idToken = runBlocking {
SignInUtil.getInstance().getIdTokenBlocking(context)
}
return idToken?.let {
Result.success(it)
} ?: Result.failure(Exception("Failed to get auth token"))
}
},
options = EmbeddedWalletOptions.Builder().build()
)
```
```swift Swift theme={"system"}
//EnvironmentConstants.ewEnv - default environment is .production
let options = EmbeddedWalletOptions(env: EnvironmentConstants.ewEnv, logLevel: .info, logToConsole: true, logNetwork: true, eventHandlerDelegate: nil, reporting: .init(enabled: true))
func initialize() throws -> EmbeddedWallet {
guard instance == nil else {
return instance!
}
return try EmbeddedWallet(authClientId: authClientId, authTokenRetriever: self, options: options)
}
```
# Initialize the EW Core SDK
Generate a `deviceId`. This value is unique per SDK instance.
Each embedded wallet (EW) `walletId` correlates to one or more `deviceId`:
```typescript TypeScript theme={"system"}
// generate a device Id, do it only once per SDK instance
const deviceId = FireblocksNCW.generateDeviceId()
```
```kotlin Kotlin theme={"system"}
// generate a device ID, do it only once per SDK instance
val deviceId = Fireblocks.generateDeviceId()
```
```swift Swift theme={"system"}
// generate a device Id, do it only once per SDK instance
let deviceId = Fireblocks.generateDeviceId()
```
When creating a new SDK instance, provide the following parameters:
* **`deviceId`:** The device ID associated with the end user and the Embedded Wallet.
* **`messagesHandler`:** The [outgoing message handler](https://ncw-developers.fireblocks.com/docs/outgoingincoming-message-handling).
* **`keyStorage`:** The [key storage handler](https://ncw-developers.fireblocks.com/docs/key-handler).
* **`eventsHandler`(optional):** The [events handler](https://ncw-developers.fireblocks.com/docs/event-handler).
## Example
```typescript TypeScript theme={"system"}
const coreOptions: ICoreOptions = {
deviceId,
eventsHandler,
secureStorageProvider,
storageProvider,
};
const ewCore =
getFireblocksNCWInstance(coreOptions.deviceId) ?? (await ew.initializeCore(coreOptions));
```
```kotlin Kotlin theme={"system"}
val coreOptions = CoreOptions.Builder()
.setEventHandler(object : FireblocksEventHandler {
override fun onEvent(event: Event) {
//handle events or just log them if needed
}
}).build()
embeddedWallet.initializeCore(deviceId, keyStorage, coreOptions)
```
```swift Swift theme={"system"}
func initializeCore() throws -> Fireblocks {
guard !deviceId.isEmpty else {
throw CustomError.deviceId
}
//Initialize the EW SDK
let ewInstance = try getInstance()
do {
return try Fireblocks.getInstance(deviceId: deviceId)
} catch {
//keyStorageDelegate is a host app implementation
self.keyStorageDelegate = KeyStorageProvider(deviceId: deviceId)
return try ewInstance.initializeCore(deviceId: deviceId, keyStorage: keyStorageDelegate!)
}
}
```
### Note
All SDKs (JS, Android, iOS) can be initialized with one of the following environments: sandbox, production.
The environment initialization value will affect the selection of the correct root certificate in the SDK. If your tenant resides in the production environment (whether it be testnet or mainnet), then choose production. If you are exploring NCW using the sandbox, then simply choose sandbox.
# Device ID
A `deviceId` is a UUID you generate to uniquely identify a client device. It must be provided when initializing the EW Core SDK. Store the `deviceId` locally and reuse it on every SDK initialization for that device.
When to generate a new `deviceId`:
* New wallet on a new device.
* Adding a new device to an existing wallet.
When to reuse an existing `deviceId`:
* Same device and wallet — retrieve from local storage.
* Recovering a lost device using the last backup.
To recover keys from a lost device, initialize the SDK with the same `deviceId` used during the last backup. You can retrieve this info via `ew.getLatestBackup()`.
### Note
If a wallet is fully initialized with a given `deviceId`, its key share can only be transferred to a new device via the [recovery procedure](https://ncw-developers.fireblocks.com/v5.0/docs/backup-recovery-1#recovery-procedure). After recovery, the original device will no longer be able to participate in MPC operations.
# Fireblocks Embedded Wallets
Source: https://developers.fireblocks.com/docs/embedded-wallet-introduction
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
### **Exciting news!**
Fireblocks acquires [Dynamic](/docs/dynamic-embedded-wallets) , a developer platform powering millions of on-chain user accounts.
While **Fireblocks' Embedded Wallet solution remains fully supported**, you may want to explore Dynamic’s expanded capabilities including seamless embedded wallets creation and user onboarding, flexible authentication, deeper customization, wallet connections and funding integrations across all major chains, as well as simplified fiat on/off ramps, DeFi yield and stablecoin rails. Dynamic gives developers everything needed to embed digital asset experiences seamlessly into any application.
[See it live](https://demo.dynamic.xyz/) and [contact us](https://fireblocks.com/dynamic) for a detailed walkthrough.
## Overview
Fireblocks offers a range of applications for handling digital asset operations and a comprehensive development platform for building your business on the blockchain.
The Fireblocks Embedded Wallet (EW) solution, formerly Non-Custodial Wallet (NCW), allows you to manage digital assets securely and effectively by granting end users full control over their funds or tokens without reliance on a third-party custodian. The Fireblocks EW comes with native web and mobile Software Development Kits (SDKs), which businesses can seamlessly integrate into their existing applications. This integration provides a secure, smooth method for storing and managing digital assets.
Employing multi-party computation (MPC) technology, the Fireblocks EW prioritizes the security and privacy of users' funds. Through MPC, end users maintain control over their private keys and benefit from an uncomplicated backup and recovery process.
The Fireblocks EW can be customized to meet your business needs, preferences, and requirements. The solution equips developers with foundational building blocks for completing key tasks, such as generating keys, signing transactions, and managing wallet balances. These building blocks give developers the flexibility to create custom product flows that integrate with their application's existing design and user interface. This adaptability empowers businesses to differentiate their product offerings, deliver unique experiences for their users, and maintain competitiveness in the market.
The Fireblocks EW doesn't require users to remember long seed phrases or mnemonics. All they have to do is create a passphrase for the recovery process, and they can save it wherever they prefer, like on Google Drive, iCloud, and more.
The Fireblocks EW solution comes with an Application Programming Interface (API) that allows developers to programmatically oversee wallet functionality and enhance their authority over the user experience.
## Why EW?
In the past year, we have seen a change in customers' preference for web3 wallet implementation, moving from the Custodial model, where the company controls its end user's assets, to the Non-Custodial Embedded model, in which the assets are controlled by the end user. This change is driven by three major aspects:
### Regulation and business risk
The Fireblocks EW provides solutions for a variety of regulatory issues applicable to both financial and non-financial enterprises.
Financial entities that provide self-custodial services must adhere to changing regulations. This limits the range of services they can extend to customers and also slows their pace of product development.
For non-financial entities, EW helps reduce the business risk associated with entering the web3 space. Businesses can concentrate on creating attractive product offerings while eliminating the responsibility and business risk associated with being the custodian of their customers' assets.
### User trust
The saying "not your keys, not your coins" encapsulates the idea that investors can't be certain about their cryptocurrency holdings unless they control the keys to their wallets.
In a surprising move in June 2022, the Celsius Network, a major player in crypto lending with assets surpassing \$20 billion, sent shockwaves through the crypto industry by announcing a temporary halt on all withdrawals from its platform.
Later the same year, the dramatic downfall of the FTX crypto exchange had a profound impact on the industry, prompting critical discussions about the nature of speculative investments. This turn of events left a considerable number of frustrated individuals unable to access their invested funds, as FTX temporarily suspended user cash withdrawals, citing liquidity challenges, shortly before declaring bankruptcy.
Presently, the market sentiment strongly favors embedded wallets.
### Retention
Customer retention was one of the initial motivations that drove financial businesses toward exploring embedded wallets. A significant portion of their customers were leaving due to their inability to access Decentralized Finance (DeFi). In response, those customers withdrew funds to engage with the DeFi landscape through external wallets.
By providing these users with an embedded solution with access to Web3 decentralized applications (dApps), these businesses can better retain customers.
# Overview
Source: https://developers.fireblocks.com/docs/embedded-wallet-ios-core-sdk
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# What's new in 2.9.14
* Improved error handling and logging with console output control.
# What's new in 2.9.8
* Improve logging capabilities by writing logs to the same file without additional folders.
# What's new in 2.9.2
* Added validations to the RPC messages received
# What's new in 2.9.1
* Introduced additional logging
# What's new in 2.9.0
Major Enhancements:
* **Join Device Flow Stability**: Fixed a rare crash that could occur when stopping the Join Device Flow, improving overall reliability.
* **SDK Logging**: Enhanced SDK logging to provide more detailed and structured logs, making it easier to debug and track issues.
* **Error Handling**: Standardized error handling across all platforms, ensuring consistent behavior and improved error reporting. Also added `FireblocksError` `MaxDevicesPerWalletReached` (111) when the maximum number of devices in a wallet is reached while trying to add a new device. This ensures users are informed about the limit and can take appropriate actions.
# What's new in 2.8.2
* Enhanced the MPC ceremony process to improve overall robustness and reliability.
# What's new in 2.8.1
* Introduced additional logging to provide better insights and troubleshooting.
# What's new in 2.8.0
Major Enhancements:
* Enhanced Performance Optimization:
* Improved execution speed and reduced latency for high-demand operations.
* Refined memory management for better stability and efficiency.
* Advanced Data Processing:
* Optimized algorithms for reduced computational overhead.
New Features:
* Improved Error Handling:
* More detailed error messages and diagnostics to facilitate quicker debugging.
* Added support for custom error handlers and logging mechanisms.
Bug Fixes:
* Addressed stability issues reported in previous versions.
# What's new in 2.7.1
* Resolved an issue when trying to sign transactions in the main thread.
# What's new in 2.7.0
In version 2.7.0, we've introduced a few enhancements:
* Improved log collection.
* Resolved an issue when trying to sign a transaction that has failed or will fail before it can even be signed.
* Improved error visibility: wrong passphrase in the recovery process is now explicitly mentioned in the returned error as `WRONG_RECOVERY_PASSPHRASE` (603)
# What's new in 2.6.0
In version 2.6.0, we've introduced a few major enhancements.
1. Direct reporting of errors to Fireblocks. This will ease the process of supporting and debugging issues in the future. More information can be found [here](https://ncw-developers.fireblocks.com/docs/ncw-sdk-telemetry-collection).
2. Our MPC ceremony processes have been enhanced for greater robustness. MPC messages will now undergo multiple retry attempts before failing.
3. Unexpected device errors, as seen in [Common Errors](/reference/common-errors) will now result in the expected messaging, and not in a timeout.
4. You can now dynamically extend wallets! Expand the range of algorithms available in a wallet by adding, for instance, EdDSA alongside ECDSA. Learn more [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms).
# What's new in v2.5.1
We introduced several enhancements and additions to the SDK functionality:
1. **Canceling Transactions**: Added a new function called `stopSignTransaction` to the SDK interfaces. This function enables your app to cancel transactions the end-user initiated for signing.
2. **Improved Error Handling**: Enhanced error handling for quick transaction signing failures caused by invalid messages from the backend, such as schema changes in the response. This improvement helps identify and resolve issues faster.
3. **MPC Key Generation**: Addressed a few edge cases in the MPC Key Generation process that could potentially result in key generation failures.
4. **EdDSA Signing Performance**: Drastically improved EdDSA Blockchains *signing* speed.
5. **Logging**: Added a new parameter, logToConsole, to FireblocksOptions. This parameter allows you to push logs to the Xcode console when running the host app, which can be helpful for debugging purposes.
6. **Minor Interface Changes**: There were some small changes to the SDK interface. Please read the guidelines in the following section for more details.
## Upgrade guidelines
1. `GenerateMPCKeys` Behavior Change: In case of an exception, GenerateMPCKeys now returns a Set containing keys and their corresponding statuses, instead of an empty Set. You will need to check that all keys have a "Ready" status to ensure successful setup. Please see the following example for [clarification](https://github.com/fireblocks/ncw-ios-demo/commit/5a1f3318974a28aee7cd9cbf92406cf31f2ebb0a#diff-3ae2d84b992c8e9c9fd4f787b4c0fa44c9e601083e7d1ee0892acd8fb913ef14L90).
2. Optional `KeyRecovery` Properties: All KeyRecovery properties are now optional. This may affect your code if you were previously relying on default values. See the following example for a similar [code change](https://github.com/fireblocks/ncw-ios-demo/commit/5a1f3318974a28aee7cd9cbf92406cf31f2ebb0a#diff-3ae2d84b992c8e9c9fd4f787b4c0fa44c9e601083e7d1ee0892acd8fb913ef14L162).
3. Optional `KeyDescriptor` Properties: All KeyDescriptor properties are now optional. This may affect your code if you were previously relying on default values. See the following example for a similar [code change](https://github.com/fireblocks/ncw-ios-demo/commit/5a1f3318974a28aee7cd9cbf92406cf31f2ebb0a#diff-3ae2d84b992c8e9c9fd4f787b4c0fa44c9e601083e7d1ee0892acd8fb913ef14L162).
# What's new in v2.4.0
We expanded the capabilities of the NCW SDK to support Solana and Algorand, now including the EdDSA algorithm alongside our existing ECDSA support. This enhancement enables a single wallet to seamlessly interact with Bitcoin, various EVMs, and Solana.
More information about the supported NCW networks may be found [here](https://ncw-developers.fireblocks.com/docs/supported-networks) .
Additionally, we're excited to announce that support for more blockchains, including Stellar, is on the horizon. Stay tuned for further updates!
## Upgrade guidelines
To successfully utilize the generateMPCKeys function with MPC\_EDDSA\_ED25519, your workspace must support EdDSA. Learn more about supporting multiple algorithms within a single wallet [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms).
# What's new in v2.3.2
We resolved a bug that occurred during transaction signing, leading to intermittent failures after a few transactions. The root cause was identified within the MPC process, where the SDK did not handle a specific use case that emerged during performance improvement efforts.
It's important to note that although a transaction may have failed initially, it was possible to retry the transaction signing with success on subsequent attempts.
# What's new in v2.3.1
We addressed and resolved a potential race condition that could occur during the `generateMPCKeys` process. This fix ensures that the operation no longer fails due to the identified race condition.
# What's new in v2.3.0
We made significant performance improvements in key generation and transactions signing.
For additional tips on enhancing overall performance, refer to our documentation [here](https://ncw-developers.fireblocks.com/docs/boosting-ncw-client-performance).
# What's new in v2.2.0
We added the ability to work with multiple devices in a single wallet.
For more information about multiple devices, refer to our documentation [here](https://ncw-developers.fireblocks.com/docs/multiple-devices).
# What's new in v2.1
We added a safer backup and recovery mechanism.
## Breaking change
We made a significant breakthrough since the following two functions in the interface will receive different parameters:
* `backupKeys`
* `recoverKeys`
You can find details about the implementation in our [ios-ncw-demo repo](https://github.com/fireblocks/ncw-ios-demo) and more information about the backup procedure [here](https://ncw-developers.fireblocks.com/v4.0/docs/backup-recovery).
## Upgrade guidelines
When upgrading to version 2.1 and later, you should require the user to run another backup procedure so that the new encrypted backup share on the Fireblocks servers will be associated with a `passphraseId`.
# Embedded Wallet SDK
Source: https://developers.fireblocks.com/docs/embedded-wallet-ios-sdk
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# What's new in 1.0.10
* Improved authentication token handling.
* Added comprehensive network logging for both success and error responses
* Enhanced error handling for network logging operations
* Improved debugging capabilities with better network request/response visibility
# What's new in 1.0.3
* Enhanced Logging: Logs are now written to a single, unified file (within the NCW Core log structure), ensuring a clearer, sequential flow of events. This improves traceability and debugging.
# Overview
Source: https://developers.fireblocks.com/docs/embedded-wallet-js-core-sdk
https://www.npmjs.com/package/@fireblocks/ncw-js-sdk
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# What's new in 12.5.6
* Added new validation to `IMessagesHandler` responses to prevent crashes from non-conforming or malformed data.
# What's new in 12.5.5
* Fixed an issue where `STARTED` event was fired twice in the case of multiple devices for the given wallet.
* Fixed an issue where reporting of errors with empty strings was missing.
* Added a new error code, `INCOMPLETE_BACKUP` (706) when trying to backup keys, while one or more of the required algorithms is missing for backup.
# What's new in 12.5.3
* Fixed an issue where timeout was not properly stopping internal polling processes, ensuring more reliable performance.
* Added a new error code, `FireblocksError` `MaxDevicesPerWalletReached` (111) when the maximum number of devices in a wallet is reached while trying to add a new device. This ensures users are informed about the limit and can take appropriate actions.
# What's new in 12.5.2
Enhanced the robustness of event dispatching to handle cases where client callbacks throw exceptions
# What's new in 12.5.1
Resolved an issue when trying to re-use an instance after calling `dispose`
# What's new in 12.5.0
* Resolved a minor issue in the MPC code.
## Breaking change
Version 12.5.0 introduces a small breaking change:
* It is not possible anymore to create **multiple instances** of the SDK **for the same device id**.
* If trying to do it, a `FireblocksError` exception will be thrown with error code `INSTANCE_ALREADY_INITIALIZED (109)`
* Instead, you must re-use the instance you already created.
* This is done by calling `getFireblocksNCWInstance(deviceId)` before creating an instance with `FireblocksNCWFactory(options)`.
We recommend visiting our [ncw-web-demo repo](https://github.com/fireblocks/ncw-web-demo) to understand how to adapt your app to the SDK changes. Specifically, you can always jump to this [commit](https://github.com/fireblocks/ncw-web-demo/pull/35/files) and see the changes we added to the web demo.
# What's new in 12.4.1
* Resolved an issue when dealing with multiple concurrent calls to `generateMPCKeys`
* Improved error visibility: wrong passphrase in the recovery process is now explicitly mentioned in the returned error as `WRONG_RECOVERY_PASSPHRASE (603)`
# What's new in 12.3.1
* Resolved an issue when trying to sign a transaction that has failed or will fail before it can even be signed.
# What's new in 12.2.1
* Resolved an issue in the MPC ceremony process that previously caused exceptions in cases of poor connectivity.
* Enhanced the robustness of the MPC ceremony process by extending the retry mechanism.
# What's new in 12.2.0
In version 12.2.0, we've introduced a few major enhancements.
* Direct reporting of errors to Fireblocks. This will ease the process of supporting and debugging issues in the future. More information can be found [here](https://ncw-developers.fireblocks.com/docs/ncw-sdk-telemetry-collection).
* Our MPC ceremony processes have been enhanced for greater robustness. MPC messages will now undergo multiple retry attempts before failing.
* You can now dynamically extend wallets! Expand the range of algorithms available in a wallet by adding, for instance, EdDSA alongside ECDSA. Learn more [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms).
# What's new in 12.1.0
In version 12.1.0, we've expanded the capabilities of the NCW SDK to support Solana and Algorand, now including the EdDSA algorithm alongside our existing ECDSA support. This enhancement enables a single wallet to seamlessly interact with Bitcoin, various EVMs, and Solana.
More information about the supported NCW networks may be found [here](https://ncw-developers.fireblocks.com/docs/supported-networks) .
Additionally, we're excited to announce that support for more blockchains, including Stellar, is on the horizon. Stay tuned for further updates!
## Upgrade guidelines
To successfully utilize the generateMPCKeys function with MPC\_EDDSA\_ED25519, it's essential that your workspace supports EdDSA. Learn more about supporting multiple algorithms within a single wallet [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms).
# What's new in 12.0.0
In version 12.0.0, we introduced a more structured approach to error handling in our JavaScript SDK. With the inclusion of an exported `FireblocksError` class, developers can now access detailed error information using the new **FireblocksError.message** and **FireblocksError.key** properties.
If issues arise during SDK activities, these structured error responses aim to provide you with better insights, enabling efficient debugging or informed inquiries to our support team.
## Upgrade guidelines
If your previous code relied on specific error responses from the NCW SDK, incorporating these new error codes may improve the accuracy of your try/catch flows. Refer to this [PR](https://github.com/fireblocks/ncw-web-demo/pull/26/files) to see how we handled the SDK upgrade in our web demo.
# What's new in 11.0.2
In version 11.0.2, fixed a bug that may occur during a call to `generateMPCKeys`.
# What's new in 11.0.1
In version 11.0.1, we have implemented significant performance improvements in key generation and transactions. For additional tips on enhancing overall performance, refer to our documentation [here](https://ncw-developers.fireblocks.com/docs/boosting-ncw-client-performance).
# What's new in 11.0.0
In version 11.0.0, we upgraded some of our JavaScript SDK infrastructure in preparation for upcoming versions, which include performance improvements in MPC key creation and transactions.
We also added these features and made these changes:
* The SDK logger utility lets you choose to keep historical data of all NCW SDK activity.
* The fetch log utility can now fetch SDK logs from your app.
* Reduced package size for faster loading times.
## Breaking change
Version 11.0.0 introduces a breaking change since we renamed the following interfaces:
* Instead of initializing via the `FireblocksNCW.initialize(options)` class function, call `FireblocksNCWFactory(options)`.
* Do not declare variables with type `FireblocksNCW` but refer to it via the `IFireblocksNCW` interface.
* Instead of initializing the logger via the `new ConsoleLogger()` function, call `ConsoleLoggerFactory()`.
* Instead of calling the `FireblocksNCW.version` function, call `version` directly.
* Instead of calling the `FireblocksNCW.generateDeviceId()` function, call `generateDeviceId()` directly.
We recommend visiting our [ncw-web-demo repo](https://github.com/fireblocks/ncw-web-demo) to understand how to adapt your app to the SDK changes. Specifically, you can always jump to this [commit](https://github.com/fireblocks/ncw-web-demo/pull/22/files#diff-bf5c0e301a4690ed37b7b89cd8479ddfd3660cb4e567b446cb12b7852c3f8f27R27) and see the changes we added to the web demo.
# What's new in 10.0.7
In version 10.0.7, we added the ability to work with multiple devices in a single wallet. You can find more information about implementing multiple devices [here](https://ncw-developers.fireblocks.com/docs/multiple-devices).
# What's new in 10.0
In version 10.0, we added a safer backup and recovery mechanism.
## Breaking change
Version 10.0 introduces a breaking change since the following two functions in the interface will receive different parameters:
* `backupKeys`
* `recoverKeys`
You can find more details about the implementation in our [ncw-web-demo repo](https://github.com/fireblocks/ncw-web-demo) and the backup procedure [here](https://ncw-developers.fireblocks.com/v4.0/docs/backup-recovery).
## Upgrade guidelines
When upgrading to version 10.0 and later, you should require the user to run another backup procedure so that the new encrypted backup share on the Fireblocks servers will be associated with a `passphraseId`.
# Embedded Wallet SDK
Source: https://developers.fireblocks.com/docs/embedded-wallet-js-sdk
https://www.npmjs.com/package/@fireblocks/embedded-wallet-sdk
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Key Storage
Source: https://developers.fireblocks.com/docs/embedded-wallet-key-storage
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
The Fireblocks Embedded Wallet (EW) feature offers a flexible key storage mechanism that allows you to customize the implementation of key loading and saving processes outside the mobile Software Development Kit (SDK) itself.
This approach allows you to incorporate various security measures, such as mobile enclaves, biometric authentication, and two-factor authentication (2FA). The EW SDK is agnostic to the precise methodology employed for key storage, with the implementation being supplied to the SDK during the initialization process.
# Web vs. Mobile
When integrating with the EW Web SDK, the key storage approach differs from that of Android and iOS. Unlike these platforms, where storage mechanisms are provided, JavaScript applications can run in various environments such as web browsers, Node.js, or Electron. This variability means you can't rely on platform-specific storage capabilities. Instead, customers using our EW Web SDK are tasked with supplying a suitable storage solution.
Our SDK incorporates a secure storage feature involving a process of *locking* and *unlocking*. Before any data retrieval or storage operation, the SDK triggers the *unlock* function, and just before finalizing the operation, it invokes the *lock* function.
Distinct from Android and iOS paradigms involving data removal or targeted checks, the web-based approach revolves around managing data stored and loaded with each SDK usage.
One option for key storage involves encrypting the secret key material with a password and storing it in the local browser storage. However, this implies that users switching to a different machine would lose access to this data. Alternatively, storing the encrypted data on the server allocates each user a secure section on the server, accessible post-login.
The key storage provider has to be provided upon SDK initialization and must implement the following interface:
```typescript TypeScript theme={"system"}
export interface IStorageProvider {
get(key: string): Promise;
set(key: string, data: string): Promise;
}
export interface ISecureStorageProvider extends IStorageProvider {
getAccess(): Promise;
}
```
```kotlin Kotlin theme={"system"}
interface FireblocksKeyStorage {
/**
* Store raw keys data
* @param keys map of keyId and raw [ByteArray] of data.
* @param callback result is a map of store keys operation result
*/
fun store(keys: Map, callback: (result: Map) -> Unit)
/**
* Load raw keys data
* @param keyIds a set of key ids to load
* @param callback result is a map of key id and raw key data as [ByteArray]
*/
fun load(keyIds: Set, callback: (result: Map) -> Unit)
fun remove(keyIds: Set, callback: (result: Map) -> Unit)
fun contains(keyIds: Set, callback: (result: Map) -> Unit)
}
```
```swift Swift theme={"system"}
public protocol KeyStorageDelegate: AnyObject {
/// Store raw keys data
/// - Parameters:
/// - keys: map of keyId and Data
/// - callback: result is a map of store keys and operation result
func store(keys: [String: Data], callback: @escaping ([String: Bool]) -> ())
/// Load raw keys data
/// - Parameters:
/// - keyIds: a set of key ids to load
/// - callback: result is a map of key id and raw key data as Data
func load(keyIds: Set, callback: @escaping ([String: Data]) -> ())
/// Remove raw data from your storage
/// - Parameter keyId: key id to remove
func remove(keyId: String)
/// Check if Set of key ids is stored on your storage
/// - Parameters:
/// - keyIds: a set of key ids to verify
/// - callback: result is a map of keys and operation result
func contains(keyIds: Set, callback: @escaping ([String : Bool]) -> ())
```
* `store`/`set`: Called to store the MPC key share on the end-user device
* `load`/`get`: Called to get the MPC key share from the end-user device
* `remove` (**Android and iOS only**): Called to remove the MPC key share from the user device
* `contains` (**Android and iOS only**): Called to check if the set of MPC key shares is stored on the device
* `getAccess` (**Web only**): Called to lock or unlock the secure key storage upon every NCW SDK execution
# Embedded Wallet Keys Explained
Source: https://developers.fireblocks.com/docs/embedded-wallet-keys-explained
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
Embedded wallets reside in a Fireblocks workspace that includes custodial Vault Accounts assigned to the customer.
Each embedded wallet has its separate keys. Also, the workspace includes one master key to serve the customer's vault accounts (not connected to the end user wallets).
Fireblocks embedded wallets use a 2-of-2 MPC signature scheme. One key share resides in an Intel SGX-enabled server managed by Fireblocks, and the other resides on the end user's device.
# Structure
The Fireblocks workspace can include an unlimited number of embedded wallets and an unlimited number of wallet accounts inside each embedded wallet. Each wallet account can hold as many asset wallets as you need. However, you can only have one type of wallet asset per wallet account.
You can also use our non-custodial embedded wallets in parallel with self-custodial wallets. One workspace can support both structures.
# Secret key management and wallet derivation
The derivation for non-custodial embedded wallets is almost the same as for self-custodial wallets. Each asset in an embedded wallet is derived according to the following structure:
**`m/purpose/coinType/account/change/index`**, where:
* **m** is the master private key
* **purpose** is the derivation standard (BIP-44 in our example)
* **coinType** is the unique identifier of an asset (0 for BTC, 60 for ETH, etc.)
* **account** is the vault account ID
* **change** is always 0
* **index** is the address index (always 0 except for UTXO-based assets)
### Note
In Non-Custodial Wallets, Bitcoin wallets can only have one deposit address per account, unlike self-custodial wallets that can have more that one deposit address within the same account.
This means that for any account, the derivation path for the BTC asset in it will always be `m/44/0/accountId/0/0`.
# Unsure about which custody model is best for you?
Read our [Guide to Digital Asset Wallets and Service Providers](https://www.fireblocks.com/a-guide-to-digital-asset-wallets-and-service-providers) for insights into evaluating digital asset wallets and service providers for your business.
# MPC Key Generation
Source: https://developers.fireblocks.com/docs/embedded-wallet-mpc-key-generation
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
The creation of multi-party computation (MPC) keys involves a dynamic, step-by-step procedure that involves several rounds of communication between the end user's device and Fireblocks. This process operates asynchronously, meaning that it takes place over multiple interactions rather than a single continuous operation.
# Key Generation
Let's break down the process for better clarity:
1. Your application calls the `generateMPCKeys` method in our SDK to initiate the generation of MPC keys. This step triggers the process and sets everything in motion.
2. `generateMPCKeys` can be called with the algorithms you wish to create under the wallet. Currently, it is `MPC_EDDSA_ED25519` or `MPC_ECDSA_SECP256K1`. More information about it can be found [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms)
3. The crucial part of the whole process lies in the communication rounds between the end user's device and Fireblocks. These rounds are essential for securely creating the keys.
4. The process unfolds repeatedly, with each round building upon the previous one. Your application exchange messages, refining the communication until the process is complete.
5. After successfully generating MPC keys, the final step involves securely storing these keys to ensure protection for your end users. You can tailor this process to your preferences through various options, such as mobile enclaves, biometric authentication, two-factor authentication (2FA), and more. You retain total control over the implementation that best suits your security needs.
# Key Generation
First, create a new EW using the EW SDK:
```typescript TypeScript theme={"system"}
// Assign (or create) the EW wallet
const wallet = await ew.assignWallet();
```
```kotlin Kotlin theme={"system"}
embeddedWallet.assignWallet()
```
```kotlin Kotlin theme={"system"}
embeddedWallet.assignWallet()
```
Next, create a new account in the newly created EW (needed once)
```typescript TypeScript theme={"system"}
// Create account under wallet
const newAccount = await ew.createAccount();
```
```kotlin Kotlin theme={"system"}
embeddedWallet.createAccount()
```
```kotlin Kotlin theme={"system"}
embeddedWallet.createAccount()
```
Lastly, start the MPC key generation from your application. You can add the below to your customer application.
```typescript TypeScript theme={"system"}
import { IKeyDescriptor } from "@fireblocks/ncw-js-sdk";
// Generate MPC Keys
const algorithms = new Set(["MPC_CMP_ECDSA_SECP256K1"]);
const keyDescriptor: Set = await ewCore.generateMPCKeys(algorithms);
```
```kotlin Kotlin theme={"system"}
val algorithms = setOf(Algorithm.MPC_ECDSA_SECP256K1)
fireblocksSdk.generateMPCKeys(algorithms = algorithms){ result ->
Timber.i("generateMPCKeys result: $result")
}
```
```swift Swift theme={"system"}
func generateKeys(algorithms: Set) async throws -> Set {
//Initialize and create the Core SDK instance
let instance = try getCore()
return try await instance.generateMPCKeys(algorithms: algorithms)
}
```
If the device storage has generated keys once (e.g., the EW Core SDK already initialized with a specific `deviceId` that was called successfully with the `generateMPCKeys` function), you do not need to call this function. This scenario relates to a situation in which an end-user is logging in to an already set-up device.
### Note
If you use a `deviceId` or `walletId` that previously had keys generated—but those keys are no longer present on the current device (e.g., after an app reinstall or using a new browser)—calling `generateMPCKeys` will fail. Fireblocks only allows key generation once per walletId–deviceId pair. In this case, you must recover the key share using the `recoverKeys` method.
# Multi-Device Implementation
Source: https://developers.fireblocks.com/docs/embedded-wallet-multi-device-implementation
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
### Device number limit
To help maintain a wallet performance, each wallet is limited to 10 devices. If you reach this limit, you can disable old or unused devices using this [endpoint](/reference/enabledevice).
# Overview
The Fireblocks Embedded Wallet (EW) solution allows multiple devices to perform actions using the same wallet, such as signing transactions and running takeovers. This lets you support a multi-device, multi-platform seamless digital experience and enables an end user to use their account on any of their devices.
## Definitions
Let us define the following two types of devices for a multiple-device wallet:
* **Requesting device:** A new device that wants to join the wallet.
* **Approving device:** The device in the wallet that can already run operations, like signing transactions; for example, the device you generated key shares with.
## Supported functions
Two functions in the EW SDK interface support multiple devices:
* **`requestJoinExistingWallet`:** A function in the requesting device that receives a handler that emits events according to the progression of the process. Specifically, the function emits `requestId`, the UUID used to approve the request.
* **`approveJoinWalletRequest`:** A function in the approving device that receives a `requestId` and will allow the processing of the approval to start.
# Implementing multiple devices
## Requesting to join a wallet
First, using your authentication solution, verify that the end user's requesting device is trying to join a wallet that has already generated key shares and that that device is currently associated with such a wallet.
### Note
You can check on the device's key status via the EW SDK by calling `getKeysStatus()` to verify that the keys are in the `READY` status.
Next, initialize the Fireblocks SDK through the requesting device with a new `deviceId`. Make sure you know which wallet you want to associate this device with, according to the authentication your end user went through.
Then, use the requesting device to call the `requestJoinExistingWallet` function with a handler. This handler emits events that notify your application of the progress of the `requestJoinExistingWallet` procedure.
```javascript Web theme={"system"}
await ewCore.requestJoinExistingWallet({
onRequestId(requestId) {
// your code here
set((state) => ({ ...state, addDeviceRequestId: requestId }));
},
onProvisionerFound() { // -> optional
// your code here
},
});
```
```kotlin Android theme={"system"}
val joinWalletHandler: FireblocksJoinWalletHandler = object : FireblocksJoinWalletHandler {
override fun onRequestId(requestId: String) {
// use this requestId to approve the request from the source device, e.g. using a QR code or a push notification
// the requestId will be used in approveJoinWalletRequest method
}
override fun onProvisionerFound() {
// use this indication the provisioner device was found and the join process continues, e.g. show a spinner/progress bar
}
}
Fireblocks.getInstance(deviceId).requestJoinExistingWallet(joinWalletHandler) { result ->
Timber.i("joinExistingWallet result: $result")
}
```
```swift iOS theme={"system"}
//Initialize and create the Core SDK instance
let instance = try getCore()
//joinWalletHandler: FireblocksJoinWalletHandler
let result = try await instance.requestJoinExistingWallet(joinWalletHandler: joinWalletHandler)
```
After you call the `requestJoinExistingWallet` function, it yields a `requestId` in three ways:
1. Via the events handler submitted with the EW SDK's initialization.
2. Via the `joinWalletResolver` callback associated with the function itself.
3. Via a webhook notification. For example:
```javascript Web (JavaScript) theme={"system"}
{
type: "NCW_ADD_DEVICE_SETUP_REQUESTED",
tenantId: string,
timestamp: number,
data: {
walletId: string,
deviceId: string,
requestId: string,
},
};
```
## Approving a new device
The approving device calls the `approveJoinWalletRequest` function with the corresponding `requestId` to approve or reject the new device.
```javascript Web (JavaScript) theme={"system"}
const result = await ewCore.approveJoinWalletRequest(requestId);
console.log("approveJoinWallet result:", result);
```
```kotlin Android (Kotlin) theme={"system"}
Fireblocks.getInstance(deviceId).approveJoinWalletRequest(requestId) { result ->
Timber.i("approveJoinWallet result: $result")
}
```
```swift iOS theme={"system"}
//Initialize and create the Core SDK instance
let instance = try getCore()
return try await instance.approveJoinWalletRequest(requestId: requestId)
```
When a new device is approved, the process of adding the requesting device begins and takes a few seconds to send multiple MPC messages.
On the existing device, we will then see additional MPC messages until the key material is ready to be stored.
Eventually, the requesting device will join the wallet and be able to run all MPC-related actions.
# Multiple device scenarios
In a multi-device scenario, all devices see the same balance, can initiate and sign transactions, approve adding a new device to the wallet, or perform any other action, such as takeover.
When performing a transaction, once a device is approved and your wallet has multiple devices, you can create a transaction from one device and sign that transaction from any other device associated with the wallet.
However, remember that only one device in a wallet can sign a specific transaction. If multiple devices "race" to sign the same transaction, only one device will succeed, and the other devices' sign transaction command will eventually time out.
# Multiple device events
The `approveJoinWalletRequest` and `requestJoinExistingWallet` functions can yield the following events emitted by the events handler.
## Approving device
* PROVISION\_INITIATED
* PROVISION\_ADD\_DEVICE\_SETUP\_REQUESTED
* PROVISION\_KEYS\_SETUP\_STARTED
* PROVISION\_SETUP\_STARTED
* PROVISION\_SETUP\_COMPLETED
* STOPPED
* TIMEOUT
## Requesting device
* JOIN\_INITIATED
* ADD\_DEVICE\_SETUP\_REQUESTED
* PROVISIONER\_FOUND
* STOPPED
* TIMEOUT
# Troubleshooting
## Request timeout
There is a three-minute timeout before the Fireblocks and EW SDKs terminate the `requestJoinExistingWallet` and `approveJoinWalletRequest` functions. This means that you should guide the user to open the existing device to approve the action before they initiate this flow. However, you can call the `stopJoinWallet` function if you want or need to implement a different timeout configuration, or simply kill the process. Then, you can retry the process by calling the appropriate function again.
## Procedure didn't work
If a procedure with a `deviceId` did not work as expected, try to join the wallet with a new `deviceId`. There is no limit to the number of new devices an approving device can approve.
# Multiple devices FAQ
## What type of devices are supported?
The end user can add any combination of devices supported by our SDKs.
## How many devices can an end user add to a single wallet?
An end user can add up to 10 devices to a single wallet.
## How do I implement multiple devices for my app?
You can achieve this in various ways, depending on your implementation. Below you can view an example flow of a requesting device and an example flow of an approving device.
### Requesting device example
The end user enters the app on a new device after passing the authorization stage. The app recognizes that the user has a wallet with keys on another device and that the current device doesn't contain any keys. The app then presents the user with the following options:
1. Add a new device; if the user has another device, they can use it to onboard the new device.
2. Recover a device if the user does not have another device.
3. Skip, which continues to the app without creating a wallet.
### Approving device example
Depending on the guidance the user receives from the requesting device, they should typically open an approving device's Settings page and initiate the Add New Device flow.
## Is adding a device always tied to the device onboarding flow?
No. Adding a device can also be initiated anywhere within the app based on the app's objectives. For example, the Add New Device flow can be triggered when the user enters a specific part of the app, when they perform a specific action within the app, or initiated directly from the app's Settings page.
# Setup
Source: https://developers.fireblocks.com/docs/embedded-wallet-setup
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
Fireblocks no longer supports the **Reactive Native SDK** and **Flutter SDK**.
# Web SDK Installation
Install the Fireblocks "EW SDK" and "EW Core SDK" using `npm`:
```bash Shell theme={"system"}
npm i @fireblocks/ncw-js-sdk
npm i @fireblocks/embedded-wallet-sdk
```
Or `yarn`:
```bash Shell theme={"system"}
yarn add @fireblocks/ncw-js-sdk
yarn add @fireblocks/embedded-wallet-sdk
```
You can find the web demo code [here](https://github.com/fireblocks/ncw-web-demo-v2).
# Android SDK Installation
First, add our maven repository configuration to your `settings.gradle` file:
```groovy Gradle theme={"system"}
repositories {
maven {
url "https://maven.fireblocks.io/android-sdk/maven"
name = "android-sdk"
credentials(HttpHeaderCredentials) {
name = "Deploy-Token"
value = "-fU8ijmuPohHaqDBgpaT"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
```
Then, add the Fireblocks SDKs dependency to your application's `build.gradle` file using the most updated bom version:
```groovy Gradle theme={"system"}
implementation "com.fireblocks.sdk:bom:1.0.2"
implementation "com.fireblocks.sdk:ew"
implementation "com.fireblocks.sdk:ncw"
```
* You can find the Android Demo code [here](https://github.com/fireblocks/android-ncw-demo).
* You can find the Android SDKs documentation [here](https://fireblocks.github.io/ncw-docs/android/).
# iOS SDK Installation
First, in your iOS Project, add the [Fireblocks Embedded Wallet SDK](https://github.com/fireblocks/ew-ios-sdk) package:
Now add the the [Fireblocks NCW iOS SDK](https://github.com/fireblocks/ncw-ios-sdk) package:
Then, after the SDK packages are added to the project, you should see them under the **Package Dependencies** section in the Project Navigator:
Lastly, import the SDK libraries:
```swift Swift theme={"system"}
import EmbeddedWalletSDK
import FireblocksSDK
```
* You can find the iOS demo code [here](https://github.com/fireblocks/ncw-ios-demo).
* You can find the iOS SDKs Docs [here](https://fireblocks.github.io/ncw-docs/ios/).
# Using ECDSA and EdDSA
Source: https://developers.fireblocks.com/docs/embedded-wallet-using-ecdsa-and-eddsa
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
Fireblocks workspaces support non-custodial wallets with two algorithms: `MPC_ECDSA_SECP256K1` (ECDSA) and `MPC_EDDSA_ED25519` (EdDSA).
Each algorithm allows the addition of different assets. For example, generating an ECDSA key set will let you add asset such as Bitcoin, or Ethereum, while generating an EdDSA key set will let you add Solana, or Algorand, for example.
A wallet can meet one of the following states:
* Generate ECDSA keys only.
* Generate EdDSA keys only.
* Generate ECDSA & EdDSA keys.
* Add EdDSA keys to an already existing ECDSA key set.
* Add ECDSA keys to an already existing EdDSA key set.
### Version Compatibility
To fully utilize an expandable wallet with your preferred algorithms, ensure that you are using Web SDK version >=12.2.0 and Mobile SDK version >=2.6.0.
# Extending Your Key Set
### Post Extension Backup
It is **crucial** to perform **another** backup after you have extended your key set. Please refer to the first point below, and make sure you follow the instructions there.
Should you face a situation where you already have an existing key set, you can generate another key set for the different algorithm, as shown in [MPC Key Generation](doc:mpc-key-generation).
Assuming you have generated an ECDSA key set, you should now trigger the key generation function with the EdDSA algorithm (`MPC_EDDSA_ED25519`) only.
In cases of extending your key set, you are required to make sure you have performed the same flows you have implemented for your already existing key set, that is:
1. Backup and Recovery, as seen [here](https://ncw-developers.fireblocks.com/docs/backup-recovery-1). Make sure you back up the new key set after generating the keys. By default, backup enforcement is enabled and you won't be able to add assets to your newly extended key set (e.g. Solana for EdDSA) until you have backed up your key set.
2. Multiple Devices, as seen [here](https://ncw-developers.fireblocks.com/docs/multiple-devices). In case there are multiple devices for the same wallet, and one of them has extended its key set, you are required to run the join wallet operation again, for your newly extended key set.
# Retrieving the Device Keys Status
The [MPC Keys Generation ](https://ncw-developers.fireblocks.com/docs/mpc-key-generation#key-generation)process is a multi-step operation that can fail or stop in the middle for various reasons, such as a network error or the end user leaving the application midway through the process. If a failure or stoppage occurs, you end up with a device and a `deviceId` that cannot be used until you complete the MPC key generation process.
To check the current key status for a device, there are two methods you can use:
1. Call the `getKeysStatus` function on the web SDK or mobile SDK. When `keyStatus` returns **READY**, the MPC key generation process has been completed. Note that **READY** is the only valid final status for the key.
2. Call the [Get device key setup state endpoint](/reference/getdevicesetupstate). This endpoint returns the device's current status and includes some additional response parameters:
1. **SetupStatus:** Returns as **COMPLETE** or **INCOMPLETE** per key that started creation on the device.
2. **Algorithm name:** Returns as `MPC_ECDSA_SECP256K1` or `MPC_EDDSA_ED25519`.
3. **backedUp:** This boolean flag indicates whether the keys were [backed up ](https://ncw-developers.fireblocks.com/docs/backup-recovery-1)by any of the wallet's devices. Remember, a wallet can have [multiple devices](https://ncw-developers.fireblocks.com/docs/multiple-devices) associated with it.
Note that a device's status will only return as **COMPLETE** when all the keys declared in its workspace have reached the **COMPLETE** status and the device's backup flag is set to **true**.
# Retrieving the Wallet Key Status
You can also query a wallet's status by calling the [Get wallet key setup state endpoint](/reference/getwalletsetupstate). The response includes the current status of all devices associated with the wallet. Note that a wallet is considered **COMPLETE** as long as at least one of its devices also has the **COMPLETE** status.
If you send a request to an incomplete wallet or device, your request will fail and Fireblocks may return [error codes ](https://ncw-developers.fireblocks.com/docs/api-errors)to provide context for the request's failure.
# Removing Keys After Irrecoverable Loss
In **rare** cases, a wallet may become unusable if a new key set is added but **not backed up** before the device is lost. For example, if a wallet originally had *ECDSA* keys that were backed up, and *EdDSA* keys were later added but never backed up, losing the device now will leave the wallet in an incomplete state. This will cause most wallet operations to fail across all devices.
To resolve this and regain control of the backed-up *ECDSA* keys, you need to perform an administrative operation to explicitly remove the *EdDSA* algorithm from the wallet’s algorithm set. This is done using the Fireblocks SDK initialized with the EW Admin API user's private key:
```typescript TypeScript theme={"system"}
const response = await fireblocksAdmin.deleteSigningAlgorithm(walletId, [SigningAlgorithm.MPC_EDDSA_ED25519])
```
This will allow the wallet to operate again using the remaining *ECDSA* key set.
## Re-generating the Key Set
Once the wallet is operational again, you can re-generate a new *EdDSA* keys set from your client application, as mentioned in [MPC Key Generation](https://ncw-developers.fireblocks.com/docs/mpc-key-generation):
```typescript TypeScript theme={"system"}
import { IKeyDescriptor } from "@fireblocks/ncw-js-sdk";
// Generate MPC Keys
const algorithms = new Set(["MPC_CMP_EDDSA_ED25519"]);
const keyDescriptor: Set = await ewCore.generateMPCKeys(algorithms);
```
```kotlin Kotlin theme={"system"}
val algorithms = setOf(Algorithm.MPC_EDDSA_ED25519)
fireblocksSdk.generateMPCKeys(algorithms = algorithms){ result ->
Timber.i("generateMPCKeys result: $result")
}
```
```swift Swift theme={"system"}
func generateKeys(algorithms: Set) async throws -> Set {
//Initialize and create the Core SDK instance
let instance = try getCore()
return try await instance.generateMPCKeys(algorithms: algorithms)
}
```
**Note**: This example assumes the *ECDSA* keys were backed up and the *EdDSA* keys were lost. The same approach applies to any algorithm type.
### Important Considerations
1. This API only removes a signing algorithm. To add algorithms, see [Extending Your Key Set](doc:multiple-algorithms#extending-your-key-set).
2. A signing algorithm cannot be removed if any of the following apply:
1. Assets already exist under that algorithm.
2. The public key was retrieved using `getPublicKey`.
3. A takeover has been performed for the wallet.
# Wallet
Source: https://developers.fireblocks.com/docs/embedded-wallet-wallet
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
A wallet is an object you manage on Fireblocks' servers for your end-users. Wallets can have multiple keys (ECDSA and [EdDSA](https://ncw-developers.fireblocks.com/docs/multiple-algorithms)) and an unlimited number of wallet accounts. Each wallet account has a single asset type under it. For instance:
* `walletId-1`
* `walletAccount-1`
* `BTC`
* `ETH`
* `walletAccount-2`
* `FTM`
* `TRON`
In the new architecture wallet creation is done automatically (if needed) as part of the `assignWallet()` EW SDK method.
## Multiple wallets and wallet accounts
Theoretically, your end-user can have multiple wallets, but that does not matter in the Fireblocks view since Fireblocks does not hold any personally identifiable information (PII) about your end-users. However, for simplicity in our demos, we assume a one-to-one relationship between an end-user and a wallet.
# Web3 Wallet Link
Source: https://developers.fireblocks.com/docs/embedded-wallet-web3-wallet-link
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# About the Fireblocks Web3 Wallet Link
As the demand for Web3 accessibility and usage grows, more users want to use dApps directly to manage their NFTs, get rewards, and more. The Fireblocks Web3 Wallet Link lets your users connect their Fireblocks Embedded Wallet addresses directly to Web3 applications without needing a wallet or any other application, offering your users one-stop shopping for anything related to crypto and Web3.
# Creating a Web3 connection
The Web3 Wallet Link currently supports WalletConnect connections. WalletConnect is a well-established standard for connecting wallets and Web3 applications and is supported by all of the leading dApps today.
When someone wants to connect to a dApp, they scan a QR code provided by WalletConnect inside the dApp. This QR code contains a URI representing the connection session to be established between the dApp and the wallet. Passing this URI onto Fireblocks using the API allows the connection to be successful.
# Examples
For Web3 Wallet Link code examples, follow [this guide](/docs/web3-wallet-link).
# Webhook Configuration
Source: https://developers.fireblocks.com/docs/embedded-wallet-webhook-configuration
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
### Note
This page focuses on setting up webhook notifications for the Fireblocks Non-Custodial Wallet (NCW). For more information about additional events sent by the Fireblocks webhook service, [visit our Developer Portal's API Reference](/reference/webhooks-notifications-1).
# Overview
Multi-party computation (MPC) operations involve communication between several participants. This collaboration occurs over multiple rounds of communication, creating an asynchronous process.
To facilitate this communication, your system needs to expose the `POST /api/webhook` REST API endpoint to receive webhook notifications generated by Fireblocks. Each notification carries essential data to the Software Development Kit (SDK), which handles the asynchronous process.
In addition to managing these aspects, the Fireblocks webhook service also delivers notifications about events occurring within your workspace. This provides you with timely updates about relevant activities.
# Configuring Webhook URLs
To configure URLs for webhook notifications:
1. In the Fireblocks Console, go to **Settings** > **General**, then scroll down to the Configure Webhook URL heading and select **Manage URLs**.
2. On the Configure Webhook URL window, enter a URL to define the HTTPS endpoint, then press **Enter**. Each webhook URL must be a complete, globally available HTTPS address, such as [https://example.com](https://example.com).
3. Select **Save**.
Once your webhook is connected to your Fireblocks workspace, you will start receiving notifications for events in that workspace.
# Receiving Webhook Notifications
## Validation
You can validate Fireblocks webhook events by validating the signature attached in the request header:
**Fireblocks-Signature:** `Base64(RSA512(_WEBHOOK_PRIVATE_KEY_, SHA512(eventBody)))`
Copy this public key to validate the above signature in Sandbox workspaces:
```pem theme={"system"}
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+fZuC+0vDYTf8fYnCN6
71iHg98lPHBmafmqZqb+TUexn9sH6qNIBZ5SgYFxFK6dYXIuJ5uoORzihREvZVZP
8DphdeKOMUrMr6b+Cchb2qS8qz8WS7xtyLU9GnBn6M5mWfjkjQr1jbilH15Zvcpz
ECC8aPUAy2EbHpnr10if2IHkIAWLYD+0khpCjpWtsfuX+LxqzlqQVW9xc6z7tshK
eCSEa6Oh8+ia7Zlu0b+2xmy2Arb6xGl+s+Rnof4lsq9tZS6f03huc+XVTmd6H2We
WxFMfGyDCX2akEg2aAvx7231/6S0vBFGiX0C+3GbXlieHDplLGoODHUt5hxbPJnK
IwIDAQAB
-----END PUBLIC KEY-----
```
## Response
The Fireblocks server will look for a response to confirm the webhook notification was received. All webhook events should receive an HTTP-200 (OK) response.
If no response is received, Fireblocks will resend the request several times. The retry schedule is 15, 45, 105, 225, 465, 945, 1905, 3825, 7665, and 15345 seconds.
# Code Examples
### Warning
These examples are not production-ready and are used only for reference. Please follow our [security guidelines](/docs/secure-api-configuration) for secure API interaction.
```javascript JavaScript theme={"system"}
const crypto = require("crypto");
const express = require("express");
const bodyParser = require('body-parser')
const port = 3000;
const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+fZuC+0vDYTf8fYnCN6
71iHg98lPHBmafmqZqb+TUexn9sH6qNIBZ5SgYFxFK6dYXIuJ5uoORzihREvZVZP
8DphdeKOMUrMr6b+Cchb2qS8qz8WS7xtyLU9GnBn6M5mWfjkjQr1jbilH15Zvcpz
ECC8aPUAy2EbHpnr10if2IHkIAWLYD+0khpCjpWtsfuX+LxqzlqQVW9xc6z7tshK
eCSEa6Oh8+ia7Zlu0b+2xmy2Arb6xGl+s+Rnof4lsq9tZS6f03huc+XVTmd6H2We
WxFMfGyDCX2akEg2aAvx7231/6S0vBFGiX0C+3GbXlieHDplLGoODHUt5hxbPJnK
IwIDAQAB
-----END PUBLIC KEY-----`.replace(/\\n/g, "\n");
const app = express();
app.use(bodyParser.json());
app.post("/webhook", (req, res) => {
const message = JSON.stringify(req.body);
const signature = req.headers["fireblocks-signature"];
const verifier = crypto.createVerify('RSA-SHA512');
verifier.write(message);
verifier.end();
const isVerified = verifier.verify(publicKey, signature, "base64");
console.log("Verified:", isVerified);
res.send("ok");
});
app.listen(port, () => {
console.log(`Webhook running at http://localhost:${port}`);
});
```
```python Python theme={"system"}
import falcon
import json
import rsa
import base64
FIREBLOCKS_PUBLIC_KEY = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+fZuC+0vDYTf8fYnCN6
71iHg98lPHBmafmqZqb+TUexn9sH6qNIBZ5SgYFxFK6dYXIuJ5uoORzihREvZVZP
8DphdeKOMUrMr6b+Cchb2qS8qz8WS7xtyLU9GnBn6M5mWfjkjQr1jbilH15Zvcpz
ECC8aPUAy2EbHpnr10if2IHkIAWLYD+0khpCjpWtsfuX+LxqzlqQVW9xc6z7tshK
eCSEa6Oh8+ia7Zlu0b+2xmy2Arb6xGl+s+Rnof4lsq9tZS6f03huc+XVTmd6H2We
WxFMfGyDCX2akEg2aAvx7231/6S0vBFGiX0C+3GbXlieHDplLGoODHUt5hxbPJnK
IwIDAQAB
-----END PUBLIC KEY-----
"""
signature_pub_key = rsa.PublicKey.load_pkcs1_openssl_pem(FIREBLOCKS_PUBLIC_KEY)
class RequestBodyMiddleware(object):
def process_request(self, req, resp):
req.body = req.bounded_stream.read()
class AuthMiddleware(object):
def process_request(self, req, resp):
signature = req.get_header('Fireblocks-Signature')
if signature is None:
raise falcon.HTTPUnauthorized('Signature required')
if not self._signature_is_valid(req.body, signature):
raise falcon.HTTPUnauthorized('Invalid signature')
def _signature_is_valid(self, body, signature):
try:
hashing_alg = rsa.verify(body, base64.b64decode(signature), signature_pub_key)
return hashing_alg == "SHA-512"
except rsa.pkcs1.VerificationError:
return False
class DummyRequest(object):
def on_post(self, req, resp):
obj = json.loads(req.body.decode("utf-8"))
print(obj)
resp.status = falcon.HTTP_201
# Create falcon app
app = falcon.API(
middleware=[
RequestBodyMiddleware(),
AuthMiddleware()
]
)
app.add_route('/webhook', DummyRequest())
if __name__ == '__main__':
from wsgiref import simple_server # NOQA
httpd = simple_server.make_server('127.0.0.1', 8000, app)
httpd.serve_forever()
```
# Immediate Webhooks
In order to send the transaction statuses in a chronological order, some transactions updates may be shortly delayed by a few seconds.
In order to deliver a great user experience, Fireblocks also provides the `NCW_TRANSACTION_STATUS_UPDATED` webhook type, which is being sent immediately, without any delays.
Although these may not be received in a chronological order, it will provide you with a notification that a transaction is `PENDING_SIGNATURE` immediately without any delays, allowing you to start the signing ceremony as soon as possible.
# Webhooks
Source: https://developers.fireblocks.com/docs/embedded-wallet-webhooks
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
## Transaction Created
A notification is sent when any new transaction is identified in the workspace.
| Parameter | Type | Description |
| --------- | ------------------------------------------------------------------------ | ------------------------------------ |
| type | string | TRANSACTION\_CREATED |
| tenantId | string | The Fireblocks workspace's unique ID |
| timestamp | number | Timestamp in milliseconds |
| data | [TransactionDetails](/reference/transaction-webhooks#transactiondetails) | All the transaction information |
## Transaction Status Updated
A notification is sent when there is any change in a transaction's status or when the number of confirmations is updated.
| Parameter | Type | Description |
| :-------- | :----------------------------------------------------------------------- | :----------------------------------- |
| type | string | TRANSACTION\_STATUS\_UPDATED |
| tenantId | string | The Fireblocks workspace's unique ID |
| timestamp | number | Timestamp in milliseconds |
| data | [TransactionDetails](/reference/transaction-webhooks#transactiondetails) | All the transaction informati |
## NCW Transaction Status Updated (Immediate)
### In Early Access
This webhook is currently part of an early access program. If you're interested in participating in the program, please [contact your Customer Success Manager](https://support.fireblocks.io/hc/en-us/requests/new?ticket_form_id=6947882197532) (requires a Help Center login).
In addition to the transaction status updates which are being sent in a chronological order (and not immediately), NCW transaction status updates are being sent right away. This is mainly to allow your backend to receive a notification that a transaction is pending signature as fast as possible.
**Note**: It will only be sent for outgoing transactions (withdrawals) with the following statuses:\
`PENDING_SIGNATURE`, `COMPLETED`, `CANCELLED`, `FAILED`, `BLOCKED`, `REJECTED`
| Parameter | Type | Description |
| :-------- | :----------------------------------------------------------------------- | :----------------------------------- |
| type | string | NCW\_TRANSACTION\_STATUS\_UPDATED |
| tenantId | string | The Fireblocks workspace's unique ID |
| timestamp | number | Timestamp in milliseconds |
| data | [TransactionDetails](/reference/transaction-webhooks#transactiondetails) | All the transaction information |
## Multi-Device Request ID
| Parameter | type | Description |
| :------------- | :----- | :------------------------------------------------------------------------ |
| type | string | NCW\_ADD\_DEVICE\_SETUP\_REQUESTED |
| tenantId | string | The Fireblocks workspace's unique ID |
| timestamp | number | Timestamp in milliseconds |
| data.walletId | string | The wallet's unique ID |
| data.deviceId | string | The device's unique ID |
| data.requestId | string | The join wallet request's unique ID; is delegated to the approving device |
### Note
The structure of `data.fieldName` comes to describe a payload with values under a key data.
## Non-Custodial Wallet Created
| Parameter | type | Description |
| :------------ | :------ | :-------------------------------------- |
| type | string | NCW\_CREATED |
| tenantId | string | The Fireblocks workspace's unique ID |
| timestamp | number | Timestamp in milliseconds |
| data.walletId | string | The wallet's unique ID |
| data.enabled | boolean | Indicates whether the wallet is enabled |
## Non-Custodial Wallet Account Created
| Parameter | type | Description |
| :------------- | :----- | :--------------------------------------- |
| type | string | NCW\_ACCOUNT\_CREATED |
| tenantId | string | The Fireblocks workspace's unique ID |
| timestamp | number | Timestamp in milliseconds |
| data.walletId | string | The wallet's unique ID |
| data.accountId | string | The account's ID in the specified wallet |
## Non-Custodial Wallet Asset Created
| Parameter | type | Description |
| :------------- | :----- | :------------------------------------------------------- |
| type | string | NCW\_ASSET\_CREATED |
| tenantId | string | The Fireblocks workspace's unique ID |
| timestamp | number | Timestamp in milliseconds |
| data.walletId | string | The wallet's unique ID |
| data.accountId | string | The account's ID in the specified wallet |
| data.asset | string | The asset's ID as defined in Fireblocks (BTC, ETH, etc.) |
## Non-Custodial Wallet Asset balance changed
### In Early Access
This webhook is currently part of an early access program. If you're interested in participating in the program, please [contact your Customer Success Manager](https://support.fireblocks.io/hc/en-us/requests/new?ticket_form_id=6947882197532) (requires a Help Center login).
Notification is sent when an asset's balance changes.
| Parameter | type | Description |
| :------------ | :----------------------------------------------------------------------------------------------------- | :----------------------------------- |
| type | string | END\_USER\_WALLET\_BALANCE\_UPDATE |
| tenantId | string | The Fireblocks workspace's unique ID |
| timestamp | number | Timestamp in milliseconds |
| data.walletId | string | The wallet's unique ID |
| data | [NcwAssetBalanceUpdate](https://ncw-developers.fireblocks.com/docs/data-objects#ncwassetbalanceupdate) | NCW asset details |
# Enable the Gas Station
Source: https://developers.fireblocks.com/docs/enabling-the-gas-station-1
### Gas Station is only available to Pro and Enterprise customers
Contact your Customer Success Manager for more information.
## Gas Station 1.0
[Contact Fireblocks Support to enable the Gas Station in your workspace](https://support.fireblocks.io/hc/en-us/requests/new?ticket_form_id=360003372200). After they enable it, verify the following in your workspace:
1. On the Network page, you should have a new Network Connection named **Fireblocks Gas Station**.
2. On the Whitelisted Addresses page, you should have a new internal wallet called **Gas Station Wallet**. This internal wallet holds asset addresses reflecting EVM-based assets supported by the Gas Station that exist on each of the vaults on which you enable the Gas Station.
## Gas Station 2.0
The Fireblocks Gas Station 2.0 now offers a self-service auto-fueling solution. You can designate a single vault account in your workspace as the auto-fuel Gas Station, and activate the auto-fueling option on other vault accounts. This allows for a self-managed, self-custody Gas Station service and helps eliminate friction.
Learn more about the Fireblocks Gas Station 2.0 enablement [here](https://support.fireblocks.io/hc/en-us/articles/11602800877596-Setup-for-Gas-Station-2-0).
# EW SDK Event Collection
Source: https://developers.fireblocks.com/docs/ew-sdk-event-collection
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
During day-to-day operations, end users are triggering countless actions within your application.
As part of your provided user experience, end users will generate keys, sign transactions and perform additional actions such as connecting their wallet to a dApp or export their private key material. Due to the complexity and variety of actions an end user may perform, different issues or errors may arise.
In order to proactively monitor and treat such problems that may appear, the EW SDK lets you toggle whether events and logs will be automatically sent to Fireblocks, through your backend.
Thus, Fireblocks may be able to proactively suggest and point onto issues or problems that your user base is facing, providing you with the ability to resolve it before any major impact.
It's important to note Fireblocks does not retrieve any PII regarding the end user. Please review the Shared Data section to validate the data that is shared with Fireblocks.
# Configuration
As part of the `FireblocksOptions` object, you will now have a new flag, `reporting`.
```typescript TypeScript theme={"system"}
// First you need to initialize the NCW SDK with an implementation of the looger
const logger: IndexedDBLogger = await IndexedDBLoggerFactory({ deviceId, logger: ConsoleLoggerFactory() });
const fireblocksNCW = await FireblocksNCWFactory({
env: ENV_CONFIG.NCW_SDK_ENV,
logLevel: "INFO",
deviceId,
messagesHandler,
eventsHandler,
secureStorageProvider,
logger,
reporting = { enabled: true },
});
// Number of logs collected
const numberOfLogs = await logger.count();
// Collect 10 logs
const logs = await logger.collect(10);
// Clears the oldest 10 logs
await logger.clear(10);
```
```swift Swift theme={"system"}
var fireblocksOptions = FireblocksOptions(
env: EnvironmentConstants.env,
eventHandlerDelegate: self,
logLevel: .info,
logToConsole: true,
reporting: ReportingOptions(enabled: true)
)
```
```kotlin Kotlin theme={"system"}
val fireblocksOptions = FireblocksOptions.Builder()
.setLogLevel(getNCWLogLevel())
.setLogToConsole(true)
.setReportingOptions(ReportingOptions(enabled = false))
.setEventHandler(object : FireblocksEventHandler {
override fun onEvent(event: Event) {
// handle events
}
})
.setEnv(environment)
.build()
```
**By default,`reporting` is enabled**. If you do not want to share telemetry logs with Fireblocks, just set `reporting` to false.
# Shared Data
When reporting on errors, the SDK will collect a few fields:
* type
* message
* code
* level
* method
* logs
All of these are fields that are related to the EW SDK itself, and **do not expose** any personal identifiable information (**PII**) regarding the end user.
In addition, the below items are the only metadata fields regarding the device that are transferred to Fireblocks:
* navigator\_appCodeName (e.g. Mozilla)
* navigator\_appName
* navigator\_language
* navigator\_platform
* navigator\_product
* navigator\_userAgent
* navigator\_vendor
* timezoneOffset
You may find an example payload here:
```text Log theme={"system"}
completedMPC:true
device:iPhone14,3
deviceId:b0550946-3d70-4e6b-949d-247549bd775f
environment:dev9
hasCMPKey:true
iosVersion:16.4
onboardedRecovery:false
timezone:GMT+3
uptime:timeval(tv_sec: 1716876653, tv_usec: 488161)
```
```text Log theme={"system"}
VersionIncremental=S.17acc52_1-1,
completedMPC=false,
Uptime= 18h29m3.942s,
keyStatus=ERROR,
Device=OnePlus/OP516FL1/NE2213/NE2213,
SdkVersion=2.5.0_1,
keyId=0743117c-f737-4f38-b5bc-2c5a0cb17209,
AndroidVersion=34,
deviceId=3ac62b9b-5bb6-4756-96ef-85015ee5f345,
hasCMPKey=Yes,
environment=dev9,
TimeZone=GMT+03:00,
onboardedRecovery=null,
OSVersion=5.10.198-android12-9-o-g4b6fa3fb4a9f,
VersionRelease=14,
algorithm=MPC_EDDSA_ED25519
```
# EW SDK Manual Log Retrieval
Source: https://developers.fireblocks.com/docs/ew-sdk-manual-log-retrieval
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Overview
If you experience issues during your application's development phase or with end users, you may need to retrieve EW SDK logs to troubleshoot those issues. To facilitate this, the EW SDK exposes methods that enable you to fetch logs. You can then send the collected logs to your designated servers.
* For our mobile SDKs, a designated interface guides you to a zipped file that you can retrieve from your end-user clients and then upload to your servers.
* The web SDK offers an interface that lets you write and fetch logs. Refer to the web demo for an example of writing logs to your browser's indexed database.
# Example
```typescript TypeScript theme={"system"}
// First you need to initialize the NCW SDK with an implementation of the looger
const logger: IndexedDBLogger = await IndexedDBLoggerFactory({ deviceId, logger: ConsoleLoggerFactory() });
const fireblocksNCW = await FireblocksNCWFactory({
env: ENV_CONFIG.NCW_SDK_ENV,
logLevel: "INFO",
deviceId,
messagesHandler,
eventsHandler,
secureStorageProvider,
logger,
});
// Number of logs collected
const numberOfLogs = await logger.count();
// Collect 10 logs
const logs = await logger.collect(10);
// Clears the oldest 10 logs
await logger.clear(10);
```
```swift Swift theme={"system"}
guard let url = FireblocksManager.shared.getSdkInstance()?.getURLForLogFiles() else {
print("Can't get file log url")
return
}
```
```kotlin Kotlin theme={"system"}
val sdkUri = Fireblocks.getUriForLogFiles(context)
```
# Need help?
Contact Fireblocks Support and include your logs as an attachment.
# Execute Smart Transfers
Source: https://developers.fireblocks.com/docs/execute-smart-transfers
# Overview
As you can open a regular Smart Transfer ticket [via these API endpoints](/reference/createticket), an intermediary can open a Smart Transfer ticket for two third-parties only via our API as well, and follow its life cycle. In order for you, as an intermediary, to open such a ticket for your third-parties, all three of you need to be connected to each other with the same network profiles on the Fireblocks Network.
# Smart Transfer flow
To create Smart Transfer tickets an established network connection must exist. In the intermediary case, all sides (intermediary and counterparties settling the tickets) should be connected via the same Network Profile.
The flow of executing a Smart Transfer ticket consists of the following steps:
1. [Create a Smart Transfer ticket](/reference/createticket)
2. [Fund Smart Transfer ticket](/reference/fulfillticket)
3. [Cancel Smart Transfer ticket](/reference/cancelticket)
### Check out the [Smart Transfers Developer Guide](/reference/execute-smart-transfers-1) for more information
# Fetching Transaction Receipt
Source: https://developers.fireblocks.com/docs/fetching-transaction-receipt
This guide outlines the procedure for retrieving a transaction receipt via the endpoint, utilizing the function in the Fireblocks SDK.
By employing the `getTransactionReceipt` function of the Fireblocks SDK, you can obtain the receipt of any transaction that has been confirmed by the blockchain. This function takes in the `baseAssetId` (indicating the blockchain) and the `txHash` (indicating the transaction hash). It manages the process of querying the blockchain and returning the transaction receipt.
### Note:
This functionality is exclusively available for EVM (Ethereum Virtual Machine) compatible chains.
## Prerequisites
Before fetching a transaction receipt, ensure you have the following information:
1. **Base Asset ID**: The `baseAssetId` of the blockchain where the transaction was executed (e.g., ETH for Ethereum). This is the Fireblocks ID of the blockchain's gas token. (To obtain the asset ID, refer to this [assetId list](https://support.fireblocks.io/hc/en-us/articles/8993656344092-Supported-blockchain-networks)).
2. **Transaction Hash**: The `txHash` of the transaction for which you wish to fetch the receipt. This is the unique identifier of the transaction on the blockchain and is a hex string (i.e. prefixed with 0x). You can obtain the transaction hash from the transaction details or the blockchain explorer.
## Example: Fetching a Transaction Receipt
Below is an example of how to fetch a transaction receipt using the Fireblocks SDK:
### 1. Initialize the Fireblocks SDK
First, import the Fireblocks SDK and initialize it with your Fireblocks API key and private key:
```typescript TypeScript theme={"system"}
import { Fireblocks, BasePath } from '@fireblocks/ts-sdk';
const privateKey = '...'; // Your Fireblocks API private key
const apiKey = '...'; // Your Fireblocks API key
const fireblocksSdk = new Fireblocks({
apiKey,
basePath: BasePath.US, // Use BasePath.EU for the EU region
secretKey: privateKey,
});
```
### 2. Fetch the Transaction Receipt
To fetch the transaction receipt, utilize the `getTransactionReceipt` function of the Contract Interactions Controller:
```typescript TypeScript theme={"system"}
const baseAssetId = 'ETH'; // The base asset ID for Ethereum
const txHash = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; // The transaction hash
const receipt = await fireblocks.getTransactionReceipt(baseAssetId, txHash);
console.log(receipt);
```
The response will be a transaction receipt object containing details about the transaction, such as the status, gas used, logs, and more.
### Note:
For further information about the transaction receipt object, refer to the [Endpoint Model](#endpoint-model) section.
## Endpoint Model
### Transaction Receipt
The transaction receipt response object includes the following fields:
* `status`: The status of the transaction (e.g., success or failure).
* `gasUsed`: The amount of gas consumed by the transaction.
* `logs`: The logs generated by the transaction (if any).
* `transactionHash`: The hash of the transaction.
* `blockHash`: The hash of the block containing the transaction.
* `blockNumber`: The number of the block containing the transaction.
* `contractAddress`: The address of the contract created (if any).
* `cumulativeGasUsed`: The cumulative gas used by the transaction.
* `from`: The address of the sender.
* `to`: The address of the receiver.
* `effectiveGasPrice`: The actual price per unit of gas paid.
* `type`: The type of the transaction.
* `logs`: The logs generated by the transaction (if any).
* `logsBloom`: The bloom filter for the logs of the transaction.
* `transactionIndex`: The index of the transaction in the block.
### Note:
The `logs` field contains an array of log objects, each representing a log generated by the transaction. Each log object includes the following fields:
* `address`: The address of the contract that generated the log.
* `topics`: An array of topics associated with the log.
* `data`: The data contained in the log.
* `blockNumber`: The number of the block containing the log.
* `transactionHash`: The hash of the transaction that generated the log.
* `transactionIndex`: The index of the transaction in the block.
* `blockHash`: The hash of the block containing the log.
* `logIndex`: The index of the log in the block.
* `removed`: Indicates whether the log was removed.
### Note:
Some fields may be empty in the response if the transaction has not been executed or if the blockchain does not support them.
# Fireblocks CLI
Source: https://developers.fireblocks.com/docs/fireblocks-cli
Execute any Fireblocks API operation from the command line.
# Overview
The Fireblocks CLI (`@fireblocks/fireblocks-cli`) is an agent-first command-line tool that exposes every Fireblocks API operation as a typed command. Commands are organized by API namespace (e.g. `vaults`, `transactions`, `embedded-wallets`) and use JWT-signed requests identical to the Fireblocks SDKs.
The CLI is built for:
* **Scripting and automation** — run API calls from shell scripts, CI pipelines, or cron jobs
* **Exploration** — inspect vault balances, transaction status, or workspace state without writing code
* **AI agent integration** — the `help-index` command returns a compact JSON index of all commands that fits in an LLM context window
## Features
* Every Fireblocks API endpoint as a typed command
* JWT-signed requests using the same signing approach as the TypeScript SDK
* Credential management — store profiles in `~/.config/fireblocks/config.json`
* `--dry-run` — preview any request before executing it
* `--debug` — log request and response details to stderr
* Write-operation confirmation prompts (skippable with `--no-confirm`)
* Structured JSON errors on stderr with distinct exit codes
* Shell autocomplete for Bash and Zsh
## Installation
The CLI is available as an npm package and requires Node.js 18 or later.
* **npm package**: `https://www.npmjs.com/package/@fireblocks/fireblocks-cli`
* **GitHub repo**: `https://github.com/fireblocks/fireblocks-cli`
* **GitHub release (latest)**: `https://github.com/fireblocks/fireblocks-cli/releases/latest`
### npm (recommended)
```bash theme={"system"}
npm install -g @fireblocks/fireblocks-cli
```
### Standalone installers (macOS, Windows, Linux)
Standalone installers for each OS are available in the GitHub Releases assets.
### Tarballs
Tarballs are also available in the GitHub Releases assets.
### Homebrew (macOS)
```bash theme={"system"}
brew tap fireblocks/fireblocks-cli
brew install fireblocks-cli
```
### Other package managers
```bash theme={"system"}
# yarn
yarn global add @fireblocks/fireblocks-cli
# pnpm
pnpm add -g @fireblocks/fireblocks-cli
```
The `fireblocks` command will be available immediately after installation.
## Verify Installation
```bash theme={"system"}
fireblocks --version
```
## Quick Start
```bash theme={"system"}
# 1. Set up credentials interactively
fireblocks configure
# 2. Verify credentials
fireblocks whoami
# 3. List vault accounts
fireblocks vaults get-paged-vault-accounts
# 4. Discover all available commands
fireblocks help-index
```
## Next Steps
* [Authentication](./cli-authentication) — configure credentials, environment variables, and profiles
* [Usage Guide](./cli-usage) — commands, flags, examples, and exit codes
# Google Cloud Confidential Space API Co-signer Architecture
Source: https://developers.fireblocks.com/docs/gcp-confidential-space-api-co-signer
### Learn how to install GCP Confidential Space Co-signer in the [following guide](/reference/install-api-cosigner-gcp)
## GCP Co-signer can only connect to one workspace at a time
Like other Co-signers, the Google Cloud Confidential Space Co-signer is installed and connected to the workspace through an API user. Once installation is complete, you can manage it via the Console or APIs to add additional API users, configure their Callback Handlers, etc.
Due to Google Cloud's Confidential Space container architecture, the Co-signer can only be commanded through Fireblocks' SaaS. As a result, it is restricted to a single workspace connected to the Co-signer. All operations must be performed within this workspace using the Console or APIs.
## Google Cloud resources used by the Co-signer
The Fireblocks GCP Confidential Space API Co-signer leverages Google's Confidential Space technology. It utilizes the following Google Cloud's resources:
* **Workload Container**: used to run the enclave.
* **Bucket**: used as the Co-signer's persistent storage and holds the encrypted database of the Co-signer.
* **KMS Customer Managed Key**: used to securely protect the Co-signer's MPC keyshares, which are stored in the Co-signer's persistent storage within a bucket.
* **IAM/WIP**: enables associating identities with Google Cloud's IAM roles to grant only essential permissions to specific resources in use.
### **Important**: Allocate a separate set of resources for each Co-signer to prevent conflicts and ensure isolation, enhancing security.
The "project" can be common between different Co-signers.
This is illustrated in the block diagram below:
## Secure Co-signer database encryption scheme
The following process is implemented to build and secure the Co-signer's database:
1. The user creates and configures a symmetric Customer Managed Key (CMK) in the KMS.
2. The Co-signer, upon initialization, asks KMS to generate an additional AES 128-bit CBC key: `FBKS-DB-Key`
3. The Co-signer initializes its encrypted database using the key `FBKS-DB-KEY`
4. The Co-signer encrypts `FBKS-DB-KEY` using the CMK.
5. The Co-signer saves its encrypted database and the encrypted form of `FBKS-DB-KEY` in the GCS bucket, serving as its persistent storage.
6. Access to KMS, including the CMK, is restricted using a Fireblocks enclave image attestation signature and the IAM role and policies that were created by the user.
This is illustrated in the block diagram below:
# Create a CSR for an API user
Source: https://developers.fireblocks.com/docs/generate-a-csr-for-an-api-user
# What is a CSR?
A Certificate Signing Request (CSR) is a file that contains your public key and some identifying information. Fireblocks uses the CSR to generate your API user's public key, which Fireblocks then uses to verify and authenticate your API calls.
# Before you begin
Make sure you have the following:
* Access to a machine where you can run OpenSSL or similar tooling
* A secure location to store your private key
# Step 1: Create the private key & CSR files
## Using OpenSSL (recommended for most users)
Open your terminal or command line and run the following command to generate a private key and CSR:
```bash Shell theme={"system"}
openssl req -new -newkey rsa:4096 -nodes -keyout api_private.key -out api_user.csr
```
### What this does
* Creates a private key file: **api\_private.key**
* Creates a CSR file: **api\_user.csr**
### Security reminder
*Never* upload or share the **api\_private.key** file. Store it securely using a Key Management System (KMS), HSM, or encrypted file storage.
# Step 2: Fill in the CSR details
When prompted, complete the following fields:
| Field | Description |
| ------------------------ | ------------------------------------------------------------ |
| Common Name (CN) | Your name or the API user's name (e.g., John\_the\_API\_Guy) |
| Organization (O) | Your organization's name |
| Organizational Unit (OU) | Optional field (e.g., API Team) |
| Country (C) | Two-letter country code (e.g., US) |
| State (ST) | Your state or province |
| Locality (L) | Your city |
# Step 3: Upload the CSR file
* In the Fireblocks Console, [follow these steps to create an API user](https://support.fireblocks.io/hc/en-us/articles/4407823826194-Adding-new-API-Users#h_01HHHT468Y7RFAP3E5DNJYHHZZ). Note that only Admin-level workspace users (Owner, Admin, and Non-Signing Admin) can create API users.
* Upload the **api\_user.csr** file in the **CSR File** field.
### Warning
Do *not* upload your private key! Keep the **api\_private.key** file secure for signing API requests later.
# Getting Started
Source: https://developers.fireblocks.com/docs/getting-started-with-embedded-wallets
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
# Before you begin
Before starting your Fireblocks Embedded Wallet (EW) implementation, it’s important to distinguish between the SDKs involved:
* The **Fireblocks EW client SDKs** (also referred to as the **EW SDK** and the **EW Core SDK**).
* The **Fireblocks SDK**.
Each serves a different purpose:
* The **EW SDKs** consist of platform-specific SDKs used in your *client app implementation*
* The **Fireblocks SDK** can be used for administrative EW operations and is initialized with an API user's private key. It can be used with one of two roles: [EW Admin and EW Signer](https://ncw-developers.fireblocks.com/docs/api-communication).
## Embedded Wallet glossary
* **EW:** Embedded Wallet.
* **Customer:** A business entity using Fireblocks' services.
* **Backend:** Optional server-side logic operated by the customer. Not required in the current architecture. [Learn more about backend use cases](/docs/embedded-wallet-high-level-architecture).
* **End User:** Fireblocks customers' end-user (i.e., the consumer).
* **Device ID:** A logical identifier representing an entity that stores a user key share and can participate in MPC operations for a given wallet. There is a unique identifier per SDK instance.
* **Physical Device ID:** A logical identifier representing a single mobile or web device.
* **Passphrase:** An end-user passphrase created for backup encryption.
* **Master Key:** A unique master key used for key share derivation.
* **Key Share:** One-half of the master key. Key Share #1 is at Fireblocks servers, and Key Share #2 is on the client side.
# Minimum requirements
## Android
* 64-bit mobile device (usually devices with at least 6GB of RAM)
* Android API version 27 (Android 8.0.1)
### Distribution ABI filters
### Pay attention
The SDK ABI Filter does not limit your app distribution to 64-bit. You must ensure that your app's `build.grade` file imposes this limitation. For additional information, refer to the [Android official guidelines](https://developer.android.com/ndk/guides/abis).
The SDK requires a minimum of 64-bit devices. The `build.gradle` file includes the following ABI Filters:
```groovy theme={"system"}
ndk {
abiFilters 'arm64-v8a', 'x86_64'
}
```
## iOS
* iOS 14 or later
## Web
Fireblocks recommends using the latest versions of the following web browsers:
* Google Chrome (Web, iOS, Android)
* Safari
* Microsoft Edge
* Firefox (Web, Android)
* Opera
* Android Browser
* Opera Mobile
* Samsung Internet
# Step-by-step process
The process of implementing the Fireblocks Embedded Wallet (EW) involves the following step-by-step sequence:
1. Complete the onboarding process to establish and configure your workspace.
2. Ensure comprehensive disaster readiness by completing the setup process for the disaster recovery kit.
3. Create the EW Signer and EW Admin API users.
4. Configure the webhook URL to enable communication between your application and Fireblocks.
5. Verify that you have at least one Transaction Authorization Policy (TAP) rule to govern your EW transactions (relevant to the production environment and not sandbox).
6. Set up your OAuth (SSO) configuration using your chosen Identity Provider (IDP), which will be used to authenticate end users.
7. (Optional) Implement a webhook listener (e.g., for transaction updates) and notify end-user devices using push notifications or other relevant channels.
8. Construct your mobile or web application and integrate the EW Software Development Kit (SDK).
9. Enroll your users into the application.
10. Generate MPC keys for each user with an EW.
11. Execute a key share backup procedure for each user to guarantee access in case of contingencies.
12. If allowed, provide the option to initiate a full key takeover and enhance control over their assets.
## EW TAP rules for Production workspaces
If you're a [Fireblocks Sandbox](/docs/quickstart) user, your sandbox workspace's TAP automatically has a rule that allows any end-user wallet to transfer any amount to any destination.
However, if you're a new or existing Fireblocks customer using a production workspace, you must [create a TAP rule](https://support.fireblocks.io/hc/en-us/articles/10394124789020-Create-a-TAP-rule) that governs end-user wallet transactions. Use the Fireblocks Console's TAP Editor to edit this rule or create additional rules as necessary.
## Flow chart
The following flow chart shows the successful workflow of a non-custodial embedded wallet system.
# Setting up OAuth configuration (SSO)
To enable user authentication in Embedded Wallet (EW), configure your Identity Provider (IDP) using the OAuth setup in the Fireblocks Console.
Once configured, Fireblocks will generate an **OAuth Client ID**. This ID is used to initialize the EW SDK on the client side.
> ⚠️ Note
>
> The EW SDK does not validate the IDP tokens itself. Instead, this setup enables Fireblocks to verify the tokens attached to end-user requests, ensuring secure authentication for all subsequent operations.
## Prerequisites
* Access to your OAuth-compatible IDP.
* The **EW Signer** API user created in your Fireblocks workspace. For more details, see [API Roles](https://ncw-developers.fireblocks.com/docs/api-communication#api-roles).
## Supported Identity Providers (IDPs)
The following OAuth-compatible IDPs are supported for use with Fireblocks Embedded Wallets. Use the provided JWKS URI when configuring your OAuth setup.
| Identity Provider | JWKS URI |
| ---------------------- | ------------------------------------------------------------------------------------------- |
| **Google** | `https://www.googleapis.com/oauth2/v3/certs` |
| **Firebase** | `https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com` |
| **Microsoft Azure AD** | `https://login.microsoftonline.com/common/discovery/v2.0/keys` |
| **AWS Cognito** | `https://cognito-idp.{REGION}.amazonaws.com/{USER_POOL_ID}/.well-known/jwks.json` |
| **Salesforce** | `https://login.salesforce.com/id/keys` |
## Required Configuration Fields
When setting up OAuth in the Console, you'll need to provide:
* **API User** – Select an API user with the "**EW Signer**" role.
* **JWKS URI** – The JWKS (JSON Web Key Set) endpoint from which Fireblocks retrieves your IDP’s public keys for token validation. see [Supported Identity Providers (IDPs)](https://ncw-developers.fireblocks.com/docs/setting-up-oauth-sso#supported-identity-providers-idps)
* **Issuer** – The expected `iss` claim in the token (must match your IDP’s value).
* **Audience** – The expected `aud` claim in the token (typically your OAuth client ID).
* **Custom wallet ID field name** *(optional)* – Specify the name of a custom claim in your IDP token (e.g., a Firebase [custom claim](https://firebase.google.com/docs/auth/admin/custom-claims)) that contains the wallet ID for the user. Then if presented in the token, Fireblocks will use this claim to override the default, deterministic wallet ID calculation for this user.
### Usage in the SDK
Once a configuration is added, the **OAuth Client ID** will appear in the Console.
Use this ID when initializing the SDK.
## User token generation in clients
For token generation and login UI, you are free to use your IDP's standard login flows and SDKs.
Fireblocks no longer supports the **Reactive Native SDK** and **Flutter SDK**.
# SDK installation
## Web SDK Installation
Install the Fireblocks "EW SDK" and "EW Core SDK" using `npm`:
```bash Shell theme={"system"}
npm i @fireblocks/ncw-js-sdk
npm i @fireblocks/embedded-wallet-sdk
```
Or `yarn`:
```bash Shell theme={"system"}
yarn add @fireblocks/ncw-js-sdk
yarn add @fireblocks/embedded-wallet-sdk
```
You can find the web demo code [here](https://github.com/fireblocks/ncw-web-demo-v2).
## Android SDK Installation
First, add our maven repository configuration to your `settings.gradle` file:
```groovy Android theme={"system"}
repositories {
maven {
url "https://maven.fireblocks.io/android-sdk/maven"
name = "android-sdk"
credentials(HttpHeaderCredentials) {
name = "Deploy-Token"
value = "-fU8ijmuPohHaqDBgpaT"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
```
Then, add the Fireblocks SDKs dependency to your application's `build.gradle` file using the most updated bom version:
```groovy Android theme={"system"}
implementation "com.fireblocks.sdk:bom:1.0.2"
implementation "com.fireblocks.sdk:ew"
implementation "com.fireblocks.sdk:ncw"
```
* You can find the Android Demo code [here](https://github.com/fireblocks/android-ncw-demo).
* You can find the Android SDKs documentation [here](https://fireblocks.github.io/ncw-docs/android/).
## iOS SDK Installation
First, in your iOS Project, add the [Fireblocks Embedded Wallet SDK](https://github.com/fireblocks/ew-ios-sdk) package:
Now add the [Fireblocks NCW iOS SDK](https://github.com/fireblocks/ncw-ios-sdk) package:
Then, after the SDK packages are added to the project, you should see them under the **Package Dependencies** section in the Project Navigator:
Lastly, import the SDK libraries:
```swift iOS theme={"system"}
import EmbeddedWalletSDK
import FireblocksSDK
```
* You can find the iOS demo code [here](https://github.com/fireblocks/ncw-ios-demo).
* You can find the iOS SDKs Docs [here](https://fireblocks.github.io/ncw-docs/ios/).
# Integrate Fireblocks with Third-Party Service Providers
Source: https://developers.fireblocks.com/docs/integrate-fireblocks-with-third-party-service-providers
# Overview
Many organizations utilizing Fireblocks seek to integrate their workspace with third-party service providers such as accounting solutions, portfolio aggregation tools, trading platforms, and more. These providers can offer valuable insights, operational efficiencies, and additional functionality by integrating directly with a Fireblocks environment.
However, since Fireblocks might not have native integrations with all these services, it is crucial to follow best practices to ensure that assets and data remain secure while maximizing the integration's effectiveness.
This guide is structured into two main sections:
* **For Fireblocks Clients**: Provides step-by-step recommendations for securely integrating third-party service providers with your Fireblocks workspace, focusing on access control, API key management, and other security practices.
* **For Third-Party Service Providers**: Offers guidance on how to securely connect with a client’s Fireblocks environment, emphasizing API key management, efficient data synchronization, and ensuring the client’s security requirements are met.
By addressing the specific concerns of both clients and providers, this guide aims to facilitate a smooth and secure integration process that benefits both parties.
# Fireblocks Clients
## Best Practices for Integration
### 1. Limit Access Levels
Ensure third-party providers are granted **Viewer** or **Editor** roles only—never **Signer** or **Admin** access. This principle applies to both API-based and UI-based integrations. Providing limited access minimizes risk exposure to your Fireblocks environment.
### 2. Secure API Key Management
If a third-party provider requires API access, the provider should handle key generation securely:
* The provider should create their own RSA private key and a Certificate Signing Request (CSR). Only the CSR should be shared with you.
* **Never accept private keys over the internet**.
### Always ensure that the third-party provider generates their own RSA private key and shares only the Certificate Signing Request (CSR) with you. Never share your private key with the provider.
Refer to the [Fireblocks API Key Management Documentation](/docs/manage-api-keys) for details on secure key management.
### 3. Use Dedicated API Keys
Always generate a new API key specific to the third-party provider. Avoid reusing API keys from internal operations to mitigate risks and facilitate easier access management.
### 4. Whitelist Provider IP Addresses
To enhance security, whitelist the provider’s server IP addresses for the specific API key. This additional security measure helps ensure only authorized servers have access.
More information can be found in the [IP Whitelisting Documentation](/docs/whitelist-ips-for-api-keys).
### 5. Initial Data Synchronization
For the first data sync, it's best to manually share balance and address reports from the Fireblocks Console to avoid overloading the API and hitting rate limits.
### 6. Enable Webhook Notifications
To keep data synchronized without excessive API polling, enable webhooks to push real-time updates from Fireblocks to the provider.
Visit the [Webhook Configuration Guide](/reference/configure-webhook-urls) for setup instructions.
### 7. Signing Transactions
If transaction signing is required, do not grant signing privileges directly to third-party providers. Use the **Designated Signer** feature and define a **Policy**. This approach maintains security by requiring your approval before any transaction is signed by the provider.
# Third-Party Service Providers (Partners)
## Best Practices for Integration
### 1. Understand Access Roles
When integrating with a Fireblocks client, expect to receive **Viewer** or **Editor** access only. **Signer** and **Admin** roles are not granted to maintain the client's security. These roles should be sufficient for most integrations to view data and perform necessary actions. Learn more about Fireblocks user roles in the ["Manage Users](/docs/manage-users)" guide.
### 2. Secure API Key Management
As a provider, you are responsible for securely generating and managing API keys:
* Generate an RSA private key and CSR, sharing only the CSR with the Fireblocks client.
* **Never share private keys with clients or transmit them over the internet**.
Consult the [Fireblocks API Key Management Documentation](/docs/manage-api-keys) for specific details on managing API keys securely.
### Always generate the RSA private key yourself and share the Certificate Signing Request (CSR) with the client. Never request the client to provide their private key!
### 3. Request a Dedicated API Key
For every new client integration, request a separate API key. This practice allows clear separation of access per client and aids in efficient management and troubleshooting.
### 4. Provide IP Addresses for Whitelisting
To ensure your integration is secure, supply the client with your server's IP addresses for whitelisting. This step helps secure API communication and restricts access to trusted IPs.
### 5. Efficient Data Synchronization
To avoid overloading the client's Fireblocks API and ensure a smooth initial data sync, it's recommended to start with balance and address reports shared directly from the Fireblocks Console. Coordinate with the client for a safe and efficient data transfer process.
### 6. Use Webhook Notifications
Reduce the need for frequent API polling by configuring webhooks that allow real-time updates from the Fireblocks client. This setup improves efficiency and ensures up-to-date data synchronization.
Check the [Webhook Configuration Guide](/reference/configure-webhook-urls) for configuration steps.
### 7. Transaction Initiation Without Signing
If your integration requires initiating transactions, ask the client to configure your access according to their **Policies**. This will ensure that your API key can initiate transactions, but any signing or approval must be performed by the designated signer configured in the Policy. This designated signer should be the customer themselves!
# Integrating third-party AML providers
Source: https://developers.fireblocks.com/docs/integrating-third-party-aml-providers
Fireblocks offers direct integrations with AML providers Chainalysis and Elliptic. If you prefer to use a different provider, you can use the workflows below to integrate a third-party service into your workspace.
### **Note**
AML screening policies within Fireblocks, including our [Autofreeze](https://support.fireblocks.io/hc/en-us/articles/6878328090780-Autofreeze-assets-from-incoming-transactions) functionality, are only supported by our direct integrations. These policies will not apply to third-party providers.
# Outgoing transactions
There are two methods for screening outgoing transactions: manual pre-screening and automated screening.
## Method 1: Manual pre-screening
You can manually send transaction details to your AML provider before sending the transaction to the blockchain. In this scenario, one of your users initiates the transaction and sends the details to your AML provider for screening.
Once you receive the screening results, you can either reject the transaction (if the risk profile is high) or accept it and send it to Fireblocks. You can also set up alerts to notify interested parties about the transaction.
## Method 2: Automated screening using the Callback Handler
You can automate third-party AML screening for outgoing transactions using:
* **Fireblocks API**: the endpoints used for initiating the transaction.
* **API Co-Signer**: a Fireblocks-provided component that automates transaction signing and must be installed on an Intel SGX-enabled server you provide.
* **Callback Handler**: an HTTPS server that receives the transaction details and automatically sends the details to your AML provider.
You must also develop a custom logic that determines whether to accept or reject transactions based on the AML screening result, as follows:
1. You initiate a transaction using the Fireblocks API.
2. The transaction goes through your [Policies](/docs/capabilities#transaction-authorization-policy-tap). If authorized, it is then sent to the co-signer gateway for signing.
3. The API Co-Signer (located in your secure environment) long-polls and fetches the transaction details from the co-signer gateway.
4. The API Co-Signer sends a request to the Callback Handler with the transaction details.
5. The Callback Handler sends the transaction details to your third-party AML provider for screening.
6. The AML provider responds with the screening result.
7. According to your custom logic, the Callback Handler accepts or rejects the transaction based on the screening result.
* If the risk profile is high, the Callback Handler responds to the API Co-Signer with Reject. The API Co-Signer does not sign the transaction, and the transaction is canceled.
* If the risk profile is acceptable, the Callback Handler responds to the API Co-Signer with Accept. The API Co-Signer signs the transaction and sends it back to the co-signer gateway for broadcasting to the blockchain.
### **Note**
The API Co-Signer expects a response within 30 seconds of sending the initial request. If the Callback Handler does not respond within 30 seconds, the transaction is not signed and is canceled.
# Incoming transactions
For incoming transactions, you have two options for managing the compliance status of your transactions: automated screening or manual review.
### **Important**
The automated and manual methods cannot be used together. You must choose one method for screening incoming transactions.
## Method 1: Automated Screening
You can use a custom workflow to send incoming transaction details to your AML provider for automated screening. To do this, you must [configure a webhook](/docs/webhooks-notifications) that notifies you when a new transaction is received. The webhook also contains the transaction's details, which you can then send to your AML provider.
Once you receive the screening results, you have two options:
1. You can [freeze](/reference/freezetransaction) the transaction if the risk profile is high. An Admin can later [unfreeze](/reference/unfreezetransaction) it.
2. You can do nothing if the risk profile is acceptable, and the funds remain immediately spendable within your wallet.
You can also set up alerts to notify interested parties about the transaction.
## Method 2: Manual Screening Verdict
### **Note**
This feature is currently available to a limited group of customers. To enable it, contact your [Fireblocks Customer Success Manager](https://support.fireblocks.io/hc/en-us/requests/new?ticket_form_id=6947882197532).
The Manual Screening Verdict feature provides a simplified, manual process for managing the compliance status of incoming transactions. Instead of relying on automated screening, it gives you full control to manually review and decide on transactions using your own internal tools and procedures. How it works:
1. **Pending Screening State**: All incoming transactions are automatically flagged and placed in a `PENDING_SCREENING`state. In this state, the transaction is paused until your compliance team reviews it.
2. **Manual Review**: Your compliance team reviews the transaction using your internal procedures (e.g., AML checks or other risk controls).
3. **Submit a Verdict**: Once the review is complete, you submit your decision via the dedicated API endpoint: `POST /aml/verdict/manual`.
1. **ACCEPT**: This releases the transaction from its pending state, allowing it to be processed.
2. **REJECT**: This flags the transaction as rejected for AML reasons. Rejected transactions are automatically frozen in Fireblocks.
4. **Timeout**: If no verdict is provided within the timeout window (default: one hour), Fireblocks will automatically **REJECT** the transaction.
### **Note**
Manual Screening Verdict applies only to incoming transactions. Outgoing transactions bypass this workflow and are not affected.
# Intel SGX Co-signer Architecture
Source: https://developers.fireblocks.com/docs/intel-sgx-api-co-signer
### Learn how to install SGX Co-signer in Azure in the [following guide](/reference/install-api-cosigner-azure)
## Resources used by the SGX Co-signer
The Fireblocks SGX Co-signer utilizes Intel's SGX enclave and attestation mechanisms. It can be deployed either in cloud service providers that support compatible SGX servers or on-premise using a bare-metal server. Also, an SGX driver must be loaded into the machine. This is the only resource that is required to install and operate the Co-signer on the host machine.
The Co-signer's database is encrypted and stored on the host machine's disk, serving as the Co-signer's persistent storage.
### **Important**: Allocate a separate machine for each Co-signer to prevent conflicts and ensure isolation, enhancing security.
This is illustrated in the block diagram below:
## Secure Co-signer database encryption scheme
The following process is implemented to build and secure the Co-signer's database:
1. The Co-signer, upon initialization, connects to the [Intel-SGX Remote Attestation server](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/attestation-services.html) that belongs to the Fireblocks SaaS and retrieves the key that encrypts its database: `FBKS-DB-Key`
2. The Co-signer initializes its encrypted database using the key `FBKS-DB-KEY`
3. The Co-signer encrypts `FBKS-DB-KEY` using the SGX hardware key of the host machine.
4. The Co-signer saves its encrypted database and the encrypted form of `FBKS-DB-KEY` in the host machine, serving as its persistent storage
5. The Co-signer cannot operate unless it is attested against Fireblocks' Remote Attestation server.
This is illustrated in the block diagram below:
## Installation artifacts
The SGX Co-signer is comprised of several components:
1. Installation script: This is the CLI interface for installing and managing the Co-signer. You can retrieve the installation script from the Console. The script includes the path to a Docker image registry for downloading the Co-signer Docker image. It supports downloading images of various versions, with default versions specified if none are explicitly provided. See the [SGX Co-signer version history](/reference/api-cosigner-versions-sgx) for details on the image version.
2. Docker image: The Co-Signer's executable is wrapped in a Docker image to provide safe, versioned, and consistent installation across different platforms. The Docker image provides all the libraries and dependencies of the main executable.
3. Main loading executable: A slim binary that downloads and verifies the enclave and exposes command line interfaces.
4. Secure SGX enclave: This component contains most of the Co-Signer's code and logic. It is both encrypted and signed by Fireblocks, and it can be downloaded from the Fireblocks server during setup.
* **Q: Should I verify the executable's signature?**\
If you are using the correct Docker image, as specified by the script, there is no need for any other verification, as it is embedded in the image.
* **Q: Why is the enclave encrypted?**\
SGX allows for saving the enclave encrypted on disk with a hardware key only available to the specific CPU where the enclave would be executed. Secured enclaves prevent the risk of modification, make it impossible to reverse engineer, and hide any potential secrets embedded within them. This enclave alone is capable of reading the secrets stored by the Co-Signer.
* **Q: Should I verify the enclave's signature?**\
There is no need for that. The Fireblocks signing key is embedded within the loading executable, which verifies the enclave's signature whenever it is loaded.
* **Q: Where do I find the enclave in the docker image?**\
The enclave is only downloaded when the Co-signer goes through a setup or upgrade process, so it is omitted from the Docker image. The name of the file is `enclave.signed.so`.
The chain of trust follows the sequence: **script > image > executable > enclave**, with Fireblocks ensuring compatibility between these components. During setup or upgrade, the Co-signer downloads the latest enclave version from Fireblocks servers, which is guaranteed to be compatible with the installed executable. To ensure the enclave uses the latest published version, always use the most recent Co-signer Docker image. The safest approach is to install the Co-signer using the latest installation script.
# Interact With Smart Contracts
Source: https://developers.fireblocks.com/docs/interact-with-smart-contracts
## Interaction with Smart Contracts
Interacting with a smart contract involves calling read or write methods on a specific contract. These functions can range from simple standard ERC-20 methods to complex smart contract logic invocations. Fireblocks offers several ways to interact with smart contracts:
1. **Interact with a Deployed Smart Contract via the Fireblocks Console** - Learn more [here](https://support.fireblocks.io/hc/en-us/articles/12265198149660-Managing-smart-contracts-for-tokenization).
2. **Use the Fireblocks EVM Web3 Provider or Local JSON RPC Tools**.
3. **Use the Fireblocks REST API**.
## Using the Web3 Provider and Local JSON RPC Tools
These tools allow you to seamlessly integrate Fireblocks into your codebase.
### EVM Web3 Provider
The EVM Web3 Provider is an EIP1193 compatible provider that can be integrated into your EVM client library (such as ethers, web3, viem) with a simple configuration.
### Learn more about the Web3 Provider in the [following developer guide](/reference/evm-web3-provider).
### Local JSON RPC
Local JSON RPC provides the same functionality as the Web3 provider but is designed for customers who do not use JavaScript-based tools for their smart contract development and integration.
### Learn more about the Local JSON RPC in the [following developer guide](/reference/evm-local-json-rpc).
## Using the Fireblocks REST API
Direct interaction with smart contracts via the Fireblocks API can be achieved by calling the Create Transaction API endpoint. To perform a contract call, set the `operation` parameter to `CONTRACT_CALL` and include the `contractCallData` parameter in the `extraParams` object of the POST request body.
The `contractCallData` value should be the hex-encoded data you want to pass to the contract. This can be structured using well-known libraries such as web3.js, ethers.js, or similar.
### Check out the [Create Transactions Developer Guide](/reference/create-transactions#contract-call-transaction).
# Approve Amount Cap
In the ERC20 standard, the `approve` operation is a crucial function that allows a token owner to authorize another address (usually a smart contract) to spend a specified amount of tokens on their behalf. This function is commonly used in DeFi applications, token swaps, and other scenarios where tokens need to be managed by smart contracts.
### How It Works
When you call the `approve` function, you specify two parameters:
* **spender**: The address that will be allowed to spend the tokens.
* **amount**: The maximum number of tokens that the `spender` is allowed to spend.
The `approve` function updates the allowance, which is the amount of tokens that the `spender` can use. This is recorded in the token contract’s internal mapping.
### Example Use Case
Suppose you want to use a DeFi platform to lend your tokens. You would first call the `approve` function to allow the platform’s smart contract to transfer tokens from your address. Once approved, the platform can transfer the specified amount of tokens from your address to the lending pool.
The **Amount Cap** limits the amount smart contracts and third-party dApps may withdraw on your behalf. This reduces the risk associated with granting an unlimited approval amount. Transaction amounts are then automatically changed from the maximum amount to the user-specified limit for all Approve transactions created with dApps.
Learn more about limiting the [Amount Cap for Approve transactions](https://support.fireblocks.io/hc/en-us/articles/4404616097426-Amount-Cap-for-Approve-transactions) via the Fireblocks Console.
# Interact with TRUST
Source: https://developers.fireblocks.com/docs/interact-with-trust
The platform can be used to securely send information required by the Travel Rule.
To interact with TRUST from your Fireblocks workspace, you must use an appropriate format of Typed Message Signing when publishing a proof of address on the TRUST internal bulletin. This signing method is safer than (and preferred over) Raw Signing because it helps mitigate the risk of users signing a valid but malicious transaction.
### Learn more about [Typed Message Signing](/docs/typed-message-signing-1#what-are-the-use-cases-for-typed-message-signing)
# Fireblocks Developer Docs
Source: https://developers.fireblocks.com/docs/introduction
Welcome to the Fireblocks Developer Portal. Whether you're building a crypto exchange, a DeFi application, or an embedded wallet experience, you'll find everything you need to integrate Fireblocks into your product.
Connect your AI agent, set up your API key, and make your first call with the SDK or CLI.
Explore all Fireblocks REST API endpoints with interactive examples and code snippets.
Understand the platform architecture, security model, and core concepts.
Official SDKs for TypeScript, Python, and Java, Fireblocks CLI plus Postman collections and dev tooling.
## Explore by Use Case
Choose the integration pattern that matches what you're building.
Embed non-custodial wallets into your application with Fireblocks MPC technology.
Manage institutional digital asset operations across exchanges, DeFi, and staking.
Issue, manage, and distribute digital tokens using smart contract templates.
Build self-custody solutions with enterprise-grade MPC key management.
## Platform Overview
Fireblocks provides a unified platform for building on blockchain with enterprise-grade security.
## Key Capabilities
Create and manage direct custody wallets for secure asset storage.
Transfer, swap, and manage digital assets across blockchains.
React to real-time events like deposits, withdrawals, and status changes.
Deploy and interact with smart contracts across EVM and non-EVM chains.
Stake assets and manage validator operations programmatically.
Integrate AML screening and travel rule compliance into your workflows.
## Start Building
Install the [Fireblocks Documentation MCP](/docs/quickstart) first so Cursor, Claude Code, Codex, or any other agent can read these docs while you build — and so your implementation stays grounded in the canonical documentation even when you're not using an agent.
[Sign up for a free Fireblocks sandbox](https://www.fireblocks.com/developer-sandbox-sign-up) to get API access and test credentials.
[Generate a CSR and API key](/docs/manage-api-keys) to authenticate your API requests using JWT signing.
Install an [SDK](/reference/typescript-sdk) for application code, or the [Fireblocks CLI](/docs/fireblocks-cli) for fast workspace operations and agent workflows. [Getting Started](/docs/quickstart) covers both.
Walk through our guides to [create wallets](/reference/create-vault-account), [send transactions](/reference/create-transactions), or [set up webhooks](/reference/webhooks-overview).
# Tokenize Assets
Source: https://developers.fireblocks.com/docs/issue-new-tokens
# Overview
Tokenization is the representation of an asset, which could be a real-world physical asset or a digitally native one, on a distributed ledger. Tokens represent ownership, control, claim, or a right to the underlying asset or service. With Fireblocks, you can issue and manage tokens for your specific use case, such as stablecoins, carbon credits, in-game assets, concert tickets, real estate, memorabilia, artwork, NFTs, or any other asset you want to tokenize.
# Tokenization in Fireblocks
### Tokenization is a premium feature that requires an additional purchase. If you don’t have access to this feature, contact your Customer Success Manager to discuss having it enabled in your Fireblocks workspace.
The Tokenization feature allows you to deploy and manage tokenized assets and their lifecycle via the Fireblocks Console or the Fireblocks API.
## Supported assets and blockchains
Fireblocks supports token issuance and management for the following networks and assets:
* All EVM-compatible blockchains supported by Fireblocks
* Stellar
* Ripple
## Token lifecycle management
Generally, a token's lifecycle involves:
1. Issuing new tokens or linking previously issued tokens.
2. Viewing token information on the Tokenization page.
3. Executing operations (minting, distributing, burning, etc.).
You can manage the tokens in your workspace using:
### The Fireblocks Console
### Learn more about Tokenization in the Fireblocks Console [here](https://support.fireblocks.io/hc/en-us/articles/8760035076892-Tokenization-Page)
* EVM blockchains: You can call any smart contract function, such as minting and burning, for your EVM-based tokens on the Tokenization page.
* Stellar and Ripple: You can issue, mint, burn, and transfer tokens on the Tokenization page. You can also create wallets with automatically established trustlines (an explicit opt-in to hold the token).
* All supported assets: You can link tokens on the Tokenization page, where you can view detailed information about each of them.
### The Fireblocks API
* EVM blockchains: You can mint, burn, and transfer tokens using specific API operations. For all other operations, you can use contract calls.
* Stellar and Ripple: You can issue, mint, burn, and transfer tokens. You can also create wallets with automatically established trustlines.
### Explore the [Tokenization APIs](/reference/issuenewtoken) in the Fireblocks API Reference
# Overview
Source: https://developers.fireblocks.com/docs/list-supported-assets-1
Fireblocks supports thousands of assets across dozens of blockchain networks and frequently adds support for new assets. All supported assets share the same name and asset ID across every customer workspace where they are available.
To see all assets supported in your workspace, use the Fireblocks API as described in [List assets](/reference/listassets).
## Globally supported assets
Globally supported assets are available by default when you create new asset wallets in any workspace. Fireblocks publishes a complete [list of globally supported assets](https://support.fireblocks.io/hc/en-us/articles/6641409557532-Globally-supported-assets), which Fireblocks refreshes monthly.
## Locally supported assets
Locally supported assets only appear in workspaces that have manually added or requested them. They are available to transfer to any destination that supports them.
Before transferring a local asset to a Fireblocks Network destination, confirm that the counterparty supports it. For more information, see the following Help Center articles:
* [Adding EVM assets to a workspace](https://support.fireblocks.io/hc/en-us/articles/5601259928220-Adding-EVM-assets-to-a-workspace)
* [Adding non-EVM assets to a workspace](https://support.fireblocks.io/hc/en-us/articles/6641659764508-Adding-non-EVM-assets-to-a-workspace)
# Main Capabilities
Source: https://developers.fireblocks.com/docs/main-capabilities
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
## 2-of-2 MPC signature scheme
The Fireblocks Embedded Wallet (EW) feature uses a 2-of-2 multi-party computation (MPC) signature scheme to enhance the security of digital signatures. This cryptographic technique involves two parties collaborating to generate a signature. This reduces the risk of single-party compromise and enhances the overall integrity of transactions.
One key share resides on the end-user's device (mobile or web), and the second key share is securely maintained within an Intel SGX-enabled server managed by Fireblocks.
Intel SGX technology ensures that the key material stored in the SGX enclave is isolated, protected, and resistant to unauthorized access.
### End-user key share management
Fireblocks provides web and mobile SDKs to customize how you configure your key loading and key saving process. This enables you to implement security measures, such as mobile enclave, biometric authentication, two-factor authentication (2FA), and more.
The SDK itself is agnostic to the specific implementation of key storage, which is passed to it upon initialization.
## Web and mobile integrations
Fireblocks provides comprehensive software development kits (SDKs) for iOS, Android, and web platforms. These SDKs allow developers to seamlessly integrate Fireblocks cryptographic and security functions into their applications.
## Multi-device support
The Fireblocks Embedded Wallet (EW) solution allows multiple devices to perform actions using the same wallet, such as signing transactions and running takeovers. This lets you support a multi-device, multi-platform seamless digital experience and enables an end user to use their account on any of their devices.
## Backup and recovery
We also offer a variety of options for securely backing up and recovering cryptographic assets. Users can choose to store backups in the cloud, employ social logins for recovery purposes, or opt to download backups locally.
## User Takeover Ability (Export Private Key)
Our User Takeover Ability enables users to export their full cryptographic keys, providing them with the autonomy to move their assets to different wallets or services. This feature emphasizes user control while requiring careful consideration of potential security implications.
## Transaction Authorization Policy
With our [Transaction Authorization Policy (TAP)](https://support.fireblocks.io/hc/en-us/articles/7354983580316), users can define and enforce specific transaction approval rules. These rules can include requirements for predetermined approval workflows, transaction limits, and more. This feature empowers users to customize transaction security based on their unique preferences and risk tolerance.
## Web3 Wallet Link
Our Web3 Wallet Link feature facilitates interaction between decentralized applications (dApps) and various wallets using the WalletConnect v2 protocol. This allows users to securely access and manage their cryptocurrency assets across different platforms and services.
## Supported Networks
### Bitcoin, EVM-based networks, Cosmos, and TRON (private and public)
The Fireblocks EW solution supports many blockchain networks, such as the Bitcoin blockchain and various networks based on the Ethereum Virtual Machine (EVM), Cosmos, and TRON. Users can securely interact with and manage their Bitcoin and EVM-based assets using our platform.
Currently, Fireblocks provides support for more than 30 EVM-based public blockchains, including several well-known ones such as Polygon, Base, BNB Smart Chain, Evmos, Moonriver, Optimism, Arbitrum One, Moonbeam, and many more. Additionally, the Fireblocks EW provides instant support for any EVM-based blockchain that becomes integrated with the Fireblocks platform. This includes private and public networks that are within our supported ecosystem.
### ERC-20, ERC-1155, and ERC-721 Tokens
The Fireblocks EW extends its support to Ethereum's token standards, namely ERC-20, ERC-1155, and ERC-721. This allows users to manage a wide array of digital assets, including fungible tokens (ERC-20), semi-fungible tokens (ERC-1155), and non-fungible tokens (ERC-721) through our platform.
Whether you're dealing with Bitcoin or participating in various EVM-based ecosystems, the Fireblocks EW allows you to seamlessly integrate and securely manage assets. Additionally, our support for Ethereum's token standards allows you to handle a wide range of tokens.
# Manage API Access
Source: https://developers.fireblocks.com/docs/manage-api-keys
# API Authentication
The Fireblocks API uses an API key and a request-signing process to provide a highly secure communication protocol. You can create API keys through the Fireblocks Console or the API.
## Create an API key in the Console
To create your first API key:
1. Generate an RSA 4096 private key and CSR file:
```bash Shell theme={"system"}
openssl req -new -newkey rsa:4096 -nodes -keyout fireblocks_secret.key -out fireblocks.csr -subj '/O='
```
2. In the Fireblocks Console, go to the [Developer center's API users page](https://console.fireblocks.io/v2/developer/api-users).
3. Select **Add API user**.
4. Enter a display name for the API key (up to 30 characters) and select the appropriate role. Permissions follow the same [user roles](/docs/manage-users) used for Console users.
5. Upload the CSR file you generated in step 1.
6. Select whether a Co-signer setup is required.
1. If you're in a testnet workspace, you can connect to the [Fireblocks Communal Test Co-signer](/reference/use-communal-cosigner).
2. Only select **First user on this machine** if you're using the API user to install a new SGX Co-signer.
7. Select **Add user**.
After the required approval quorum is reached, the API key appears in the API users list. You can copy the API key from there by hovering your pointer over the value in the **API User (ID)** column.
Every request using this API key must follow the [Fireblocks API authentication scheme](/reference/signing-a-request-jwt-structure).
## Create an API key via the Fireblocks API
Complete step 1 from the Console procedure above to generate your RSA key and CSR file, then call the [Create API Key](/reference/createapiuser) endpoint to complete the API key creation operation.
# API key management best practices
Your API credentials are a prime target for attackers. Fireblocks recommends following these best practices to work securely with our APIs.
## Role-based access control
Provision each API user's role according to the principle of least privilege. Fireblocks supports multiple roles for role-based access control, and an API user can hold any one of them. Create separate API users to enforce duty separation and establish clear security boundaries.
### Best practice
Create at least two API users with distinct roles. For example, a Viewer role for read-only operations and a Signer role with transaction-signing capabilities.
## Policy rules for API users
API users with transaction initiation and signing capabilities can execute transactions like any Console user. Create strong Policy rules to govern what transaction types these API users can conduct and from which accounts.
### Best practice
Limit API users to transact from a specific vault account and up to a defined amount. This blocks or flags transactions that exceed the pre-defined limits or originate from unauthorized accounts.
## IP address allowlisting
Each API user can restrict API calls to specific IP addresses. If no IP addresses are allowlisted, the API accepts requests from any address. Explicitly allowlist only the IP addresses you expect to call the Fireblocks API.
### Address format
Only /32 IP addresses are accepted. Do not enter addresses as a range of values.
## Generating and storing RSA 4096 private keys
Each API user requires a public/private key pair to sign requests. Keep your `fireblocks_secret.key` file safe and secure at all times.
To protect your key pair:
* Generate a unique CSR file and key pair for each API user. This limits the blast radius if one user's keys are compromised.
* Generate the CSR file and key pair in an offline (air-gapped) environment for added security.
* Store `fireblocks_secret.key` in a hardened environment with advanced security controls such as multi-factor authentication and endpoint protection.
## Storing API keys outside your codebase
Never embed API keys directly in code or commit them to your source tree. Keys embedded in code can be accidentally exposed, especially if you use a public source control system such as GitHub. Instead, store API keys in environment variables or in files outside your application's source tree.
## Rotating secrets
Rotation works differently depending on the API user type:
* **Fireblocks API users:** Because authentication relies on a CSR and associated secret key, create a new API user to rotate credentials.
* **Co-signers:** Re-enroll the API user to obtain a new pairing token, then complete the pairing process to receive a new refresh token.
* **Fireblocks Agent for KeyLink:** Uses the pairing token, access token, and device. This user type does not hold MPC keys.
### Best practice
Before rotating, use the [Get all API keys](/reference/getapikeys) endpoint to list all API keys paired to a specific API Co-Signer.
# Manage Deposits at Scale
Source: https://developers.fireblocks.com/docs/manage-deposits-at-scale
## Overview
One of the most important processes for a business is the ability to handle deposits made by clients. To facilitate this, each client needs their own wallet for the asset they want to deposit.
This requirement applies to both scenarios: deposits made by clients from external sources and on-ramp processes such as purchasing crypto and storing it in their address. Both flows result in the creation of a new wallet for the specific user.
Businesses serving hundreds of thousands or even millions of users need to create and manage these addresses and the deposited funds in the most operationally and cost-effective ways.
In this guide, we will outline the recommended workflows for Fireblocks clients to achieve an efficient setup for processing user deposits. The topics covered include:
* Setting up the correct wallet structure for your use case
* Receiving notifications on incoming transfers
* Processing UTXO and Tag/Memo-based asset deposits
* Processing account-based asset deposits
* Best practices for generating deposit addresses
* Validating wallet balances
* Maintaining an internal ledger
## Setup the Wallet Structure
The wallet structure, or as we call it in Fireblocks, the vault structure, that you set up will directly impact the capabilities, efficiency, and operational load of your business. Fireblocks recommends one of the following two setups, depending on the type of your operation:
* **Segregated Vault Structure**: Ideal for customers running a B2B business. This setup is recommended for those who want full segregation of their clients' funds.
* **Omnibus Vault Structure**: Ideal for customers running a B2C business. This setup is recommended for those who want to create a dedicated wallet for each user and then sweep the funds into a single Treasury wallet.
### Learn more about the Fireblocks [Vault Structure types](/docs/create-direct-custody-wallets#types-of-vault-structures)
## Get Notifications for Incoming Transactions
To receive notifications about incoming transactions to your Fireblocks wallets, we recommend using the Webhook service.
Webhooks are push notifications sent by Fireblocks to a URL specified by the customer. This service sends notifications about various events in your Workspace, including incoming funds. Each incoming transaction triggers a series of events, starting with an alert that a new transaction has been identified, followed by subsequent notifications about the transaction's completion status.
### Learn more about the Fireblocks [Webhook service](/reference/configure-webhook-urls)
## Process UTXO and Tag/Memo Based Assets Deposits
Customers who find the Omnibus structure suitable for their business needs and work with UTXO-based assets will notice that all such assets (e.g., BTC, BCH, LTC, DOGE, ADA) are deposited into a single "Deposit" vault account. Each user has their own deposit address identified by the `description` parameter.
Processing these funds is straightforward in terms of address generation and management, but it introduces some potential challenges that should be considered during the integration phase. When running a retail-facing business and processing a large volume of UTXO-based asset deposits, customers may find that their deposit vault account accumulates a significant number of unspent transaction outputs (UTXOs) for a specific asset. Efficiently managing these UTXOs is crucial for the following reasons:
1. **Creating Outgoing Transactions**: Customers might want to move deposited funds (or part of them) to different venues such as exchange accounts, withdrawal vaults, or even a cold wallet. The number of UTXOs that can be selected for a transaction is limited to 250 UTXOs per transaction. This limitation could prevent customers from moving the desired amount if the selected 250 UTXOs do not add up to the intended amount. This depends on the UTXO selection mechanism in your Fireblocks wallet, which by default chooses the **smallest confirmed UTXOs first**. The selection mechanism can be adjusted to select the largest confirmed UTXOs first, based on customer preference.
2. **Fee Efficiency**: If a wallet has many small UTXOs, creating outgoing transactions will require selecting more UTXOs to reach the required amount. This results in larger transaction sizes and higher fees, making the transaction more attractive to miners/validators.
To overcome the mentioned in the above, customer should implement a UTXO consolidation logic as described in the following section.
### Unique deposit addresses via shared wallets
For UTXO-based chains, we recommend a similar approach to memo-based chains. Calling the [Create a new deposit address](/reference/createvaultaccountassetaddress) endpoint generates a new deposit address under the same wallet. Each end user receives a unique deposit address while funds are still received into a shared wallet. End-user deposits are identified by the receiving address included in the transaction notification, eliminating the need to create separate wallets per user.
### UTXO Consolidation
UTXO-based transactions in Fireblocks have a limit of 250 inputs (UTXOs) per transaction. Additionally, there must be a logic to select the inputs for a transaction, which Fireblocks implements as follows:
1. **DEFAULT Selection Mechanism**: By default, Fireblocks selects the first 250 smallest confirmed inputs available for a specified vault account. This helps customers use up small UTXOs and reduce the number of available UTXOs in their vault account.
2. **Configurable Selection Mechanism**: Fireblocks can be configured to select the 250 largest confirmed inputs first. This configuration requires opening a request with our support team.
This consolidation transaction is typically made from the Deposits vault account to one of the Withdrawals vault accounts to maintain a sufficient asset balance for user withdrawals. However, the transaction can also be executed with multiple destinations, such as different vault accounts, exchange accounts, external addresses, or even a cold wallet.
The trigger for the consolidation process can be based on the number of deposits made into the Deposits vault account. For instance, customers can decide that after every 250 deposits (tracked by an internal counting logic), the system will automatically create the consolidation transaction. Others may choose to execute this transaction based on current network fees to save on transaction costs.
Fireblocks provides two important endpoints to help clients build their UTXO consolidation logic:
1. [Get Maximum Spendable Amount in a Single Transaction](/reference/getmaxspendableamount): This endpoint returns the maximum amount of a particular asset that can be spent in a single transaction from a specified vault account.
2. [Create Transaction](/reference/createtransaction): This endpoint creates a transaction with the specified amount returned from the endpoint above.
Additionally, clients who want to trigger the consolidation transaction based on the number of deposits made into their Deposits vault account can use the Fireblocks [Webhook service](/reference/configure-webhook-urls) to get notifications on completed incoming transfers.
### Check out the UTXO Consolidation [Developer Guide](/reference/consolidate-utxos)
## Process Account Based Asset Deposits
Customers who want to generate a unique address for each of their end-users need to create a new intermediary vault account for each user and then the required vault wallet within this newly generated vault account. This is necessary because account-based assets do not support the generation of multiple addresses under the same wallet.
Once the generated address is shared with the end-user and the end-user makes a deposit into that vault account, most customers will want to perform a sweeping operation. This operation consolidates all deposited funds from the intermediary vault accounts into a single treasury management vault account for various business purposes.
Sweeping funds involves moving assets from address A to address B. It is important to note that this is an on-chain operation and includes transaction fee payments.
### Learn more about the [Sweeping Mechanism](/docs/sweep-funds)
While sweeping base assets like ETH is straightforward, sweeping deposited ERC20 tokens presents a challenge. This is because the transaction fee must be paid in the network's base asset, which end-users might not have in their wallets. To address this issue, Fireblocks recommends using the Fireblocks Gas Station feature.
### Learn more about the Fireblocks [Gas Station](/docs/work-with-gas-station)
### Memo and tag-based deposit identification
For account-based chains, we recommend creating a dedicated vault account for each end user and managing all of their associated wallets within that account.
Some chains, such as Stellar and Ripple, support deposit identification using a memo or tag (see the full list [here](/reference/vault-objects#createaddressresponse)). On these chains, you can assign each end user a unique memo or tag to identify their deposits using the [Create a new deposit address](/reference/createvaultaccountassetaddress) endpoint. This allows multiple users to deposit into a shared wallet without needing a separate vault account or wallet per end user. Deposits are credited by matching the memo or tag field included in the transaction.
This shared-wallet approach reduces operational overhead and fees by eliminating the need for sweeping funds and allowing reconciliation through a single or small number of transactions. However, it is still considered good practice to separate vault accounts by function. For example, cold storage, warm wallets, deposits, withdrawals, and treasury.
**Important**
The main disadvantage of this approach is that you must manage internal credits and balances based solely on transactions, because there is no on-chain balance to validate. Your internal system becomes the source of truth.
## Create Deposit Addresses Best Practices
Customers serving hundreds of thousands or even millions of users will eventually need to create a corresponding number of deposit addresses within a single vault account (for UTXO deposits) and/or intermediate vault accounts (for Account Based assets) in their workspace. A basic implementation is to create a new deposit address or vault account for the end-user whenever the user registers for the service or requests a deposit address for a specific coin.
In this setup, customers make a real-time API call to Fireblocks to generate a new deposit address or create a new vault account with a vault wallet for the requested asset, triggered by the end-user request.
While this approach is acceptable, the best practice we recommend is to create these deposit addresses or intermediate vault accounts proactively. Fireblocks customers should run a service that continuously creates addresses, vault accounts, and vault wallets, regardless of user requests.
This proactive approach means maintaining a pool of pre-generated vault accounts and addresses. When a user requests a new deposit address, customers can quickly assign a pre-generated address instead of making a real-time API call to Fireblocks. This reduces the risk of encountering API errors in real-time and significantly decreases the waiting time for users to receive a new address, thereby enhancing the user experience and providing a near real-time service.
### Pre-creating vault accounts
We recommend pre-creating vault accounts in advance. When an end user requests access, you can create the required wallets later and assign them to one of the pre-created vault accounts. To manage scale efficiently, you can maintain either high or low vault account thresholds — once the number of available accounts reaches a low threshold, resume creating accounts until the required threshold is met.
When a wallet is created for an end user, assign it to the appropriate pre-created vault account and update the assignment in your internal systems.
### Resource identification
To map resources to the correct end users, we recommend using the following fields:
* **Vault account:** use the `name` field
* **Wallet:** use the `description` field
Assign these fields at resource creation time and use them internally for end-user assignment.
**Important**
Do not store personally identifiable information (PII) in these fields.
### Vault account visibility
When creating deposit vault accounts, set the `hiddenOnUi` flag to `true`. This helps ensure proper management of important vault accounts in the Fireblocks Console.
### Wallets requiring on-chain creation
Some wallets require an on-chain operation to be created, including:
* SPL tokens (Solana)
* Ripple tokens
* Stellar tokens
* HBAR
* EOS
For SPL tokens, Associated Token Accounts (ATAs) can be created by receiving a token transfer from an external source. The account creation fee is included as part of that transfer.
While SPL, Ripple, and Stellar tokens use fees taken from the wallet itself, EOS wallets are currently funded by Fireblocks treasury and are expected to be used reasonably. In the future, the funding for these wallets will transition to a self-bootstrapped model.
To associate the pre-generated address with the end-user, during the assigning process on the customer's side, the following APIs should be called to synchronize both Fireblocks and the customer's internal system with the user reference:
1. **UTXO and Tag/Memo Based Assets**: When assigning a new UTXO-based asset deposit address within your Deposit vault account for a new user, call the [Update Address Description API endpoint](/reference/updatevaultaccountassetaddress) with the newly assigned user reference as the description.
2. **Account-Based Assets**: When assigning a new intermediate vault account for an end-user, call the [Rename a Vault Account API endpoint](/reference/updatevaultaccount) with the newly assigned user reference as the vault account name. Ensure that the vault account name does not contain any PII data.
## Validate Balances
Fireblocks allows you to receive notifications about incoming transactions to your Fireblocks vault accounts. A common setup for Fireblocks customers is to subscribe to the webhook service and get notified whenever a new deposit is made into a vault account. When an event for an incoming transaction is triggered, followed by an event confirming the deposit's completion, the typical setup on the customer's end will automatically update the internal ledger and adjust the balance of the user associated with the deposited vault account.
While this approach is generally correct, Fireblocks recommends implementing additional validation steps before crediting the end user with the deposited amount to avoid potential loss of funds.
### Validating Incoming Balances is crucial!
Learn more about the best practices for validating balances and performing reconciliation processes in the following [guide](/docs/validate-balances)
## Maintain an Internal Ledger
An internal ledger is a fundamental component to consider when building a retail-facing solution. Essentially, it records incoming transfers and balances for your users.
Maintaining this ledger is crucial because funds deposited by users into their accounts are often swept or moved to a different account, as described in the sweeping mechanism section. You need to accurately track how much each user has deposited and what balance should be displayed in your system.
Fireblocks does not provide a built-in component or feature for this specific need, so customers can implement it in any way they see fit. However, Fireblocks offers all the necessary utility tools and features to effectively maintain such a ledger. This includes APIs for validation and reconciliation processes and a webhook service that allows you to create an event-driven system triggered by various events in your Fireblocks workspace.
# Overview
Source: https://developers.fireblocks.com/docs/manage-users
Fireblocks users can be added either via the web console or via the API:
* For adding users via the console please refer to [this guide](https://support.fireblocks.io/hc/en-us/articles/360012832959-User-roles)
* For adding users via the API please refer to the following [API endpoints](/reference/createconsoleuser) Generally, there are different user roles that can be assigned to a specific user, please see the user role table below:
There are different API Key types. Each type contains other capabilities in addition to transaction permissions.
| API Key Type | Role | Transaction Permissions | Environment |
| --------------------- | ----------- | --------------------------------------------------------- | -------------------- |
| **Admin** | Signing | Can sign transactions. | Production |
| **Non-Signing Admin** | Non-Signing | Can't sign transactions. | Production + Sandbox |
| **Signer** | Signing | Can sign transactions. | Production |
| **Approver** | Non-Signing | Can't sign transactions. | Production |
| **Editor** | Non-Signing | Can't sign transactions. | Production + Sandbox |
| **Viewer** | View-Only | Can only view transaction history. | Production + Sandbox |
| **Security Auditor** | View-Only | Can only view transaction history and workspace elements. | Production + Sandbox |
| **NCW\_ADMIN** | Non-Signing | Can only manage Non Custodial Wallets. | Production + Sandbox |
| **NCW\_SIGNER** | Signing | Can only sign transaction from Non Custodial Wallets. | Production + Sandbox |
Defining users in your workspace may seem straightforward, but it requires careful alignment with the supported roles.
Whether your goal is maximum security or optimal work efficiency, the right approach depends on your specific business use cases.
Before getting started, familiarize yourself with [user groups](https://support.fireblocks.io/hc/en-us/articles/7249202090396-User-group-management-and-best-practices) and [approval groups](https://support.fireblocks.io/hc/en-us/articles/11500062124188-Approval-groups) . These two features are crucial for defining user roles and actions in your Fireblocks workspace and can significantly enhance your operational efficiency and security.
* Segregate users into two categories: those responsible for managerial decisions and changes, and those handling day-to-day operations. Differentiating between users who can make changes in the workspace and those who can only initiate or sign transactions will enhance security. For more details, refer to [this guide](/docs/segregate-duties) .
* Always consider the admin quorum approval. The more approvals required for a workspace change, the longer and more complex the implementation process will be.
* Start by defining groups and their tasks. Based on these tasks, identify the roles that match and add individual users accordingly. Managing your operations with the correct setup of groups will enhance the performance of regular operations and facilitate general workspace changes.
Follow the general best practices when choosing users and roles as outlined [here](https://support.fireblocks.io/hc/en-us/articles/5254222799900-Best-practices-for-choosing-user-roles) .
## API Users Use Cases
API users can be used either to access Fireblocks API or to be paired with a cosigner (one can be both at the same time, but this is not the best practice).
In the case of an API user used to access the API, it has API key and API Secret that are required for authentication.
In the case of an API user paired with a cosigner, it has MPC key shares if it's a Signer or Admin, a One-time pairing token, and Device in case it's an API user that is paired with a device.
In the case of an API user used for KeyLink, it does not have MPC keys, but it has the pairing token, the access token, and the device.
# Manage Withdrawals at Scale
Source: https://developers.fireblocks.com/docs/manage-withdrawals-at-scale
# Withdrawal Flow
Withdrawals are one of the most critical and active functions in any retail-facing crypto business. Users depend on the withdrawal process to move funds quickly and securely. Designing an efficient, secure withdrawal flow is essential to delivering a reliable platform.
## Automate the withdrawal flow
### Setup
Automation is essential for ensuring a smooth, uninterrupted 24/7 withdrawal service. Relying on manual transaction signing is not scalable and introduces significant security risks. To address these challenges, implement a [Fireblocks Co-Signer](/reference/api-cosigner-management) component. This approach guarantees continuous operation and enhances the overall security of your withdrawal process.
### Highly available setup
One best practice for automation is setting up a highly available system by implementing the Co-signer in active/active mode. In this configuration, systems can take over from one another without downtime, ensuring that failover capability is always in place. For more information, see [Fireblocks Co-signer High Availability setup](/docs/multiple-cosigners-high-availability).
### Co-Signer logging and monitoring
Comprehensive monitoring and alerting are vital for maintaining a secure and reliable automated signing process. Setting up these systems lets you track transaction status in real time and detect anomalies that may indicate potential issues. Configure alerts to notify relevant personnel immediately when transactions are stuck or suspicious activity is detected, enabling prompt intervention.
For more information, see [API Co-signer Maintenance](/reference/api-cosigner-maintenance).
## Implementing multiple withdrawal wallets
### Withdrawal pool
Using multiple withdrawal vault accounts can help reduce the impact of stuck transactions and enable higher throughput. Distribute user withdrawal requests across several withdrawal vault accounts using a round-robin mechanism (a circular execution pattern between wallets) to reduce the risk of transaction queues.
While multiple withdrawal vault accounts offer clear throughput benefits, they also introduce operational complexity. Keep the following in mind:
* **Balance monitoring:** Regularly monitor the balance of each wallet to ensure sufficient liquidity.
* **Automated refills:** Implement automated refill mechanisms to transfer funds between wallets as needed.
Multiple withdrawal wallets are particularly beneficial for Ethereum, which uses the nonce mechanism and therefore processes transactions sequentially, and for UTXO-based assets like Bitcoin. In the UTXO model, an unconfirmed output from a previous transaction can be used as input for a new one. This can result in a chain of stuck transactions if the first is not confirmed.
Although mechanisms like [Replace By Fee (RBF)](/docs/boost-transactions-1#rbf-and-cpfp-in-fireblocks) and [Child Pays For Parent (CPFP)](/docs/boost-transactions-1#rbf-and-cpfp-in-fireblocks) exist to release stuck transactions, relying on them is not ideal. The Bitcoin protocol also has a built-in mechanism that rejects transactions using an unconfirmed output from a transaction with more than 25 predecessors. This can create a queue of withdrawals and, in some cases, cause withdrawal failures.
### Number of withdrawal wallets
A typical ECDSA-based chain transaction takes 6–7 seconds from initiation to broadcast. EdDSA-based chain transactions are slightly faster by about a second. On chains other than Solana and Tron (where parallel processing is not supported), Fireblocks serializes and signs transactions only after observing the previous transaction on the chain or node (TAP evaluation is still performed in parallel). In some cases, there is an additional delay of approximately 2 seconds before the transaction or its artifact is observed after submission.
For each sustained 1 TPS, we recommend using 5–6 withdrawal wallets and routing each new withdrawal to the next wallet in round-robin order. This guidance applies to steady-state throughput rather than short-term peaks. Queued transactions are acceptable as long as the queue continues to clear.
### Pay close attention to transaction queues
Rapid growth may indicate that the Co-Signer is not signing transactions fast enough — this can be caused by slow callbacks, underpowered machines, or insufficient Co-Signers. If transactions remain queued for more than two hours, cancel and resubmit them, as they are likely to fail due to a timeout.
For wallets that support parallel processing (specifically Solana and Tron), enable parallel processing for up to four transactions. This configuration typically requires two withdrawal wallets per 1 TPS.
| Chain type | Recommended withdrawal wallets | Notes |
| ----------------- | ------------------------------ | ------------------------------------------------------------- |
| EVM / ECDSA-based | 5–6 per 1 TPS | Round-robin routing; monitor for stuck nonce chains |
| Bitcoin (UTXO) | 2–3 per 1 TPS | Batch in 30-second windows; stay under 25-tx chain limit |
| Solana / Tron | 2 per 1 TPS | Enable parallel processing (up to 4 concurrent tx per wallet) |
| Stellar | \~10 per 1 TPS | One tx per account per ledger (5s intervals) |
## Blockchain-specific guidance
### EVMs
Fireblocks supports advanced nonce management for EVMs to improve transaction latency and throughput. If a transaction fails and is not mined, its nonce can be reused by the next transaction from the same wallet, preventing the transaction chain from getting blocked.
Monitor transactions closely and identify any stuck in a confirming state from the same wallet. This is usually caused by a stuck low-fee transaction. Boosting or replacing the transaction via RBF allows the next transaction to be pushed to the chain. Identifying such situations early is critical; otherwise, you may submit multiple transactions with low fees, causing a backlog.
### Watch for delays due to fee spikes
Some node implementations enforce per-address submission limits when transactions have low fees, long nonce chains, or unconfirmed dependencies. Although the Fireblocks framework can retry dropped transactions, delays during fee spikes can cause low fees and additional stuck transactions.
We recommend having several withdrawal accounts and routing withdrawals uniformly across them. Using five to six wallets enables approximately 1 TPS throughput.
### UTXOs
Under the current design, a UTXO wallet can serialize a single transaction at a time. In some cases, unconfirmed change outputs are reused in subsequent transactions, which can result in a stuck wallet if:
* A transaction is not mined due to low fees.
* The dependency chain reaches the maximum chain length of 25 unconfirmed transactions (common in Bitcoin nodes), causing new transactions to be rejected.
To avoid this situation, use one or more of the following methods:
* Batch withdrawals using multi-destination transactions. Creating a batch every 30 seconds results in 20 transactions over 10 minutes, staying below the 25-transaction limit.
* Schedule sweeping or funding to withdrawal wallets to obtain multiple confirmed UTXOs, reducing reliance on unconfirmed change outputs.
* Use CPFP to release transactions stuck due to low fees. Apply CPFP before reaching the 25-transaction chain limit. (RBF support is planned for the future.)
* Use multiple withdrawal wallets, as described earlier.
In general, aim to balance the number of UTXOs. Too many UTXOs are harder to reconcile; too few can cause mempool congestion and unconfirmed transactions.
For Bitcoin, we recommend holding two to three withdrawal wallets and batching withdrawals in 30-second windows.
For additional details on UTXO selection logic and filtering, see [Select UTXOs](/reference/select-utxos-for-a-transaction).
### Solana and Tron
On Solana, Fireblocks supports parallel transaction serialization per wallet using durable nonces, with up to 1,000 concurrent transactions in non-finalized states. Fee payer transactions and support for transactions without durable nonces are planned for the future.
For Tron, parallel serialization of transactions per wallet is planned by EOQ2, with support for up to 600 concurrent non-finalized transactions.
### You need multiple Co-signers for high-throughput setups
High-throughput setups require multiple Co-signers that can handle parallel traffic. Additional Co-signers can be configured as needed.
### Stellar
Stellar uses sequence numbers and allows only one transaction per account per ledger (created every 5 seconds). As a result, throughput from a single wallet is limited. We recommend creating approximately 10 Stellar withdrawal wallets per 1 TPS. Fireblocks is considering support for channel accounts to enable better throughput and latency.
## Confirmation policy
Blockchain confirmations verify transactions while preventing fraud and double-spending. However, the confirmation threshold directly affects how quickly funds become available: the higher the threshold, the longer the delay.
For internal operations like sweeping or reconciliation, you can define a low confirmation requirement. Setting confirmations to `0` means:
* On **Bitcoin-based chains and EVMs**: the transaction is considered complete once it enters the mempool.
* On **other chains**: the transaction is considered complete immediately once included in a block.
On Bitcoin-based UTXO chains, setting confirmations to `0` also allows the resulting UTXOs to be immediately used in subsequent transactions.
For more information, see [Deposit Control & Confirmation Policy](/docs/define-confirmation-policy).
## Transaction batching
Transaction batching lets you consolidate multiple withdrawal requests into a single transaction with multiple destinations, minimizing fees. Because a batched transaction carries a single set of metadata, it is more cost-effective than multiple individual transactions. Fireblocks supports transaction batching for UTXO-based assets, Solana, and SPL20 tokens.
Batching does require collecting multiple user requests over a set period (for example, every X minutes) before processing them together. This approach reduces fees but may introduce slight delays for users expecting immediate withdrawals. The right batching interval depends on your withdrawal volume and user experience requirements.
Fireblocks supports creating a single transaction with multiple destinations using the [Create a new transaction](/reference/createtransaction) endpoint by passing the `destinations` array, which contains separate `destination` objects. For more information, see [Multiple destination transfer](/reference/create-transactions#multiple-destination-transfer).
## Working with One-Time Addresses
By default, outgoing transactions in Fireblocks can only be made to whitelisted addresses approved by the Workspace's Admin Approval Quorum. For businesses looking to scale their withdrawal flows and eliminate manual processes, this can become cumbersome.
To address this, Fireblocks introduced the One-Time Address (OTA) feature. OTA allows you to interact with non-whitelisted addresses, streamlining the withdrawal process. For more information, including security considerations, see [Work with One-Time Addresses](/docs/whitelist-addresses#work-with-one-time-addresses).
## Idempotent transactions
In RESTful APIs, idempotency means that making the same API call multiple times produces the same result as making it once. For financial operations like withdrawals, this is critical; without it, repeated requests can result in duplicate transactions and cause significant discrepancies.
Fireblocks provides idempotency for transaction creation through the `externalTxId` parameter. When you include `externalTxId` in a [Create a new transaction](/reference/createtransaction) request, Fireblocks rejects any subsequent request using the same value with an HTTP 400 error:
```json theme={"system"}
{
"message": "The external tx id that was provided in the request, already exists",
"code": 1438
}
```
Unlike the `Idempotency-Key` header (which expires after 24 hours), `externalTxId` is stored permanently. Fireblocks rejects duplicate values even if the follow-up request is made more than 24 hours after the original.
For more information, see [externalTxId](/reference/create-transactions#externaltxid) and [API Idempotency](/reference/api-idempotency).
# Mandatory fields for Bitstamp deposits
Source: https://developers.fireblocks.com/docs/mandatory-fields-for-bitstamp-deposits
## Originator: Myself (Individual)
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"dateOfBirth": "2000-01-01",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
}
},
"originatingVASP": {
"vaspCode": "914a9dae-4234-45d1-be83-fd40e818e381"
}
}
}
}
```
## Originator: Myself (Corporate)
```json Business theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Business",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"company": {
"name": "ACME Inc"
}
},
"originatingVASP": {
"vaspCode": "914a9dae-4234-45d1-be83-fd40e818e381"
}
}
}
}
```
## Originator: Third party (Individual)
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"dateOfBirth": "2000-01-01"
},
"originatingVASP": {
"vaspCode": "914a9dae-4234-45d1-be83-fd40e818e381"
}
}
}
}
```
## Originator: Third party (Corporate)
```json Third party theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"company": {
"name": "ACME Inc"
}
},
"originatingVASP": {
"vaspCode": "914a9dae-4234-45d1-be83-fd40e818e381"
}
}
}
}
```
# Mandatory fields for Bitstamp withdrawals
Source: https://developers.fireblocks.com/docs/mandatory-fields-for-bitstamp-withdrawals
## Sending to myself (Individual)
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"dateOfBirth": "2000-01-01",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
}
},
"beneficiaryVASP": {
"vaspCode": "914a9dae-4234-45d1-be83-fd40e818e381"
}
}
}
}
```
## Sending to myself (Corporate)
```json Business theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"company": {
"name": "ACME Inc"
}
},
"beneficiaryVASP": {
"vaspCode": "914a9dae-4234-45d1-be83-fd40e818e381"
}
}
}
}
```
## Sending to another beneficiary (Individual)
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"dateOfBirth": "2000-01-01"
},
"beneficiaryVASP": {
"vaspCode": "914a9dae-4234-45d1-be83-fd40e818e381"
}
}
}
}
```
## Sending to another beneficiary (Corporate)
```json Third party theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"company": {
"name": "ACME Inc"
}
},
"beneficiaryVASP": {
"vaspCode": "914a9dae-4234-45d1-be83-fd40e818e381"
}
}
}
}
```
# Mandatory fields for OKex withdrawals
Source: https://developers.fireblocks.com/docs/mandatory-fields-for-okex-withdrawals
## Private wallet (Individual)
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "false",
"entityType": "Individual"
}
}
}
}
```
## Private wallet (Corporate)
```json Business theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "false",
"entityType": "Business"
}
}
}
}
```
## Hosted wallet/Exchange (Individual) - VASP exists
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "true",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"streetName": "Oak",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "11000",
"subdivision": "Massachusetts",
"country": "US"
}
},
"beneficiaryVASP": {
"vaspCode": "did:ethr:0xf2bd35dc59cbbe3efb15a5bd411ac84e7c86d25a"
}
}
}
}
```
## Hosted wallet/Exchange (Individual) - Custom VASP
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "true",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"streetName": "Oak",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "11000",
"subdivision": "Massachusetts",
"country": "US"
}
},
"beneficiaryVASP": {
"vaspCode": "-2",
"vaspName": "ACME VASP"
}
}
}
}
```
## Hosted wallet/Exchange (Corporate) - VASP exists
```json Third party theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "true",
"entityType": "Business",
"postalAddress": {
"streetName": "Oak",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "11000",
"subdivision": "Massachusetts",
"country": "US"
},
"company": {
"name": "ACME Inc"
}
},
"beneficiaryVASP": {
"vaspCode": "did:ethr:0xfeb4f99829a9acdf52979abee87e83addf22a7e1"
}
}
}
}
```
## Hosted wallet/Exchange (Corporate) - Custom VASP
```json Third party theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"isHosted": "true",
"entityType": "Business",
"postalAddress": {
"streetName": "Oak",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "11000",
"subdivision": "Massachusetts",
"country": "US"
},
"company": {
"name": "ACME Inc"
}
},
"beneficiaryVASP": {
"vaspCode": "-2",
"vaspName": "ACME VASP"
}
}
}
}
```
# Mandatory fields for TrustCo withdrawals
Source: https://developers.fireblocks.com/docs/mandatory-fields-for-trustco-withdrawals
## Sending to myself (Individual)
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"externalReferenceId": "111-222-333-444"
},
"beneficiaryVASP": {
"vaspName": "Prosperity Financial"
}
}
}
}
```
## Sending to myself (Corporate)
```json Business theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"externalReferenceId": "111-222-333-444",
"company": {
"name": "ACME Inc"
}
},
"beneficiaryVASP": {
"vaspName": "Prosperity Financial"
}
}
}
}
```
## Sending to another beneficiary (Individual)
```json Individual theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"externalReferenceId": "111-222-333-444"
},
"beneficiaryVASP": {
"vaspName": "Prosperity Financial"
}
}
}
}
```
## Sending to another beneficiary (Corporate)
```json Third party theme={"system"}
{
"piiData": {
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"streetName": "Oak street",
"buildingNumber": "1",
"city": "Boston",
"postalCode": "02001",
"country": "US"
},
"externalReferenceId": "111-222-333-444",
"company": {
"name": "ACME Inc"
}
},
"beneficiaryVASP": {
"vaspName": "Prosperity Financial"
}
}
}
}
```
# Mandatory properties for Binance deposits
Source: https://developers.fireblocks.com/docs/mandatory-properties-for-deposits
# Overview
For incoming deposits to Binance, the Travel Rule mandates the submission of specific PII. This page outlines the necessary data fields and their formats, varying by jurisdiction, to ensure your deposits are compliant and processed without delay.
Developers should review these requirements carefully, alongside the provided country-specific descriptions and examples, to correctly structure PII messages for all deposit transactions.
## Bahrain
### Originator: Myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "BH"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "BH"
}
}
}
```
### Originator: Not myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AU",
"city": "Perth"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "BH"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"country": "AU",
"city": "Perth"
},
"company": {
"name": "ACME Inc"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "BH"
}
}
}
```
## France
### Originator: Myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"originatingVASP": {
"vaspName": "Binance"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "FR"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"originatingVASP": {
"vaspName": "Binance"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "FR"
}
}
}
```
### Originator: Not myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AO"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "FR"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"company": {
"name": "ACME Inc"
},
"postalAddress": {
"country": "AR"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "FR"
}
}
}
```
## India
### Originator: Myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "IN"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "IN"
}
}
}
```
### Originator: Not myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"nationalIdentification": {
"nationalIdentifier": "12345xyz"
},
"postalAddress": {
"country": "AR",
"subdivision": "State",
"city": "Buenos Aires",
"postalCode": "123123123",
"streetName": "Oak street 123"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "IN"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"country": "AR",
"subdivision": "State",
"city": "Buenos Aires",
"postalCode": "123123123",
"streetName": "Oak street 123"
},
"company": {
"name": "ACME Inc"
},
"registrationNumber": "pan1234"
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "IN"
}
}
}
```
## Japan
### Originator: Myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"originatingVASP": {
"vaspName": "BINANCE"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "JP"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"originatingVASP": {
"vaspName": "BINANCE"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "JP"
}
}
}
```
### Originator: Not myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"postalAddress": {
"country": "AU",
"city": "Perth"
},
"names": [
{
"primaryName": "Kanji name",
"nameType": "Kanji"
},
{
"primaryName": "Kana name",
"nameType": "Kana"
},
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
]
},
"originatingVASP": {
"vaspName": "BINANCE"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "JP"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"country": "AU",
"city": "Perth"
},
"names": [
{
"primaryName": "Kanji name",
"nameType": "Kanji"
},
{
"primaryName": "Kana name",
"nameType": "Kana"
},
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
]
},
"originatingVASP": {
"vaspName": "BINANCE"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "JP"
}
}
}
```
## Kazakhstan
### Originator: Myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AT",
"city": "Vienna"
}
},
"transactionData": {
"deposit": {
"txPurpose": "service"
}
},
"beneficiaryVASP": {
"vaspCountry": "KZ"
}
}
}
```
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"postalAddress": {
"country": "AT",
"city": "Vienna"
},
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
]
},
"transactionData": {
"deposit": {
"txPurpose": "service"
}
},
"beneficiaryVASP": {
"vaspCountry": "KZ"
}
}
}
```
### Originator: Not myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AT",
"city": "Vienna"
}
},
"transactionData": {
"deposit": {
"txPurpose": "service"
}
},
"beneficiaryVASP": {
"vaspCountry": "KZ"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"postalAddress": {
"country": "AT",
"city": "Vienna"
},
"entityType": "Business",
"company": {
"name": "ACME Inc"
}
},
"transactionData": {
"deposit": {
"txPurpose": "service"
}
},
"beneficiaryVASP": {
"vaspCountry": "KZ"
}
}
}
```
## Poland
### Originator: Myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"originatingVASP": {
"vaspName": "Binance"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "PL"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"originatingVASP": {
"vaspName": "Binance"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "PL"
}
}
}
```
### Originator: Not myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AT"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "PL"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"company": {
"name": "ACME Inc"
},
"postalAddress": {
"country": "AR"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "PL"
}
}
}
```
## South Africa
### Originator: Myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"deposit": {
"receiveFrom": "1"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "ZA"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"deposit": {
"receiveFrom": "1"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "ZA"
}
}
}
```
### Originator: Not myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AR"
}
},
"deposit": {
"receiveFrom": "1"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "ZA"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"company": {
"name": "ACME Inc"
},
"postalAddress": {
"country": "AU"
}
},
"deposit": {
"receiveFrom": "1"
},
"transactionData": {
"deposit": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCountry": "ZA"
}
}
}
```
## United Arab Emirates (UAE)
### Originator: Myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "AE"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "AE"
}
}
}
```
### Originator: Not myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AT",
"city": "Vienna"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "AE"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"originator": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"country": "AT",
"city": "Vienna"
},
"company": {
"name": "ACME Inc"
}
},
"originatingVASP": {
"vaspName": "Binance"
},
"beneficiaryVASP": {
"vaspCountry": "AE"
}
}
}
```
# Mandatory properties for Binance withdrawals
Source: https://developers.fireblocks.com/docs/mandatory-properties-for-withdrawals
# Overview
To ensure compliance with Binance's Travel Rule requirements for withdrawals, it's crucial to understand the specific Personally Identifiable Information (PII) that must accompany these transactions.
This section details the mandatory properties for successful withdrawals, providing country-specific information and practical examples to guide your implementation. Adhering to these guidelines is essential for seamless and compliant asset transfers.
## Bahrain
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "BH"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "BH"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AT",
"city": "Vienna"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "BH"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"country": "AT",
"city": "Vienna"
},
"company": {
"name": "Acme INC"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "BH"
}
}
}
```
## France
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "FR"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "FR"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AT"
}
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "FR"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"country": "AT",
"city": "Vienna"
},
"company": {
"name": "Acme INC"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "BH"
}
}
}
```
## India
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "IN"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "IN"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AR",
"city": "Buenos Aires"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "IN"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"country": "AR",
"city": "Buenos Aires"
},
"company": {
"name": "ACME Inc"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "IN"
}
}
}
```
## Japan
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual",
"postalAddress": {
"country": "AR",
"city": "Buenos Aires"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE",
"vaspName": "CN"
},
"transactionData": {
"withdraw": {
"txPurpose": "goods",
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "JP"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business",
"postalAddress": {
"country": "AR",
"city": "Buenos Aires"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE",
"vaspName": "CN"
},
"transactionData": {
"withdraw": {
"txPurpose": "goods",
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "JP"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"postalAddress": {
"country": "AR",
"city": "Buenos Aires"
},
"entityType": "Individual",
"names": [
{
"primaryName": "Kanji name",
"nameType": "Kanji"
},
{
"primaryName": "Kana name",
"nameType": "Kana"
},
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
]
},
"beneficiaryVASP": {
"vaspCode": "BINANCE",
"vaspName": "CN"
},
"transactionData": {
"withdraw": {
"txPurpose": "goods",
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "JP"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"postalAddress": {
"country": "AR",
"city": "Buenos Aires"
},
"entityType": "Business",
"names": [
{
"primaryName": "Kanji name",
"nameType": "Kanji"
},
{
"primaryName": "Kana name",
"nameType": "Kana"
},
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
]
},
"beneficiaryVASP": {
"vaspCode": "BINANCE",
"vaspName": "CN"
},
"transactionData": {
"withdraw": {
"txPurpose": "goods",
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "JP"
}
}
}
```
## Kazakhstan
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual",
"postalAddress": {
"country": "AT",
"city": "Vienna"
}
},
"withdraw": {
"txnPurpose": "service"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "KZ"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business",
"postalAddress": {
"country": "AT",
"city": "Vienna"
}
},
"withdraw": {
"txnPurpose": "service"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "KZ"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"postalAddress": {
"country": "AT",
"city": "Vienna"
},
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
]
},
"withdraw": {
"txnPurpose": "service"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "KZ"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"postalAddress": {
"country": "AT",
"city": "Vienna"
},
"entityType": "Business",
"company": {
"name": "ACME Inc"
}
},
"withdraw": {
"txnPurpose": "service"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "KZ"
}
}
}
```
## New Zealand
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"beneficiaryVASP": {
"vaspCode": "others",
"vaspName": "SomeVASP"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "NZ"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"beneficiaryVASP": {
"vaspCode": "others",
"vaspName": "SomeVASP"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "NZ"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "DZ"
}
},
"beneficiaryVASP": {
"vaspCode": "others",
"vaspName": "SomeVASP"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "NZ"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"company": {
"name": "ACME Inc"
},
"postalAddress": {
"country": "DZ"
}
},
"beneficiaryVASP": {
"vaspCode": "others",
"vaspName": "SomeVASP"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "NZ"
}
}
}
```
## Poland
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "PL"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "PL"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AR"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "PL"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"company": {
"name": "ACME Inc"
},
"postalAddress": {
"country": "DZ"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "PL"
}
}
}
```
## South Africa
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"beneficiaryVASP": {
"vaspCode": "others",
"vaspName": "Some VASP"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "ZA"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"beneficiaryVASP": {
"vaspCode": "others",
"vaspName": "Some VASP"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "ZA"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "DZ"
}
},
"beneficiaryVASP": {
"vaspCode": "others",
"vaspName": "Some VASP"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "ZA"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"company": {
"name": "ACME Inc"
},
"postalAddress": {
"country": "AU"
}
},
"beneficiaryVASP": {
"vaspCode": "others",
"vaspName": "Some VASP"
},
"transactionData": {
"withdraw": {
"isAddressVerified": true
}
},
"originatingVASP": {
"vaspCountry": "ZA"
}
}
}
```
## United Arab Emirates (UAE)
### Sending to myself
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Individual"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "AE"
}
}
}
```
```json Business theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "FirstParty",
"entityType": "Business"
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "AE"
}
}
}
```
### Sending to another beneficiary
```json Individual theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Individual",
"names": [
{
"primaryName": "John",
"nameType": "Latin",
"secondaryName": "Doe"
}
],
"postalAddress": {
"country": "AU",
"city": "Perth"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "AE"
}
}
}
```
```json Third party theme={"system"}
{
"type": "exchange-service-travel-rule",
"typeVersion": "1.0.0",
"data": {
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"entityType": "Business",
"postalAddress": {
"country": "AU",
"city": "Perth"
},
"company": {
"name": "ACME Inc"
}
},
"beneficiaryVASP": {
"vaspCode": "BINANCE"
},
"originatingVASP": {
"vaspCountry": "AE"
}
}
}
```
# Configuring Multiple API Co-signers in High Availability
Source: https://developers.fireblocks.com/docs/multiple-cosigners-high-availability
## Overview
You can configure multiple API Co-signers to operate in an active-active state, ensuring transaction operations align with your business continuity requirements. If one API Co-signer fails or becomes impaired, the remaining Co-signer(s) will continue signing transactions seamlessly.
## Configuring multiple Co-Signers to work in parallel
Upon completing the Co-signer's setup and configuration, you can configure them to work in parallel using the Policies.
Each API Co-signer must have at least one API user assigned the Signer role. These API users should be added to the **Designated Signers / Groups** field in the Policy for the transaction types the Co-signers are authorized to sign. You can add API users individually or as part of a user group. All designated signers for the rule must be API users. A combination of API users and Fireblocks Console users is not permitted. Refer to the [following article](https://support.fireblocks.io/hc/en-us/articles/19156998685980-About-Policies) to learn more about creating and modifying your Policies.
Once the Owner and Admin Quorum approve the Policy update, multiple Co-signers operate in parallel. Now, the transaction signing process follows these steps:
1. A transaction is initiated using the Console or APIs.
2. Fireblocks evaluates the transaction against the workspace's Policy to match it with the appropriate rule. The rule includes API users in the Designated Signers/Groups field.
3. Fireblocks calls all the Co-signers that are paired with the API users listed in the Policy rule's Designated Signers/Groups field to confirm their availability for signing.
4. Fireblocks identifies the first available API user with a paired Co-signer and sends the transaction to that Co-signer for signing.
5. If a Callback Handler is configured for the API Co-signer, it determines whether the transaction is signed or rejected based on the defined callback logic. If no Callback Handler is configured, the API user signs the transaction automatically.
## Configuring Policy rules for a group of API Co-signers
### Exchange or fiat accounts
You cannot add multiple API users or a user group to the Designated Signers/Groups field in rules in which the Source field contains an exchange or fiat account. Doing so causes transactions that match that rule to fail automatically. You must assign a single API user in Policy rules for exchange and fiat accounts.
### Policy Configuration
Depending on how you want to customize the Policy (i.e., whether you create inclusionary or exclusionary rules), you can use different methods to ensure transactions match the correct rule. In the following examples, Group 1 members are the API Co-Signers.
#### Method 1: Including API Co-Signers only for supported sources
| Rule | Initiator | Type | Source | Dest. | Whitelisted / OTA | Amount | Time Period | Asset | Action | Approved By | Designated Signers / Group |
| :--- | :-------- | :--- | :----- | :---- | :---------------- | :----- | :---------- | :---- | :---------- | :---------- | :------------------------- |
| 1 | Any | Tx | Any VA | Any | Whitelisted + OTA | \$0 | Single Tx | Any | Allow | - | Group 1 |
| 2 | Any | Tx | Any | Any | Whitelisted + OTA | \$0 | Single Tx | Any | Approved By | Tywin | - |
The rules in the table above state:
* Rule 1: This rule allows any single transaction from any vault account to any whitelisted destination or one-time address with an amount greater than \$0 from any asset. However, all transactions that match this rule must be signed by one of the Group 1 members.
* Rule 2: This rule allows any single transaction from any source to any whitelisted destination or one-time address with an amount greater than \$0 from any asset. However, all transactions that match this rule must be approved by Tywin.
Therefore, according to the first match principle, the API Co-signers only sign single transactions in which the source is a vault account.
#### Method 2: Excluding API Co-Signers from unsupported sources
| Rule | Initiator | Type | Source | Dest. | Whitelisted / OTA | Amount | Time Period | Asset | Action | Approved By | Designated Signers / Group |
| :--- | :-------- | :--- | :--------------------- | :---- | :---------------- | :----- | :---------- | :---- | :---------- | :---------- | :------------------------- |
| 1 | Any | Tx | Any Exchange, Any Fiat | Any | Whitelisted + OTA | \$0 | Single Tx | Any | Approved By | Tywin | - |
| 2 | Any | Tx | Any | Any | Whitelisted + OTA | \$0 | Single Tx | Any | Approved By | Tywin | Group 1 |
The rules in the table above state:
* Rule 1: This rule allows any single transaction from any exchange or any fiat account to any whitelisted destination or one-time address with an amount greater than \$0 from any asset. However, all transactions that match this rule must be approved by Tywin.
* Rule 2: This rule allows any single transaction from any source to any whitelisted destination or one-time address with an amount greater than \$0 from any asset. However, all transactions that match this rule must be approved by Tywin and then signed by one of the members from Group 1.
Therefore, according to the first match principle, the API Co-Signers only sign single transactions in which the source is not an exchange or a fiat account.
## Multiple API Co-signers deployment options
Co-signers can be deployed either in the cloud or on-premise, depending on your requirements. For example, you can implement a cluster with three Co-signers in an active-active-passive architecture as follows:
* **Active-Active Co-signers:** Two API Co-signers are deployed in separate availability zones within a cloud service provider. This configuration eliminates a single point of failure and ensures continuous operation without downtime.
* **Passive Co-signer:** A third API Co-signer is deployed on-premise as a failover. This on-premise Co-signer ensures redundancy, allowing for uninterrupted operation during updates or maintenance of the cloud-based Co-signers.
## Backup & Recovery
Backing up the API Co-signer server and data is highly recommended for streamlining machine updates or replacement processes. This backup can also be used for disaster recovery (DR), however, it is recommended to set up an additional API Co-signer in high availability (active-active) and use it if something goes wrong. You can learn more about backing up and restoring the API Co-signer by referring to one of the articles below:
* [SGX API Co-Signer Backup & Recovery](/reference/api-cosigner-maintenance-sgx#migrate-to-a-new-machine)
* [AWS Nitro API Co-Signer Backup & Recovery](/reference/api-cosigner-maintenance-aws-nitro#migrate-to-a-new-machine)
## Best practices
To ensure business continuity, install the API Co-signers in high availability using both on-prem data centers (when possible) and cloud service providers.
If only one infrastructure provider is available for hosting all the API Co-signers, follow the best practices for each cloud service provider for setting up cross-region replication and multiple API Co-signer instances on different data centers when deploying on-prem.
# Overview
Source: https://developers.fireblocks.com/docs/network-link-integration-guide-for-provider-connectivity
### Want to know more about the Provider Network and commercial prerequisites?
Visit [our Help Center article about the Provider Network](https://support.fireblocks.io/hc/en-us/articles/22144765384348) to learn more.
See the [Fireblocks Provider Connectivity API v2 documentation](https://fireblocks.github.io/fireblocks-network-link/v2/docs.html) on GitHub to learn how to connect your service to Fireblocks.
# Registering as a service provider
### Note on the supported testing scope
As a best practice, we recommend that your onboarding should cover only up to three stages: **Dev** → **Staging** → **Production**. Additional testing setups for supporting multiple internal environments are not supported by default and require explicit approval.
Once your license agreement for listing your service with Fireblocks is signed, the Fireblocks technical team will request the following connected account registration settings:
1. Display name (e.g., "My Exchange" or "My Exchange Sandbox")
2. Icon (a 32x32 .svg file)
3. Step-by-step guide for generating an API key for your platform
1. A public link to your knowledge base is preferred. A shareable document or PDF is also acceptable.
4. Base URL for your API endpoints (e.g., "[https://my-service.com/fireblocks"](https://my-service.com/fireblocks%22))
5. Will your service provide a sandbox environment?
6. For Off-Exchange capabilities, please provide your CSR file.
7. User credentials for testing
8. Which signing method will your server use for all requests? Please choose one of the supported options by specifying the pre-encoding function, signing algorithm, and post-encoding function during the server onboarding process.
1. **Pre-encoding options:**
1. `URL encoded`
2. `Base64`
3. `HexStr`
4. `Base58`
5. `Base32`
2. **Signing algorithms & possible hash functions:**
1. `HMAC (SHA512, SHA3_256, or SHA256)`
2. `RSA PKCS1v15 (SHA512, SHA3_256, or SHA256)`
3. `ECDSA prime256v1/secp256k1 (SHA256 only)`
3. **Post-encoding options:** (URL encoding not supported)
1. `Base64`
2. `HexStr`
3. `Base58`
4. `Base32`
9. [Validation tool results](https://github.com/fireblocks/fireblocks-network-link/tree/main/v2/api-validator)
# Asset Mapping in Network Link v2
For Network Link v2 integrations, asset mapping is based on the provider's response to `GET/capabilities/assets`. The required fields are:
* ID (on the provider's side)
* Name (on the provider's side)
* Symbol (on the provider's side)
* Decimal places (number of decimals for the asset on the provider's side)
* Test asset (true/false)
* Type (BucketAsset, ERC20Token, BEP20Token, StellarToken, Jetton, SPLToken)
# IP allowlisting
All API calls from Fireblocks to your service are sent from a fixed set of IP addresses, grouped by geographical region. Your service should allowlist these addresses to allow Fireblocks communication with your servers.
| Singapore | Europe | USA |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 18.99.36.0
18.99.36.1
18.99.36.2
18.99.36.3
18.99.36.4
18.99.36.5
18.99.36.6
18.99.36.7
18.99.36.8
18.99.36.9
52.76.208.129 | 18.98.161.0
18.98.161.1
18.98.161.2
18.98.161.3
18.98.161.4
18.98.161.5
18.98.161.6
18.98.161.7
18.98.161.8
18.98.161.9
18.98.161.10
18.98.161.11
18.98.161.12
18.98.161.13
18.98.161.14
18.98.161.15
18.98.161.16
18.98.161.17
18.98.161.18
18.98.161.19
18.133.153.74
3.10.68.107
3.64.123.47
18.158.242.74
3.10.103.242
3.67.233.15 | 18.97.132.0
18.97.132.1
18.97.132.2
18.97.132.3
18.97.132.4
18.97.132.5
18.97.132.6
18.97.132.7
18.97.132.8
18.97.132.9
40.117.39.160 |
# Mandatory endpoints implementation per user flow
## Minimum viable provider
* **Required`GET /capabilities` response:** "accounts": \["\*"]
* **Required endpoints:**
* `GET /capabilities`
* `GET /capabilities/assets`
* `GET /accounts`
* `GET /accounts/{accountId}`
## Balance support
* **Required`GET /capabilities` response:** "accounts": \["*"], "balances": \["*"]
* **Required endpoints:**
* `GET /accounts/{accountId}/balances`
## Transfer support
* **Required`GET /capabilities` response:** "accounts": \["*"], "balances": \["*"], "transfers": \["\*"]
* **Required endpoints:**
* `GET /accounts/{accountId}/capabilities/transfers/deposits`
* `GET /accounts/{accountId}/capabilities/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/deposits`
* `GET /accounts/{accountId}/transfers/deposits/{id}`
* `GET /accounts/{accountId}/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/withdrawals/{id}`
## Blockchain transfer
* **Required`GET /capabilities` response:** "accounts": \["*"], "balances": \["*"], "transfers": \["*"], "transfersBlockchain": \["*"]
* **Required endpoints:**
* `GET /accounts/{accountId}/capabilities/transfers/deposits`
* `GET /accounts/{accountId}/capabilities/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/deposits`
* `GET /accounts/{accountId}/transfers/deposits/{id}`
* `GET /accounts/{accountId}/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/withdrawals/{id}`
* `POST /accounts/{accountId}/transfers/deposits/addresses`
* `GET /accounts/{accountId]/transfers/deposits/addresses`
* `GET /accounts/{accountId}/transfers/deposits/addresses/{id}`
* `POST /accounts/{accountId}/transfers/withdrawals/blockchain`
## Peer transfer
* **Required`GET /capabilities` response:** "accounts": \["*"], "balances": \["*"], "transfers": \["*"], "transfersPeerAccounts": \["*"]
* For fiat assets, add "transfersFiat": \["\*"] to the response.
* **Required endpoints:**
* `GET /accounts/{accountId}/capabilities/transfers/deposits`
* `GET /accounts/{accountId}/capabilities/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/deposits`
* `GET /accounts/{accountId}/transfers/deposits/{id}`
* `GET /accounts/{accountId}/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/withdrawals/{id}`
* `POST /accounts/{accountId}/transfers/withdrawals/peeraccount`
## Internal transfer
* **Required`GET /capabilities` response:** "accounts": \["*"], "balances": \["*"], "transfers": \["*"], "transfersInternal": \["*"]
* For fiat assets, add "transfersFiat": \["\*"] to the response.
* **Required endpoints:**
* `GET /accounts/{accountId}/capabilities/transfers/deposits`
* `GET /accounts/{accountId}/capabilities/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/deposits`
* `GET /accounts/{accountId}/transfers/deposits/{id}`
* `GET /accounts/{accountId}/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/withdrawals/{id}`
* `POST /accounts/{accountId}/transfers/withdrawals/subaccount`
## Fiat transfer
* **Required`GET /capabilities` response:** "accounts": \["*"], "balances": \["*"], "transfers": \["*"], "transfersFiat": \["*"]
* **Required endpoints:**
* `GET /accounts/{accountId}/capabilities/transfers/deposits`
* `GET /accounts/{accountId}/capabilities/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/deposits`
* `GET /accounts/{accountId}/transfers/deposits/{id}`
* `GET /accounts/{accountId}/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/withdrawals/{id}`
* `POST /accounts/{accountId}/transfers/withdrawals/fiat`
## Liquidity/RFQ support
* **Required`GET /capabilities` response:** "accounts": \["*"], "balances": \["*"], "liquidity": \["\*"]
* **Required endpoints:**
* `GET /capabilities/liquidity/quotes`
* `POST /accounts/{accountId}/liquidity/quotes`
* `GET /accounts/{accountId}/liquidity/quotes`
* `GET /accounts/{accountId}/liquidity/quotes/{id}`
* `POST /accounts/{accountId}/liquidity/quotes/{id}/execute`
## On-/Off-Ramp & Bridging
* **Required`GET /capabilities` response:** "accounts": \["*"], "ramps": \["*"], "balances": \["\*"]
* For prefunded flows, "balances": \["\*"] must be returned with `GET` account API. See below.
* **Required endpoints:**
* `GET /accounts/{accountId}/capabilities/ramps`
* `POST /accounts/{accountId}/ramps`
* `GET /accounts/{accountId}/ramps`
* `GET /accounts/{accountId}/ramps/{id}`
* `GET /accounts/{accountId}/balances` (only for prefunded flows)
* `GET /accounts/{accountId}/rate`
* Your service should implement the `rate` endpoint to ensure Fireblocks customers see your service's real-time rates for asset pairs. Otherwise, Fireblocks defaults to quotes or its internal rating service.
## Collateral
### **Note:**
In addition to implementing the endpoints below, providers supporting Collateral/Off-Exchange flows must also integrate with the Fireblocks Off-Exchange API. This is required for reporting events from the provider back to Fireblocks (e.g., confirming deposits or settlements).
Technical Reference: [Fireblocks Off-Exchange - Exchange to Fireblocks](https://fireblocks.github.io/fireblocks-off-exchange/#tag/Exchange-to-Fireblocks)
The provider should also use this [endpoint](https://fireblocks.github.io/fireblocks-off-exchange/#tag/Exchange-to-Fireblocks).
* **Required`GET /capabilities` response:** "accounts": \["*"], "balances": \["*"], "transfers": \["*"], "transfersBlockchain": \["*"], "collateral": \["\*"]
* **Required endpoints:**
* `GET /accounts/{accountId}/balances`
* `GET /accounts/{accountId}/capabilities/transfers/deposits`
* `GET /accounts/{accountId}/capabilities/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/deposits`
* `GET /accounts/{accountId}/transfers/deposits/{id}`
* `GET /accounts/{accountId}/transfers/withdrawals`
* `GET /accounts/{accountId}/transfers/withdrawals/{id}`
* `POST /accounts/{accountId}/transfers/deposits/addresses`
* `GET /accounts/{accountId}/transfers/deposits/addresses`
* `GET /accounts/{accountId}/transfers/deposits/addresses/{id}`
* `POST /accounts/{accountId}/transfers/withdrawals/blockchain`
* **Collateral endpoints:**
* `POST accounts/{accountId}/collateral/link`
* `GET accounts/{accountId}/collateral/link`
* `POST accounts/{accountId}/collateral/{collateralId}/addresses`
* `GET accounts/{accountId}/collateral/{collateralId}/addresses`
* `GET accounts/{accountId}/collateral/{collateralId}/addresses/{id}`
* `POST accounts/{accountId}/collateral/{collateralId}/intents/deposits`
* `POST accounts/{accountId}/collateral/{collateralId}/deposits`
* `GET accounts/{accountId}/collateral/{collateralId}/deposits`
* `GET accounts/{accountId}/collateral/{collateralId}/deposits/{collateralTxId}`
* `POST accounts/{accountId}/collateral/{collateralId}/intents/withdrawals`
* `POST accounts/{accountId}/collateral/{collateralId}/withdrawals`
* `GET accounts/{accountId}/collateral/{collateralId}/withdrawals`
* `GET accounts/{accountId}/collateral/{collateralId}/withdrawals/{collateralTxId}`
* `POST accounts/{accountId}/collateral/{collateralId}/settlement`
* `GET accounts/{accountId}/collateral/{collateralId}/settlement`
* `GET accounts/{accountId}/collateral/{collateralId}/settlements/{settlementVersion}`
# Fireblocks Object Model
Source: https://developers.fireblocks.com/docs/object-model
The Fireblocks platform can be viewed as consisting of the following components:
### Fireblocks Workspace
Each unique instance of Fireblocks is called a *workspace*.
### Vault accounts
A Vault account is an easy way to separate and maintain security boundaries across assets.
Vault accounts store your asset wallets on the Fireblocks platform. Any user with the appropriate permissions can create a vault account since that is not a workspace action that requires approval.
The Vault structure for your application you're building on top of Fireblocks can either be 'Segregated' or 'Omnibus'.
#### **Segregated**
With this vault structure, each user of your application is assigned individual vault accounts.
* For example, you may have vault accounts labeled as **User #1, User #2, User #3, etc...** each of which maps to a user of the application you are building on top of Fireblocks.
#### **Omnibus**
With this vault structure, all users of your application are assigned one, or several, centralized vault accounts.
* For example, you may have a single vault account labeled as **Omnibus**, where all of your user's funds and assets are swept for a single withdrawal.
### Vault wallets
Vault wallets are used to manage internal deposit addresses. Each vault wallet contains at least one deposit address for its asset type.
Each vault account can hold any number of assets supported by Fireblocks, including multiple deposit addresses for blockchains that support it, such as UTXO-based chains like BTC. Depending on the asset type, different wallets may support multiple address types or formats. Each vault wallet is assigned to a single digital asset supported by Fireblocks.
Your workspace contains multiple assets from different blockchains. You can use one of the existing assets or add a new asset to your workspace and use it as an vault wallet.
[Learn how to create vault accounts and vault wallets using the Fireblocks API.](/docs/create-direct-custody-wallets)
### Exchange accounts
To transfer funds securely to/from exchanges, you'll need to integrate an exchange account by adding your API credentials for those exchanges.
### Fiat accounts
To transfer fiat through one of our integrated fiat providers, you need to explicitly add your fiat provider's API credentials within your desired workspace fiat account.
### Whitelisted/Unmanaged wallets
### Note:
The terms "**whitelisted wallets**" and "**unmanaged wallets**" are used interchangeably to describe wallets that are external and not under Fireblocks' management. In certain areas of the system, such as the API and Webhooks, these wallets are referred to as unmanaged wallets.
Whitelisted or unmanaged wallets are an additional security measure for interacting with various blockchain addresses. They can be named how you prefer and marked as either 'internal', 'external', or 'contract'.
* **Internal wallet** - a deposit address existing inside your organization.
* **External wallet** - a deposit address existing outside your organization.
* **Contract wallet** - a deposit address of an on-chain smart contract.
### Note:
This only applies to smart contracts on EVM-compatible blockchains.
# Off Exchange
Source: https://developers.fireblocks.com/docs/off-exchange
# Overview
Fireblocks is the digital asset management infrastructure for the leading trading desks, hedge funds, brokerages, custodians, and banks. Through the Fireblocks Console, users connect and trade on over 30 exchanges. As part of an important initiative, making sure that the end user still has complete control over his own asset Fireblocks offers the Off Exchange solution. This way ,the end user can enjoy the various benefits of the exchange while avoiding the risk of a centralized malfunction.
Benefits:
* Complete end user control
* Provide a trustable relationship, where the customer safely continues his work with the exchange
* Control rate limits and response codes
* Manage the supported assets
* Optimize the platform load for requests from Fireblocks
[Read the Fireblocks Off-Exchange official documentation](https://fireblocks.github.io/fireblocks-off-exchange/)
# Official Public Keys
Use the following key(s) to validate requests received from Fireblocks on Off-Exchange:
## Development Testing
```yaml theme={"system"}
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtug0j82+C1WCcqCPEzEm
sao1kH4gIDHewI06SsiB1aIdZ/v+I/PTRTYhKC0JVtsio+KeF/YDWI3c1RZrMa9/
7yOoQ8QNNG0U65q2//LoSz3He6E9/7b5V+BrQwvCHPOv4kp+un9bZ23BqvX+jgJQ
aKTvjEeBUW6fOh2oupRGH51teBcQpmgPFP1b26BGFSiGBdyB1OX6qYchIv5C/XW/
d3NoOUD96kEMEsDUKCvXwPp5gelqZQoaGZZatE5AllFdJJQKXU8DWDXTJMSyxIIY
rzx6S5RToDDK/Z7SKG4k8q1pd6pViNe88DJYV6kJdSgiYThl07sATWo+6Ev6nFSo
z69Jx+BWx5v2aLJfc6ghuN7j5dOBtex+tklHMw0s1XCiE14Pyi6px9dNNJApp6wM
LIDmMeKTZ65ar22q5ySgrNQHvVOy66zRZhfOu5fueSPa4C3CBoarCpiUIQTVNzf5
AA3qBKfunIUqHYNzdvPt/MwQErW1G9XPxGC+az0Cc4qEmICUSlYiFC1BLD6YKpjP
MsPkuj2d9MYfDUQktt1IKsWOTE6NNVzmYpbZkA7TD6hcqd7rV6Zf5TcK9vvEB1V5
F0jJYUdNXygdzKOwY/OlQ0eoF5vb6XU46y24cCnKgJ23ZfdLJJrFOdpbEaooErhn
37BWbAWH9EpcHM9pFNUYOhkCAwEAAQ==
-----END PUBLIC KEY-----
```
## Production Testing
```yaml theme={"system"}
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9JxE/VqDSCnUD5030Ufm
CoTiOtbLGRGZ6XK1KNhtD1c0MQUtiHoCCcAmmyOlTuemaPjrscGFOdITeubEPoO1
+smHziM2LkzSgtOwdgTXA+pYxnMe9lDXCtgD5mRRUQB6IqsqZN8bJcG+VuF/mMZy
qkuUIskrjJ+kn0ZfiR0PHVYkaUzvHhmyB8ZxrQTOWLB7H+62g7ZBI1U1cOcyHnSH
HVh0TpZ573fztqQS3ECGeCnpo6jQEfBeCvwx5sBkum+3iWl9VDwXIlyjcodlYqD1
YmrYrSPJwpQlxv9zUw2LarwJU+uv3EmIRKyQdxsHO8tcXGDy6WWl/zUNw1nu6uLd
kCteOJUT/SX0QlxizLFE02AAEW0hBNT0KHhD5GVN0QRkWfAJTxLSajqKEeg7M2KO
0xfh+PMEeEOzIc3GC5xv/oJ3tFt7ZawbU19WpifUcBiU2r4HLPaijxN7K9bZIfUt
K5maCIATuqn1U05G0zXUvkgZ64fHBzwtMl3grp5t6++QiH3fShBD+hUQmPoTV9p3
vgPtigK2+USPyJVwa22YplY96XckkBToOcrvYZc710gpTRwFjQdJ/DfrUYqh4UaV
7k/n9sCDRM3sM353tMAmr6dFYHKN5OwviKD2t9RNMa3j67wqHAeLimFvAM8fMe5I
aNSwkiUjHhlLPOqPhhXl3U8CAwEAAQ==
-----END PUBLIC KEY-----
```
# On/Off-Ramp, and cross-chain Swap via CeFi
Source: https://developers.fireblocks.com/docs/on-ramp-off-ramp-and-bridgeswap-via-account-based-providers-cefi
### **Beta Feature**
The Trading API is currently in beta and subject to change. For participation details, contact your Fireblocks Customer Success Manager or email [CSM@fireblocks.com](mailto:CSM@fireblocks.com).
This guide provides step-by-step examples of how to execute various order operations using the Fireblocks Trading API via account-based providers. These require you to connect an account before trading. For instructions on how to connect accounts, see [Fireblocks Connected Accounts](https://support.fireblocks.io/hc/en-us/articles/360017435399-Fireblocks-connected-accounts). This guide covers multiple use cases including on-ramp (fiat to crypto), off-ramp (crypto to fiat), and bridging (crypto-to-crypto).
## Prerequisites
Before you begin, ensure you have completed the prerequisites outlined in the [Trading API Overview](/docs/trading-api-overview#/):
* ✅ Fireblocks API credentials configured
* ✅ Fireblocks TypeScript SDK installed (`@fireblocks/version 13.x or later`)
* ✅ Connected account(s) set up with your chosen provider(s) via the Fireblocks Console (see [Fireblocks Connected Accounts](https://support.fireblocks.io/hc/en-us/articles/360017435399-Fireblocks-connected-accounts) for setup instructions)
## SDK Setup
First, set up your Fireblocks SDK client:
```typescript TypeScript theme={"system"}
import { Fireblocks } from '@fireblocks/ts-sdk';
import * as fs from 'fs';
// Initialize the Fireblocks SDK
const fireblocks = new Fireblocks({
apiKey: 'your-api-key',
secretKey: fs.readFileSync('/path/to/your/secret.key', 'utf8'),
basePath: 'https://api.fireblocks.io',
});
```
## Provider and account discovery
Before trading with account-based providers, find out which providers are available and which accounts you have connected. If you haven't connected any accounts yet, see [Fireblocks Connected Accounts](https://support.fireblocks.io/hc/en-us/articles/360017435399-Fireblocks-connected-accounts) for setup instructions.
### Step 1: Get Providers and Connected Accounts
Retrieve all trading providers. For account-based providers, the response includes provider information and connected accounts, allowing you to extract both `providerId` and `accountId` in a single call.
```typescript TypeScript theme={"system"}
// Get all trading providers
const response = await fireblocks.trading.getTradingProviders({ pageSize: 20 });
// Filter for account-based providers
const accountBasedProviders = response.data.data.filter(p => p.accountBased);
// Access provider and account information
for (const provider of accountBasedProviders) {
console.log(`Provider: ${provider.id} (${provider.name})`);
provider.accounts?.forEach(account => {
console.log(` Account: ${account.id} (${account.name})`);
});
}
```
### Response Example
```json JSON theme={"system"}
{
"data": [
{
"id": "ALFREDPAY",
"name": "Alfred Pay",
"accountBased": true,
"connected": true,
"accounts": [
{
"id": "acc_5e9a2d1c4b7f3e8a",
"name": "My Alfred Pay Account"
}
],
"manifest": {
"assetTypes": ["FIAT", "DIGITAL"],
"capabilities": ["TRADING"]
}
},
{
"id": "YELLOWCARD",
"name": "Yellow Card",
"accountBased": true,
"connected": true,
"accounts": [
{
"id": "acc_9f4e2d8b1c6a5e73",
"name": "Yellow Card Main Account"
}
],
"manifest": {
"assetTypes": ["FIAT", "DIGITAL"],
"capabilities": ["TRADING"]
}
}
],
"total": 2,
"next": null
}
```
### Key Fields Explained
| Field | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `id` | Unique identifier for the provider (use as `providerId` in subsequent API calls) |
| `name` | Display name of the provider |
| `accountBased` | `true` for account-based providers, `false` for direct access providers |
| `connected` | Whether you have at least one connected account with this provider |
| `accounts` | Array of connected accounts for this provider. Each account has an `id` (use as `accountId` in subsequent API calls) and `name` |
### For more details about this endpoint, see the [Get Providers API Reference](/reference/gettradingproviders).
### Step 2: Get Supported Trading Pairs
For each connected account, discover which trading pairs are supported:
```typescript TypeScript theme={"system"}
// Get supported trading pairs for a specific connected account
const response = await fireblocks.trading.getTradingPairs({
accountId: 'acc_9f4e2d8b1c6a5e73',
});
// Response data
const tradingPairs = response.data;
// tradingPairs = [
// {
// "id": "7c9e8f2a-4b5d-4e1c-9a3b-6f8d2e5c7a1b",
// "toAsset": "USDC",
// "fromAsset": "USD",
// "prefunded": false,
// "fromAssetRail": "ACH"
// }
// ]
```
### Step 3: Get Indicative Rates
Get indicative rates for price preview (these are not executable quotes):
```typescript TypeScript theme={"system"}
// Get indicative rates
const response = await fireblocks.trading.getRates({
accountId: 'acc_9f4e2d8b1c6a5e73',
baseAssetId: 'USD',
quoteAssetId: 'BTC',
});
const rates = response.data;
```
### **Note:** Rates provide indicative prices for preview, while quotes return committed rates that can be executed until expiration.
## Clarification on how to translating user intent into baseAssetId, quoteAssetId, side, and baseAmount
When creating a **Quote** or an **Order**, you express the trade using:
* `baseAssetId`: the asset you **receive** on **BUY** / **give** on **SELL**
* `quoteAssetId`: the counter asset used to **pay**/**receive**
* `side`:
* `BUY`: receive base / pay quote
* `SELL`: give base / receive quote
* `baseAmount`: amount in `baseAssetId`
* `BUY`: base amount to receive
* `SELL`: base amount to sell
### Examples
| Intent | baseAssetId | quoteAssetId | side | baseAmount |
| ----------------------- | ----------- | ------------ | ---- | ---------- |
| Buying 100 BTC with USD | BTC | USD | BUY | 100 |
| Buying 100 USD with BTC | USD | BTC | BUY | 100 |
| Selling 100 BTC for USD | BTC | USD | SELL | 100 |
| Selling 100 USD for BTC | USD | BTC | SELL | 100 |
## Participants & compliance
Participant details vary by provider and rail. The `participantsIdentification` object defines the originator and beneficiary involved in an order.
### Example structure
```json theme={"system"}
{
"participantsIdentification": {
"originator": {
"externalReferenceId": "user_123",
"participantRelationshipType": "FirstParty",
"entityType": "INDIVIDUAL"
},
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"fullName": {
"firstName": "Alice",
"lastName": "Lee"
}
}
}
}
```
### Key concepts
* **First-party**: Acting for self — provider already holds KYC; minimal data required.
* **Third-party**: Acting for another — provider may require full PII.
The level of PII data required depends on the provider and the relationship type (first-party vs. third-party).
## Use Case Examples
The following sections demonstrate different trading use cases with account-based providers:
## Use Case 1: On-Ramp - DVP Settlement with Market Execution
**Use Case:** Convert fiat to crypto at the market rate. The user creates the order, receives payment instructions from the provider, deposits the funds, and once payment is confirmed, the provider executes and settles the crypto, ensuring delivery versus payment (DVP).
**Settlement Type:** DVP (Delivery vs Payment)\
**Execution Type:** Market
### **Note:** The `baseAssetId`, `baseAssetRail`, `quoteAssetId`, and `quoteAssetRail` values used in the order must match a supported trading pair returned from the `getTradingPairs` endpoint (see Step 2 in Getting Started). This ensures the provider supports the specific asset and rail combination you're requesting.
### Step 1: Create the Order
```typescript theme={"system"}
// Create on-ramp order with DVP settlement and market execution
const response = await fireblocks.trading.createOrder({
createOrderRequest: {
via: {
type: 'PROVIDER_ACCOUNT',
providerId: 'bridge-provider-001',
accountId: 'acc_9f4e2d8b1c6a5e73',
},
executionRequestDetails: {
type: 'MARKET',
side: 'BUY',
baseAmount: '1000',
baseAssetId: 'USD',
baseAssetRail: 'ACH',
quoteAssetId: 'USDC',
quoteAssetRail: 'BLOCKCHAIN',
},
settlement: {
type: 'DVP',
sourceAccount: {
type: 'EXTERNAL',
},
destinationAccount: {
type: 'ONE_TIME_ADDRESS',
address: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
},
},
participantsIdentification: {
originator: {
entityType: 'BUSINESS',
participantRelationshipType: 'FirstParty',
},
beneficiary: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'ThirdParty',
fullName: {
lastName: 'Johnson',
firstName: 'Alexander',
},
postalAddress: {
streetName: 'Fifth Avenue',
buildingNumber: '350',
postalCode: '10118',
city: 'New York',
subdivision: 'NY',
district: 'Manhattan',
country: 'US',
},
externalReferenceId: 'person_ref_7f3e2d1c4b8a5e9f',
dateOfBirth: '1985-03-15',
},
},
customerInternalReferenceId: '32e423',
},
idempotencyKey: `order-${Date.now()}`,
});
const order = response.data;
```
### Step 2: Handle Payment Instructions
Since the settlement type is DVP and the source type is EXTERNAL, the funds will move from outside Fireblocks. The order creation response will include payment instructions for the rail which you select (e.g., ACH, SEPA, Wire):
```json theme={"system"}
{
"paymentInstructions": {
"referenceId": "REF-ACH-001",
"type": "ACH",
"address": {
"accountHolder": {
"name": "Bridge Provider Ltd.",
"address": "123 Main Street",
"city": "New York",
"country": "US",
"subdivision": "NY",
"postalCode": "10001"
},
"bankName": "JPMorgan Chase Bank N.A.",
"bankAccountNumber": "9876543210",
"routingNumber": "021000021",
"accountType": "CHECKING"
}
}
}
```
### Considerations
* For third-party payouts, like the one in the example, the provider must receive the beneficiary details (PII as required by the provider). In this case, you are the originator — acting as a first party, already KYC'd with the provider. Therefore, the only data needed is to set the `beneficiary.participantRelationshipType = "FirstParty"`.
* Since the settlement type is DVP and the source type is EXTERNAL, the funds will move from outside Fireblocks. As a result, the order creation response will include payment instructions for the rail which you select (e.g., ACH, SEPA, Wire).
## Use Case 2: On-Ramp - Prefunded settlement with quote execution
**Use Case:** Convert fiat to crypto at a locked rate from a committed quote. Funds are already held in the account; no payment instructions are returned in the response, and the provider will execute and settle the request immediately.
**Settlement Type:** Prefunded\
**Execution Type:** Quote
### Step 1: Create a Quote
```typescript theme={"system"}
// Create a quote for on-ramp
const quoteResponse = await fireblocks.trading.createQuote({
createQuote: {
scope: [
{
providerId: 'SCRYPT',
accountId: 'scrypt_acc_5e9a2d1c4b7f3e8a',
},
],
side: 'BUY',
baseAssetId: 'USDT_ERC20',
quoteAssetId: 'TRX_USDT_S2UZ',
baseAmount: '15000',
},
idempotencyKey: `quote-${Date.now()}`,
});
const quote = quoteResponse.data.quotes[0];
```
In the quote response, you will receive all related metadata, including the quote ID (`id`) and expiration time (`expiresAt`). The quote ID is then used in the next step to create an order and execute the trade.
### Step 2: Execute order with quote
```typescript theme={"system"}
// Execute order using the quote from Step 1
const response = await fireblocks.trading.createOrder({
createOrderRequest: {
via: {
type: 'PROVIDER_ACCOUNT',
accountId: 'acc_5e9a2d1c4b7f3e8a',
providerId: 'ALFREDPAY',
},
executionRequestDetails: {
type: 'QUOTE',
reQuote: {
type: 'MARKET',
},
quoteId: 'quote_8f2e4d1a9c5b7e3f',
},
settlement: {
type: 'PREFUNDED',
destinationAccount: {
type: 'VAULT_ACCOUNT',
accountId: 'vault_acc_9f3e2d1c4b8a7e5f',
},
},
participantsIdentification: {
originator: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
beneficiary: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
},
},
idempotencyKey: `order-${Date.now()}`,
});
const order = response.data;
```
### Considerations
* In this example, you perform an on-ramp for yourself, not for a third-party recipient. Therefore, both the originator and beneficiary use `"participantRelationshipType": "FirstParty"`, and no additional PII data is required.
* The `quoteId` used in the order request is the same ID returned in the response from the `POST /trading/quotes` call.
## Use Case 3: Off-Ramp - DVP settlement with market execution
**Use Case:** Convert crypto to fiat at the market rate. The provider waits for confirmation of the crypto deposits before finalizing the settlement, ensuring delivery versus payment (DVP).
**Settlement Type:** DVP\
**Execution Type:** Market
### **Note:** The `baseAssetId`, `baseAssetRail`, `quoteAssetId`, and `quoteAssetRail` values used in the order must match a supported trading pair returned from the `getTradingPairs` endpoint (see Step 2 in Getting Started). This ensures the provider supports the specific asset and rail combination you're requesting.
### Step 1: Create the Order
```typescript theme={"system"}
// Create off-ramp order with DVP settlement and market execution
const response = await fireblocks.trading.createOrder({
createOrderRequest: {
via: {
type: 'PROVIDER_ACCOUNT',
providerId: 'YELLOWCARD',
accountId: 'acc_9f4e2d8b1c6a5e73',
},
executionRequestDetails: {
type: 'MARKET',
side: 'BUY',
baseAmount: '250',
baseAssetId: 'XOF',
baseAssetRail: 'LOCAL_BANK_TRANSFER_AFRICA',
quoteAssetId: 'USDT_ERC20',
quoteAssetRail: 'BLOCKCHAIN',
},
settlement: {
type: 'DVP',
sourceAccount: {
type: 'VAULT_ACCOUNT',
accountId: 'vault_acc_5e9a2d1c4b7f3e8a',
},
destinationAccount: {
type: 'EXTERNAL_WALLET',
accountId: 'fiat_whitelisted_acc_9f3e2d1c4b8a7e5f',
},
},
participantsIdentification: {
originator: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
beneficiary: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
},
},
idempotencyKey: `order-${Date.now()}`,
});
const order = response.data;
```
### Considerations
* In this example, you perform an off-ramp for yourself, not for a third-party recipient. Therefore, both the originator and beneficiary use `"participantRelationshipType": "FirstParty"`, and no additional PII data is required.
* In this example, you chose to use a whitelisted account as the destination fiat account type. This allows you to register and manage external bank accounts (and also crypto addresses) directly within Fireblocks, ensuring secure, verified destinations that can be safely reused for future orders and transactions.
* Since the source of this order is a Vault Account, once the provider receives the order request, a transfer request will be automatically created from your vault to the provider. You will then need to approve and sign this transfer in accordance with the workspace's policy rules before the order can be executed.
## Use Case 4: Bridging (Crypto-to-Crypto) - DVP settlement with quote execution
**Use Case:** Execute a cross-chain bridging operation through the provider's connected accounts. In this flow, the user swaps USDT on Ethereum for USDT on Tron using their Scrypt provider account.
**Settlement Type:** DVP\
**Execution Type:** Quote
### Step 1: Create a Quote
```typescript theme={"system"}
// Create a quote for crypto-to-crypto bridging
const quoteResponse = await fireblocks.trading.createQuote({
createQuote: {
scope: [
{
providerId: 'SCRYPT',
accountId: 'scrypt_acc_5e9a2d1c4b7f3e8a',
},
],
side: 'BUY',
baseAssetId: 'USDT_ERC20',
quoteAssetId: 'TRX_USDT_S2UZ',
baseAmount: '15000',
},
idempotencyKey: `quote-${Date.now()}`,
});
const quote = quoteResponse.data.quotes[0];
```
In the quote response, you will receive all related metadata, including the quote ID (`id`) and expiration time (`expiresAt`). The quote ID is then used in the next step to create an order and execute the trade.
### Step 2: Execute Order with Quote
```typescript theme={"system"}
// Execute bridging order using the quote from Step 1
const response = await fireblocks.trading.createOrder({
createOrderRequest: {
via: {
type: 'PROVIDER_ACCOUNT',
providerId: 'SCRYPT',
accountId: 'scrypt_acc_5e9a2d1c4b7f3e8a',
},
executionRequestDetails: {
type: 'QUOTE',
reQuote: {
type: 'MARKET',
},
quoteId: 'quote_khge4d1a9c5bmvby',
},
settlement: {
type: 'DVP',
sourceAccount: {
type: 'VAULT_ACCOUNT',
accountId: 'vault_acc_5e9a2d1c4b7f3e8a',
},
destinationAccount: {
type: 'VAULT_ACCOUNT',
accountId: 'vault_acc_5e9a2d1c4b7f3e8a',
},
},
participantsIdentification: {
originator: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
beneficiary: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
},
},
idempotencyKey: `order-${Date.now()}`,
});
const order = response.data;
```
### Considerations
* In this example, you perform bridging via a connected account for yourself, not for a third-party recipient. Therefore, both the originator and beneficiary use `"participantRelationshipType": "FirstParty"`, and no additional PII data is required.
* The `quoteId` used in the order request is the same ID returned in the response from the `POST /trading/quotes`call.
* Since the source of this order is a Vault Account, once the provider receives the order request, a transfer will automatically be initiated from your Vault Account to the provider's connected account on Scrypt. This transfer is governed by the workspace's Transfer Policy, just like any other transfer in Fireblocks.
* **ReQuote Option:** Instead of `"type": "MARKET"`, you can use `"type": "RETRY"` with `count` (1-10 retry attempts) and optional `slippageBps` (slippage tolerance in basis points) to automatically retry quote generation if the original quote expires, giving you more control over price execution.
## Order Tracking & Monitoring
After creating an order, monitor its execution status to track completion.
### Polling for order status
```typescript theme={"system"}
// Get order status and details
const response = await fireblocks.trading.getOrder({
orderId: 'order_id_here',
});
const order = response.data;
// Check: order.status, order.executionSteps, order.createdAt, etc.
```
### Order Status Values
| Status | Description |
| --------------------- | ------------------------------------------------ |
| `CREATED` | Order has been created and is being processed |
| `AWAITING_PAYMENT` | Waiting for payment to be received |
| `PENDING_USER_ACTION` | Requires user action (e.g., approval in console) |
| `PROCESSING` | Order is being executed |
| `COMPLETED` | Order has been successfully completed |
| `FAILED` | Order execution failed |
| `CANCELED` | Order was canceled |
### **Note:** FAILED, COMPLETED and CANCELED are terminal states.
### Webhooks
Subscribe to order-update events through the Fireblocks Webhooks API. See the [Fireblocks Webhooks API documentation](/) for more details.
## Additional Resources
* [Trading API Overview](/docs/trading-api-overview)
* [Bridging via Direct Access Providers (DeFi)](/docs/swap-via-direct-access-providers-defi) - For crypto-to-crypto bridging using direct access providers like Uniswap
* Fireblocks SDKs: [Python](https://pypi.org/project/fireblocks/) | [TypeScript](https://www.npmjs.com/package/@fireblocks/ts-sdk) | [Java](https://central.sonatype.com/artifact/com.fireblocks.sdk/fireblocks-sdk/overview)
* [Fireblocks Developer Portal](/)
## Support
For questions or issues with the Trading API:
* Contact your Fireblocks [Customer Success Manager](https://support.fireblocks.io/hc/en-us/requests/new?ticket_form_id=6947882197532)
* Email: [CSM@fireblocks.com](mailto:CSM@fireblocks.com)
* Check the [Fireblocks Developer Portal](/) for updates
# Overview
Source: https://developers.fireblocks.com/docs/overview
### Unsure about which custody model is right for you?
Read our “[Guide to Digital Asset Wallets and Service Providers](https://www.fireblocks.com/a-guide-to-digital-asset-wallets-and-service-providers)” for insights into evaluating digital asset wallet and service providers for your business
# Overview
Fireblocks provides customers with an option to choose what custody model works best for their use case. In this guide we will outline the main technical and conceptual differences between Embedded Wallets and Direct Custody wallets.
Following are the main differences between direct custody and Embedded Wallets wallets in Fireblocks.
1. Direct custody wallets use a 3-of-3 multi-party computation (MPC) signature scheme while Embedded Wallets wallets use a 2-of-2 signature scheme.
2. There is only one master key per workspace for direct custody wallets, while each Embedded Wallets wallet has its own master key.
3. UTXO-based assets, such as BTC, can have multiple deposit addresses per wallet per vault account for direct custody wallets. For Embedded Wallets wallets, one wallet can have multiple accounts while each account can hold only 1 BTC address.
4. The Fireblocks Network and exchange integrations are supported for direct custody wallets only.
# Direct Custody Wallets
## Structure
* The main section of the workspace is the Fireblocks Vault which holds all MPC wallets.
* Inside the Vault, an unlimited number of vault accounts can be created. This allows to segregate between distinct clients and various use cases.
* Each vault account can hold as many asset wallets as you need. However, you can only have one wallet per asset.
* In a vault account, asset wallets can accommodate numerous deposit addresses for UTXO-based assets, while account-based assets are assigned with a single address.
## Secret key management and wallet derivation
Each vault account is identified by its *vault account ID*. This identifier is used for derivation of the asset wallets in a specific vault account.
Using one master key (split into three key shards) for the entire workspace, you can create an unlimited number of vault accounts. The vault account ID acts as the account value of the derivation path.
Each asset within this specific Vault would be derived according to the following structure: m/purpose/coinType/account/change/index.
* **m**: master private key
* **purpose**: the derivation standard (BIP44 in our example)
* **coinType**: the unique identifier of an asset (0 for BTC, 60 for ETH, etc.)
* **account**: the vault account ID
* **change**: always 0
* **index**: the address index (always 0 except for UTXO based assets such as Bitcoin)
# Embedded Wallets
## Structure
Fireblocks Embedded Wallets wallets can be used in parallel with direct custody wallets. One workspace can support both structures. However, Fireblocks strongly recommends splitting the direct custody and the Embedded Wallets parts of your business into two different workspaces due to some settings that are shared by both types of wallets in the same workspace.
Fireblocks Embedded Wallets wallets use 2-of-2 MPC signature scheme. One key share is stored within an Intel SGX-enabled server managed by Fireblocks, and the second key share is stored on the end user's device.
## Secret key management and wallet derivation
The derivation for Embedded Wallets wallets is almost the exact same as the derivation for direct custody wallets. The main difference is that each Embedded Wallets wallet will have its own master key, which is split into two key shards. In a single Embedded Wallets wallet, you can create an unlimited number of accounts while each account can have only one supported asset per asset type.
# Define Payment Flows
Source: https://developers.fireblocks.com/docs/payment-flows-copy
# What are Payment Flows?
Fireblocks empowers you to leverage blockchains and digital rails for efficient, dependable, and predictable payments. The Payments feature in Fireblocks enables the creation of secure, dynamic payment flows that consist of various actions within a single solution.
Payment flows allow you to streamline and automate your payment transactions. By configuring and executing payments directly from the Payments page in the Fireblocks Console or via the [Fireblocks API](/reference/createflowconfiguration) , you can manage various types of financial operations with ease and precision.
# How does it work?
The Payments API involves two resources.
* **Workflow Configuration (WC):** This resource acts as a template for your payment flow. It contains the types of operations and each operation’s schema of parameters. Each operation under a WC is referred to as a workflow configuration operation (WCO).
* **Workflow Execution (WE):** This resource allows you to validate, preview, and launch your payment flow based on a specific WC. Each operation within a WE is referred to as a workflow execution operation (WEO).
Generally, the payment workflow consists of the following three steps:
* [Create a WC](/reference/createflowconfiguration).
* The WC completes the validation process and moves to `READY_FOR_EXECUTION` state.
* [Create a WE based on the WC](/reference/createflowexecution).
* The WE completes the validation process and the preview process and moves to `READY_FOR_LAUNCH` state.
* [Launch the WE](/reference/launchflowexecution).
The validation and preview processes are not instantaneous. Before continuing to the next step, the WC or WE should be in a ready state.
The validation process is required again when creating the WE because:
* Changes may have occurred during the time between creating a WC and creating a WE. For example, the account could have been removed from the workspace.
* New parameters may have been added when creating the WE and should be verified.
# Overview
Source: https://developers.fireblocks.com/docs/perform-drs-process
# Overview
Fireblocks provides a comprehensive backup and recovery solution to ensure that you always have access to your assets, even if you lose access to your signing devices or in the unlikely event that Fireblocks suspends operations.
Your Fireblocks Vault is a secure multi-party computation (MPC) based wallet that prevents your private key from being a single point of failure when you sign transactions. With Fireblocks MPC, one key share is stored on your company’s hardware, either in each user with signing privileges’ Fireblocks mobile app or on a server that hosts your API Co-Signer. You have two corresponding key shares, which Fireblocks stores at top-tier cloud providers. Your three key shares are never together in one place to expose your full private key.
# Recovery Tools
Fireblocks recommends using our [native self-serve recovery tool](https://support.fireblocks.io/hc/en-us/articles/12023480536732-Introduction-to-in-house-key-backup-and-recovery). Alternatively, you can use [one of our DRS partners](https://support.fireblocks.io/hc/en-us/articles/17211307086364-Third-Party-Disaster-Recovery-Services).
# Getting Started
Source: https://developers.fireblocks.com/docs/quickstart
Install the Fireblocks Documentation MCP, then use an SDK or the Fireblocks CLI to make your first Fireblocks API calls.
By the end of this guide, you will have:
* Connected your agent to the Fireblocks docs
* Created and approved an API user
* Initialized the Fireblocks SDK or CLI
* Created a vault account
* Sent your first transaction
## Step 0: Connect your AI agent to Fireblocks docs
Before you start, install the **Fireblocks Documentation MCP** so your agent (Cursor, Claude Code, Codex, or other) can access docs in real time to ensure up to date, accurate implementation context.
[Click here to add the Fireblocks Documentation MCP to Cursor.](https://cursor.com/en/install-mcp?name=fireblocks\&config=eyJ1cmwiOiJodHRwczovL2RldmVsb3BlcnMuZmlyZWJsb2Nrcy5jb20vZG9jcy9tY3AifQ==)
If the install link doesn't open in your environment, open Cursor's MCP installer manually and point it at `https://www.developers.fireblocks.com/mcp`.
```bash theme={"system"}
claude mcp add --transport http fireblocks-docs https://www.developers.fireblocks.com/mcp
```
```bash theme={"system"}
codex mcp add --transport http fireblocks-docs https://www.developers.fireblocks.com/mcp
```
Use the Fireblocks Documentation MCP endpoint:
`https://www.developers.fireblocks.com/mcp`
## Step 1: Set up API authentication
Fireblocks authenticates API requests with **JWT signatures**. Each request is signed with an **API secret key** (RSA private key) that stays in your environment. Fireblocks stores only the matching **public key**, which you register when you create the API user by uploading a **Certificate Signing Request (CSR)**.
### How signing works
| Component | Location | Purpose |
| -------------------------------- | --------------------- | ----------------------------------------------------- |
| **API secret key** (private key) | Your environment only | Signs every API request to prove it came from you |
| **Public key** | Fireblocks | Verifies that requests were signed by your secret key |
Your API secret **never** leaves your environment. Fireblocks only receives your public key. We cannot sign requests on your behalf, and a compromised Fireblocks system would not expose your credentials.
### Generate a CSR and secret key
You will create:
* A **secret key** file that stays in your environment and signs requests
* A **CSR** file containing the corresponding public key, which you upload in the Console
1. (Windows users) Install **Win32OpenSSL** using the default settings.
2. (Windows users) Open OpenSSL Command Prompt.
3. In your CLI, run:
```bash Shell theme={"system"}
openssl req -new -newkey rsa:4096 -nodes -keyout fireblocks_secret.key -out fireblocks.csr -subj '/O='
```
This command creates:
* **fireblocks\_secret.key** — your RSA 4096 private key (API secret)
* **fireblocks.csr** — the CSR you upload when creating the API user
4. Store the secret key file securely.
### Create an API user (API key)
If you’re using a Sandbox environment, you can skip this subsection. Sandboxes come with an API user already created and access to the [Communal Test Co-signer](/reference/use-communal-cosigner#/).
To create an API key with a signing role:
1. In the Fireblocks Console, go to **Developer Center** > **API Users**.
2. Select **Add API user**.
3. Name the API user, select the appropriate workspace role for it (e.g., Signer if you want it to sign transactions), and upload the `fireblocks.csr` file you generated above.
4. Select **Add user**.
After the request to add the API user is approved, it will appear in the API users list. You'll receive an **API Key** (API User ID), a unique identifier for the API user that you'll use alongside your secret key.
## Choose your path: SDK or CLI
From **Step 2** onward, the guide splits into two tracks that share the same API credentials. Pick the one that matches what you're building:
* **SDK** — for application code (apps, services, backends) where you ship typed, maintainable Fireblocks integrations. **Recommended for production.**
* **Fireblocks CLI** — for fast workspace operations, exploration, scripts, CI, and operator/agent workflows. Lets your AI agent propose exact commands you can review and run.
Steps **3 through 5** each use two synced tabs. Pick **SDK** or **CLI** once and the choice carries through the rest of the guide. The SDK and CLI are not mutually exclusive; you can use both in the same workspace.
## Step 2: Initialize the SDK or CLI
Pick the tab that matches your track. The same choice will apply to Steps 3–5.
Fireblocks provides official SDKs for multiple languages:
* [TypeScript SDK](https://github.com/fireblocks/ts-sdk)
* [Python SDK](https://github.com/fireblocks/py-sdk)
* [Java SDK](/reference/java-sdk#/)
Install the appropriate SDK for your environment:
```bash npm theme={"system"}
npm install fireblocks-sdk
```
```bash pip theme={"system"}
pip install fireblocks-sdk
```
```java Java theme={"system"}
// Follow Java SDK instructions on the documentation link above
```
After installing the SDK, initialize the client with:
* Your **API Key** (obtained from the Fireblocks Console after creating the API user)
* Your **API secret key** (the `fireblocks_secret.key` file from Step 1)
The SDK uses your secret key to sign each API request automatically.
```typescript TypeScript theme={"system"}
import { FireblocksSDK } from "fireblocks-sdk";
import fs from "fs";
const apiKey = "";
const privateKey = fs.readFileSync("fireblocks_secret.key", "utf8");
const fireblocks = new FireblocksSDK(privateKey, apiKey);
```
```python Python theme={"system"}
from fireblocks_sdk import FireblocksSDK
api_key = ""
with open("fireblocks_secret.key", "r") as f:
private_key = f.read()
fireblocks = FireblocksSDK(private_key, api_key)
```
```java Java theme={"system"}
import com.fireblocks.sdk.FireblocksSDK;
import java.nio.file.Files;
import java.nio.file.Paths;
String apiKey = "";
String privateKey = new String(Files.readAllBytes(Paths.get("fireblocks_secret.key")));
FireblocksSDK fireblocks = new FireblocksSDK(privateKey, apiKey);
```
Replace `` with your API Key from the Fireblocks Console.
Install the Fireblocks CLI (Node.js 18+ required), then connect it to your workspace:
```bash theme={"system"}
npm install -g @fireblocks/fireblocks-cli
fireblocks --version
fireblocks configure # paste API key + path to fireblocks_secret.key
fireblocks whoami # verify credentials resolve and authenticate
```
Other installers (Homebrew, standalone binaries, yarn/pnpm) are documented on the [Fireblocks CLI](/docs/fireblocks-cli) page.
For agent workflows, your agent should run `fireblocks help-index` once to discover commands, and use `--dry-run` and `--idempotency-key` on writes.
## Step 3: Create a Vault Account
A Vault Account is where your assets are securely stored.
```typescript TypeScript theme={"system"}
const vault = await fireblocks.createVaultAccount('My First Vault');
console.log(vault);
```
```python Python theme={"system"}
vault = fireblocks.create_vault_account("My First Vault")
print(vault)
```
```java Java theme={"system"}
var vault = fireblocks.createVaultAccount("My First Vault");
System.out.println(vault);
```
```bash theme={"system"}
fireblocks vaults create-vault-account \
--data '{"name":"My First Vault"}' \
--no-confirm
```
You can view the new Vault account in the Console under **Accounts** > **Vault**.
If you’re using a Sandbox, your account should come pre-funded. If you need additional funds, see [Receiving funds into your Fireblocks account](https://support.fireblocks.io/hc/en-us/articles/4414266562450-Receiving-funds-into-your-Fireblocks-accounts) for more information.
## Step 4: Create a Transaction
Now that your vault has funds, you can create your first transaction.
```typescript TypeScript theme={"system"}
const transaction = await fireblocks.createTransaction({
assetId: 'ETH_TEST',
source: { type: 'VAULT_ACCOUNT', id: vault.id },
destination: { type: 'EXTERNAL_WALLET', id: '' },
amount: '0.01',
});
console.log(transaction);
```
```python Python theme={"system"}
transaction = fireblocks.create_transaction({
"assetId": "ETH_TEST",
"source": { "type": "VAULT_ACCOUNT", "id": vault["id"] },
"destination": { "type": "EXTERNAL_WALLET", "id": "" },
"amount": "0.01"
})
print(transaction)
```
```java Java theme={"system"}
var txRequest = new TransactionRequest();
txRequest.setAssetId("ETH_TEST");
txRequest.setSource(new Source("VAULT_ACCOUNT", vault.getId()));
txRequest.setDestination(new Destination("EXTERNAL_WALLET", ""));
txRequest.setAmount("0.01");
var tx = fireblocks.createTransaction(txRequest);
System.out.println(tx);
```
Preview the request first with `--dry-run`, then execute with an idempotency key so safe retries don't create duplicate transactions:
```bash theme={"system"}
# Preview
fireblocks transactions create-transaction \
--data '{"assetId":"ETH_TEST","amount":"0.01","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"EXTERNAL_WALLET","id":""}}' \
--dry-run
# Execute
fireblocks transactions create-transaction \
--data '{"assetId":"ETH_TEST","amount":"0.01","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"EXTERNAL_WALLET","id":""}}' \
--idempotency-key "$(uuidgen)" \
--no-confirm
```
## Step 5: Verify Transactions
To verify your transaction status, use the following.
For Fireblocks transactions:
```typescript TypeScript theme={"system"}
const tx = await fireblocks.getTransactionById(txId);
```
```python Python theme={"system"}
tx = fireblocks.get_transaction_by_id(txId)
```
```java Java theme={"system"}
var tx = getTransactionById(String txId);
```
For external transactions:
```typescript TypeScript theme={"system"}
const tx = await fireblocks.getTransactionByExternalTxId(externalTxId);
```
```python Python theme={"system"}
tx = fireblocks.get_transaction_by_external_tx_id(externalTxId)
```
```java Java theme={"system"}
var tx = getTransactionByExternalTxId(String externalTxId);
```
```bash theme={"system"}
# By Fireblocks transaction ID
fireblocks transactions get-transaction --tx-id --json
# By external transaction ID
fireblocks transactions get-transaction-by-external-id \
--external-tx-id --json
```
## Next Steps
**CLI**
* [Fireblocks CLI](/docs/fireblocks-cli) — install, overview, and quick start
* [CLI Authentication](/docs/cli-authentication) — credentials, profiles, and environment variables
* [CLI Usage](/docs/cli-usage) — commands, flags, exit codes, and examples
**SDKs**
* [TypeScript SDK](/reference/typescript-sdk)
* [Python SDK](/reference/new-python-sdk)
* [Java SDK](/reference/java-sdk)
**API and platform**
* [API Reference](/reference/api-overview) — REST endpoints and request bodies
* [Manage API keys](/docs/manage-api-keys) — CSR flow, roles, and rotation
* Automate transaction signing with [API co-signers](/docs/use-cosigners-for-signing-automation#/)
* Real-time updates with [webhooks](/reference/webhooks-gettingstarted-configuringwebhooks#/)
# Overview
Source: https://developers.fireblocks.com/docs/raw-signing
### Warning
Raw Signing is an insecure signing method and is not generally recommended. Bad actors can trick someone into signing a valid transaction message and use it to steal funds.
For this reason, Raw Signing is a premium feature that requires an additional purchase and is not available in workspaces by default.
If you're interested in this feature and want to see if your use case is eligible for it, please contact your Customer Success Manager.
Fireblocks Sandbox workspaces have Raw Signing enabled by default to allow for testing purposes.
# Overview
Raw Signing is a powerful feature within Fireblocks. As the Web3 world continues to evolve rapidly, Fireblocks provides the option to support additional chains and actions by signing an arbitrary message using the Fireblocks infrastructure.
Our WalletConnect integration and the Fireblocks Chrome Extension sometimes use Raw Signing to sign transactions initiated by dApps. You will need to add Policy rules for these dApp-initiated raw transactions to go through.
### Check out the Raw Signing Developer Guide [here](/reference/structure-the-api-call)
# What are the use cases for Raw Message Signing?
Typically, Raw Message Signing is used in the following scenarios:
* When you want to sign a transaction on a blockchain that Fireblocks doesn’t currently support
* When you want to perform an operation that we don’t currently support on a blockchain that we do support (e.g., staking on a lesser-known blockchain)
* When you want to use cryptography to prove and validate messages that are not supported by [Typed Message Signing](/docs/typed-message-signing-1) (e.g., Proof of Assets, Proof of Addresses)
* When someone sends funds to your address over a blockchain that we don’t currently support, and you want to recover the funds
# Enabling Raw Signing
By default, Raw Signing is not available in production workspaces. Contact your Customer Success Manager to enable Raw Signing.
If Raw Signing is disabled in your workspace and you attempt to create a raw transaction, it will fail and show the **BLOCKED\_BY\_POLICY** substatus.
# Policy rules for Raw Signing
Policies reject all raw transactions by default. After enabling the Raw Signing feature in your production workspace, you must add Policy rules that allow users to initiate, approve, and sign raw transactions from specific vault accounts.
You can also use your Policy rules to limit the range of derivation paths, vault accounts, and assets available for raw transactions. Unless explicitly defined otherwise in the rule, the rule matches all derivation paths. When creating the rule, select Groups and accounts as your source and enter Any vault. Then you can enter a derivation path.
The derivation path used in signing can be passed along with the signing request in one of two ways:
* **Explicitly:** By passing the signing algorithm and the full derivation path
* **Implicitly:** By passing the vault account ID, the asset ID, and (optionally) the change and the address index
These properties together comprise a full BIP44-like derivation path. Typically, this approach is used to create custom transactions on supported protocols.
# Segregate Duties
Source: https://developers.fireblocks.com/docs/segregate-duties
To ensure the security of your workspace operations, it is crucial to segregate duties and delegate responsibilities appropriately. The first and most important step is to distinguish between users handling critical managerial tasks and those managing regular operations.
For the former, it is important to understand the permission level of an administrator and the influence they will have with any changes made to the workspace. Please review this [article](https://support.fireblocks.io/hc/en-us/articles/360012832959-User-roles) for more information.
For day-to-day operations, consider three key roles in the transaction process when assigning responsibilities:
* Who will initiate transactions?
* Who will approve transactions?
* Who will sign off on transactions?
Once you have defined these responsibilities, review the following use cases to help you segregate duties properly:
**Manual Process:** Typically used for operations involving a large amount of assets. This involves 100% human intervention. A transaction will be initiated via the Fireblocks console UI, approved manually by certain people (user or group) on their mobile devices, and signed by either the same people or someone else. Note that approvers are not required to have an MPC key to approve transactions.
**Semi-Automated Process:** Used for operations that are not large in value but still significant enough to require human verification. Transactions can be initiated by a person via the UI or an API user and signed by either one of them.
**Fully Automated Process:** Commonly used for internal transactions (between Fireblocks VA) or withdrawals of small amounts. API users initiating transactions must have the relevant permissions. If the same user is linked with the API-cosigner machine, ensure they are assigned a signer permission role.
# Self-Custody Infrastructure
Source: https://developers.fireblocks.com/docs/self-custody-infrastructure
Be the owner of your funds without compromising speed and security using Fireblocks' self-custody infrastructure
# What is Self-Custody Infrastructure?
Fireblocks Self-Custody Infrastructure is a secure and reliable way to store your digital assets. With our robust APIs and multi-layer security, MPC, and Intel SGX, you can be sure that your funds are safe and accessible instead of handling the security work yourself.
[Start developing on Fireblocks today](https://www.fireblocks.com/developer-sandbox-sign-up/?gl=1*19mlzew*_ga*MTY4ODc5Mjc3Ni\[%E2%80%A6]_ga_D39L1D2ZX2*MTY4Nzg2MTQwOS4xNi4xLjE2ODc4Njc3OTMuMjcuMC4w).
# Set up and store your funds through Fireblocks Self-Custody Infrastructure
Using our self-custody technology, you can harness your funds to hold them securely and safely:
* **API Co-Signer:** Automate the approval and signing of transactions and maintain custody with our API Co-Signer.
* **MPC technology:** With MPC, the corresponding private key shares are created and encrypted in isolated environments among multiple parties. To sign transactions, the key shares are used to perform multiple rounds of computation without ever being brought into the same environment. Because of this, MPC eliminates the single point of compromise of private key creation and signing.
* **Secure Hardware Enclaves:** Self-custody your private keys in secure hardware enclaves to keep your keys safe from malicious software or unauthorized users.
* **Key backups:** Get a backup copy of all your signing keys and have full control over your funds.
Learn more about [our Custody Infrastructure](https://www.fireblocks.com/digital-asset-custody/).
# Guides
## Raw Message Signing
Support more chains and actions. Generate ECDSA and EdDSA signatures to [sign any transaction type or message](/docs/raw-signing).
## Typed Message Signing
Allows you to [sign messages using specific standard formats](/docs/typed-message-signing-1) that prefix the message with a magic string. For ETH\_MESSAGE and EIP712 messages.
## Custodial Services
Flexible MPC-based wallet infrastructure enables both [segregated vault structures and omnibus vault structures](/docs/custodial-services) based on your business needs.
## UTXO Consolidation
Leverage automation to [consolidate your unspent UTXO balances across UTXO wallets](/reference/consolidate-utxos) through special transactions that merge them into a single output.
## UTXO Manual Selection
Use dedicated API calls to [manually select specific UTXO asset wallet balances](/reference/select-utxos-for-a-transaction) to consolidate into a single transaction to send to your omnibus account.
## Creating an Omnibus Vault Structure
Use API keys to [generate intermediate vault accounts, identify incoming transactions, and sweep funds](/reference/create-omnibus-structure) to the Omnibus Deposits vault accounts.
## Sweep to Omnibus
How to [automate moving funds from intermediate vault accounts, assigned to your end-users](/reference/sweep-to-omnibus-1) for their deposits to your omnibus account.
## Validating Travel Rule transactions with Fireblocks and Notabene
Using the Fireblocks SDK to [submit transactions to Notabene for validation that they comply with the Travel Rule](/reference/validate-travel-rule) while keeping PII data encrypted.
# Developer Community
Want to learn more from Fireblocks knowledge experts and other developers? [Join our developer community today](https://community.fireblocks.com/)!
# Set Auto Fueling Property
Source: https://developers.fireblocks.com/docs/set-auto-fueling-property
# Overview
Vault account auto-fueling is always available for API users with the Gas Station enabled, and any vault account with the Gas Station badge in the Console participates in the Gas Station service.
* When an incoming token transaction to an auto-fueling vault account completes, Fireblocks automatically transfers the appropriate base asset from the Gas Station to the vault account. This is because the auto-fueled vault account must have a token with a non-zero balance on the relevant network where you are expecting an auto-fueling transaction.
* When an outgoing transaction from an auto-fueling vault account completes, Fireblocks checks the token and gas balance. The vault account is refueled if the token balance is above 0.00001 and the base asset is below the set threshold. Token transfers from this vault account to any destination will then have sufficient gas to cover transaction fees.
## Enabling auto-fueling in the Console
For new vault accounts, select **Auto-fuel with gas after an incoming transaction completes** when you create the account.
For existing vault accounts, go to **My Funds** > **Accounts**, find the appropriate vault account, and then select **More Actions** (**...**) > **Enable Auto-Fueling** > **Enable**. The Gas Station badge appears next to the name of the vault account when you're done.
## Disabling auto-fueling in the Console
In the Fireblocks Console, go to **My Funds** > **Accounts**, find the appropriate vault account, and then select **More Actions** (**...**) > **Disable Auto-Fueling** > **Disable**. The Gas Station badge is removed when you're done.
## Enabling auto-fueling via the API
For new vault accounts, call the [Create a new vault account endpoint](/reference/createvaultaccount) and set the **autoFuel** field to **true**.
For existing vault accounts:
1. Call the [List vault accounts (paginated) endpoint](/reference/getpagedvaultaccounts) to find the vault account's ID.
2. Call the [Turn auto-fueling on or off endpoint](/reference/setvaultaccountautofuel), enter the vault account's ID in the **vaultAccountId** field, and then set the **autoFuel** field to **true**.
## Disabling auto-fueling via the API
1. Call the [List vault accounts (paginated) endpoint](/reference/getpagedvaultaccounts) to find the ID of the vault account.
2. Call the [Turn auto-fueling on or off endpoint](/reference/setvaultaccountautofuel), enter the vault account's ID in the **vaultAccountId** field, and then set the **autoFuel** field to **false**.
### Check the Gas Station [developer guide](/reference/enable-auto-fueling) for API code examples.
# Set Policies
Source: https://developers.fireblocks.com/docs/set-transaction-authorization-policy
Policies define which actions are allowed or blocked in your Fireblocks workspace: controlling who can initiate transactions, from which sources, to which destinations, and under what conditions. You can manage Policies directly in the Fireblocks Console using the Policy Editor, or programmatically via the API.
## Managing policies via the API
The Fireblocks API gives you two ways to manage your Policy: publish changes directly, or work with a draft before publishing.
### Publish directly
To retrieve your active Policy or publish a new one without a review step, use these endpoints:
* [Get the active policy](/reference/getactivepolicy)
* [Publish a new set of policy rules](/reference/publishdraft)
### Work with drafts
If your workflow requires reviewing or validating Policy changes before they go live, use Policy Drafts:
* [Get the active draft](/reference/getdraft)
* [Update the draft with a new set of rules](/reference/updatedraft)
* [Publish a draft by ID](/reference/publishpolicyrules)
## Best practices
Policy rules are evaluated in the order they are defined, so rule ordering matters. Place the most restrictive rules first, and order rules by likelihood of a match. This ensures high-risk or tightly scoped rules are evaluated before broader, more permissive ones, reducing the chance of a transaction being incorrectly approved.
## Learn more
* [About Policies](https://support.fireblocks.io/hc/en-us/articles/19156998685980-About-Policies): Help Center overview of how Policies work
* [Policies developer guide](/reference/configure-transaction-authorization-policy): How to work with Policies programmatically
# Stake Assets
Source: https://developers.fireblocks.com/docs/stake-assets
# Overview
You can stake to various networks from your Vault using the Fireblocks API. When staking, you select a third-party staking provider to operate the validators associated with your staked funds. Typically, the staked amount is locked for a certain period of time.
Staked assets become eligible to receive rewards after the network's activation period. Staking rewards are calculated over a period of time usually known as an epoch. This is the period of time in which validators and their staked amount are accounted for. Depending on the network, an epoch may be anywhere from a few minutes to several days. Typically, staking rewards are calculated and distributed after each epoch ends.
When you unstake your assets, you no longer generate staking rewards, but you're able to use those assets for other transactions.
# Staking via Fireblocks API
To stake, you must fund a vault account with the asset you want to stake and create Policy rules for staking. Then create staking transactions using the dedicated [staking API endpoints](/reference/getchains).
Staking with the Fireblocks API allows you to:
* Easily and securely stake assets through native API calls.
* Create dedicated Policy rules for staking using the **Stake** operation type.
* Track the status and rewards for your staked funds.
* Initiate staking transactions without the need for SDKs, scripts, or Raw Signing.
* Select validators to oversee your staked funds.
## Supported assets
* Ethereum
* Solana
* MATIC
### Check out the Staking developer guide [here](/reference/stake-assets-1)
# Supported Networks
Source: https://developers.fireblocks.com/docs/supported-networks
The following table contains the blockchain networks supported by the Fireblocks Embedded Wallet (EW) service.
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
### Missing something?
Fireblocks is always looking towards improving its vast chain offering. If you're missing a blockchain or a token on this list, contact your customer success manager and let us know!
| Network Name | Asset Symbol | Network Protocol | API Asset ID |
| ------------------------- | ------------ | ---------------- | -------------- |
| Arbitrum | ETH | ETH | ETH-AETH |
| Astar | ASTR | ETH | ASTR\_ASTR |
| Aurora\_dev | AURORA | ETH | AURORA\_DEV |
| Avalanche (C-Chain) | AVAX | ETH | AVAX |
| Axelar | AXL | COSMOS | AXL |
| Base | ETH | ETH | BASECHAIN\_ETH |
| Bitcoin | BTC | BTC | BTC |
| BNB Smart Chain | BNB | ETH | BNB\_BSC |
| Canto | CANTO | ETH | CANTO |
| Celestia | TIA | COSMOS | CELESTIA |
| Celo | CELO | ETH | CELO |
| Chiliz | CHZ | ETH | CHZ |
| Chiliz (\$CHZ) | CHZ | ETH | CHZ\_CHZ2 |
| Cosmos Hub | ATOM | COSMOS | ATOM\_COS |
| dYdX | DYDX | COSMOS | DYDX |
| Ethereum | ETH | ETH | ETH |
| Ethereum Proof-of-Work | ETHW | ETH | ETHW |
| Evmos | EVMOS | ETH | EVMOS |
| Fantom | FTM | ETH | FYM |
| Gnosis Chain (EVM) | xDAI | ETH | xDAI |
| HT Chain | HT | ETH | HT\_CHAIN |
| KAVA | KAVA | ETH | KAVA |
| Linea | ETH | ETH | LINEA |
| Matic Gas Token (Polygon) | MATIC | ETH | MATIC\_POLYGON |
| Moonbeam | GLMR | ETH | GLMR\_GLMR |
| Moonriver | MOVR | ETH | MOVR\_MOVR |
| Oasys | OAS | ETH | OAS |
| Optimistic Ethereum | ETH | ETH | ETH-OPT |
| Osmosis | OSMO | COSMOS | OSMO |
| Ronin | RON | ETH | RON |
| RSK Smart Bitcoin | RBTC | ETH | RBTC |
| Shimmer | SMR | ETH | SMR\_SMR |
| SmartBCH | BCH | ETH | SMARTBCH |
| Songbird | SGB | ETH | SGB |
| Songbird (Legacy) | SGB | ETH | SGB\_LEGACY |
| TokenX | TKX | ETH | TKX |
| TRON | TRX | TRX | TRX |
| Velas | VLX | ETH | VLX\_VLX |
| XDC Network | XDC | ETH | XDC |
| zkEVM | ETH | ETH | ETH\_ZKEVM |
| Solana | SOL | SOL | SOL |
| Algorand\* | ALGO | ALGO | ALGO |
| Stellar\* | XLM | XLM | XLM |
| Ripple | XRP | XRP | XRP |
| TON\* | TON | TON | TON |
| LTC | LTC | BTC | LTC |
\*Asset is not supported for takeover.
### Additional Assets
Additional testnets and tokens we support might not appear in the list above.
In order to query the full list of assets supported by our offering, please use the [Retrieve supported assets endpoint](/reference/wallets-getsupportedassets).
# Supported Platforms
Source: https://developers.fireblocks.com/docs/supported-platforms
The Fireblocks Embedded Wallets (EW) SDK offers tools to build on multiple platforms.
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
## Web
We offer a [web SDK](https://www.npmjs.com/package/@fireblocks/ncw-js-sdk) for your web development. You can also use our [Embedded Wallets API](/reference/create-1#/) to build your apps.
Refer to our [React Demo App](doc:react-demo-application) or look at our [open source code](https://github.com/fireblocks/ncw-web-demo-v2) .
## Mobile
#### iOS Swift SDK
Refer to [iOS Native Demo App](doc:ios-native-demo-app) to learn how you can use our iOS SDK.
#### Android Kotlin SDK
Refer to [Android Native Demo App](doc:android-demo-application) to learn how you can use our Android SDK.
# Swap examples via DeFi
Source: https://developers.fireblocks.com/docs/swap-via-direct-access-providers-defi
### **Beta Feature**
The Trading API is currently in beta and subject to change. For participation details, contact your Fireblocks Customer Success Manager or email [CSM@fireblocks.com](mailto:CSM@fireblocks.com).
This guide provides a step-by-step example of how to execute a swap using the Fireblocks Trading API via direct access providers, such as Uniswap. A swap is the process of exchanging one cryptocurrency for another on the same network. The guide demonstrates swapping ETH for USDC on Ethereum using Uniswap as the direct access provider.
## Prerequisites
Before you begin, ensure you have completed the prerequisites outlined in the [Trading API Overview](/docs/trading-api-overview#/):
* ✅ Fireblocks API credentials configured
* ✅ Vault accounts with sufficient assets
* ✅ Fireblocks TypeScript SDK installed (`@fireblocks/[email protected]`)
## SDK Setup
First, set up your Fireblocks SDK client:
```typescript TypeScript theme={"system"}
import { Fireblocks } from "@fireblocks/ts-sdk";
import * as fs from "fs";
// Initialize the Fireblocks SDK
const fireblocks = new Fireblocks({
apiKey: "your-api-key",
secretKey: fs.readFileSync("/path/to/your/secret.key", "utf8"),
basePath: "https://api.fireblocks.io"
});
```
## Swap Flow Overview
The following steps outline the process for executing a swap via direct access providers:
```text theme={"system"}
1. List Providers
2. Approve Terms (executed once per workspace and ONLY via the Fireblocks console)
3. Create Quote
4. Execute Order
5. Monitor Order
```
## Step 1: List Available Providers
Before trading, retrieve the list of available providers and use the response to identify the `id` of your desired provider.
### API Call
```typescript theme={"system"}
// List all available trading providers
const providersResponse = await fireblocks.tradingBeta.getTradingProviders({
pageSize: 20
});
// Filter for direct access providers only (accountBased: false)
const directAccessProviders = providersResponse.data.data.filter(provider => !provider.accountBased);
```
### Response Example
```json theme={"system"}
{
"data": [
{
"id": "UNISWAP_CLASSIC",
"name": "Uniswap Classic",
"logo": "https://example.com/logos/uniswap.png",
"accountBased": false,
"approved": false,
"hasTermsOfService": true,
"termsOfServiceUrl": "https://uniswap.org/terms"
}
],
"total": 1,
"next": null
}
```
### Key Fields Explained
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------- |
| `id` | Unique identifier for the provider (use this in subsequent API calls) |
| `name` | Display name of the trading platform |
| `accountBased` | `false` for direct access providers, `true` for account-based providers |
| `hasTermsOfService` | Whether the provider requires Terms of Service approval |
| `termsOfServiceUrl` | URL to review the Terms of Service |
| `approved` | For direct access providers: indicates if Terms of Service have been approved |
Direct access providers may require one-time Terms of Service approval. The fields hasTermsOfService and approved indicate whether approval is required and whether your workspace already approved it. Approval must be done once per workspace via the Fireblocks Console.
### For more details about this endpoint, see the [Get Providers API Reference](/reference/gettradingproviders).
## Step 2: Approve Terms of Service (Direct Access Providers Only)
Direct access providers require one-time Terms of Service approval before trading. **Approval must be done in the Fireblocks Console** (not available via SDK).
### Check Approval Status
```typescript theme={"system"}
// Get provider details to check approval status
const provider: DirectAccessProvider = providersResponse.data.data.find(
p => p.id === "UNISWAP_CLASSIC"
);
if (provider?.hasTermsOfService && !provider.approved) {
throw new Error("Approve Terms of Service in Fireblocks Console before proceeding");
}
```
## Clarification on how to translating user intent into baseAssetId, quoteAssetId, side, and baseAmount
When creating a **Quote** or an **Order**, you express the trade using:
* `baseAssetId`: the asset you **receive** on **BUY** / **give** on **SELL**
* `quoteAssetId`: the counter asset used to **pay**/**receive**
* `side`:
* `BUY`: receive base / pay quote
* `SELL`: give base / receive quote
* `baseAmount`: amount in `baseAssetId`
* `BUY`: base amount to receive
* `SELL`: base amount to sell
### Examples
| Intent | baseAssetId | quoteAssetId | side | baseAmount |
| ----------------------- | ----------- | ------------ | ---- | ---------- |
| Buying 100 BTC with USD | BTC | USD | BUY | 100 |
| Buying 100 USD with BTC | USD | BTC | BUY | 100 |
| Selling 100 BTC for USD | BTC | USD | SELL | 100 |
| Selling 100 USD for BTC | USD | BTC | SELL | 100 |
## Step 3: Create a Quote for the Swap
Creating a quote is required before executing a swap via direct access providers. A quote provides you with the exact exchange rate, expected amounts, fees, and price impact for the swap.
### API Call
```typescript theme={"system"}
// Create a quote for swapping ETH to USDC on Ethereum with Uniswap
const quoteResponse = await fireblocks.tradingBeta.createQuote({
createQuote: {
scope: [{ providerId: "UNISWAP_CLASSIC" }], // Direct access provider (no accountId)
baseAssetId: "ETH", // Asset you're selling
quoteAssetId: "USDC", // Asset you're receiving
baseAmount: "0.5", // Amount of ETH to sell
side: "SELL", // Direct access provider quotes support SELL only
slippageBps: 50, // Optional - Defaults to 50 BPS (0.5%)
settlement: { // Required for direct access provider quotes
type: "DVP",
sourceAccount: {
type: "VAULT_ACCOUNT",
accountId: "0"
},
destinationAccount: {
type: "VAULT_ACCOUNT",
accountId: "0"
}
}
},
idempotencyKey: `quote-${Date.now()}`
});
const quote = quoteResponse.data.quotes[0];
```
### Quote Response Example
```json theme={"system"}
{
"quotes": [
{
"id": "quote_8f2e4d1a9c5b7e3f",
"via": {
"type": "PROVIDER",
"providerId": "UNISWAP_CLASSIC"
},
"type": "COMMITTED",
"baseAssetId": "ETH",
"quoteAssetId": "USDC",
"baseAmount": "0.5",
"quoteAmount": "1247.50",
"quoteMinAmount": "1241.25",
"priceImpact": 0.005,
"expiresAt": "2024-01-15T10:35:00.000Z",
"generalFees": [
{
"feeType": "NETWORK",
"assetId": "ETH",
"amountType": "FIXED",
"amount": "0.01"
}
],
"executionSteps": [
{
"type": "APPROVE",
"fee": {
"feeType": "NETWORK",
"assetId": "ETH",
"amountType": "FIXED",
"amount": "0.005"
}
},
{
"type": "CONTRACT_CALL",
"fee": {
"feeType": "NETWORK",
"assetId": "ETH",
"amountType": "FIXED",
"amount": "0.005"
}
}
]
}
]
}
```
### Understanding Quote Fields
| Field | Description |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | Unique quote identifier (use when creating order) |
| `type` | Quote type: `COMMITTED` - the provider commits to the quote rates (guaranteed execution at the quoted price with respect to slippage boundaries), `INDICATIVE` - an indication of expected prices (rates may vary at execution time) |
| `baseAmount` | Amount you're spending/selling |
| `quoteAmount` | Expected amount you'll receive |
| `quoteMinAmount` | Minimum amount guaranteed (accounting for slippage) |
| `priceImpact` | Deviation from market price and execution price due to trade size or limited liquidity (as a decimal, e.g., 0.005 = 0.5%). A high price impact means your transaction will result in a substantial loss of funds |
| `expiresAt` | Quote expiration time (typically 1-5 minutes) |
| `generalFees` | Provider fees for the trade |
| `executionSteps` | Array of steps required to complete the trade, each containing a `type` field that can be `APPROVE` (token approval), `PERMIT` (permit signature), `CONTRACT_CALL` (smart contract interaction), `EXECUTE` (main swap execution), `SETTLEMENT` (settling funds), or `DELIVERY` (delivering assets). Each step may include associated fees |
> **Note:** Quotes expire quickly (typically within 1-5 minutes). Create your order promptly after receiving a quote.
### For more details about this endpoint, see the [Create Quote API Reference](/reference/createquote).
## Step 4: Execute the Swap Order
Once you have a quote, execute the swap using that quote. Direct access providers like Uniswap require a quote to ensure you get the expected rate and protection against price slippage.
### Execute Order with Quote
```typescript theme={"system"}
// Execute swap order using the quote from Step 3
const orderResponse = await fireblocks.tradingBeta.createOrder({
createOrderRequest: {
via: {
type: "PROVIDER", // Direct access provider execution
providerId: "UNISWAP_CLASSIC"
},
executionRequestDetails: {
type: "QUOTE",
quoteId: quote.id // Quote ID from Step 3
},
settlement: {
type: "DVP", // Direct access swaps always use DVP
sourceAccount: {
type: "VAULT_ACCOUNT",
accountId: "0"
},
destinationAccount: {
type: "VAULT_ACCOUNT",
accountId: "0"
}
}
},
idempotencyKey: `order-${Date.now()}`
});
const order = orderResponse.data;
```
> **Why direct access providers require quotes:** Unlike some account-based providers, direct access providers (like Uniswap) through Fireblocks require creating a quote first. This ensures you know the exact exchange rate, fees, and slippage protection before the transaction executes on-chain.
### For more details about this endpoint, see the [Create Order API Reference](/reference/createorder).
## Step 5: Monitor Order Status
After creating an order, monitor its execution status to track completion.
### Get Order Details
```typescript theme={"system"}
// Get order status and details
const orderStatusResponse = await fireblocks.tradingBeta.getOrder({
orderId: order.id
});
console.log("Order status:", orderStatusResponse.data.status);
```
### For more details about this endpoint, see the [Get Order Details API Reference](/reference/getorder).
### List All Orders
```typescript theme={"system"}
// List orders with optional filters
const ordersResponse = await fireblocks.tradingBeta.getOrders({
pageSize: 20,
order: "ASC", // Order by createdAt
providerId: ["UNISWAP_CLASSIC"], // Filter by provider
statuses: ["COMPLETED"] // Filter by status
});
console.log("Orders:", ordersResponse.data.data);
```
### For more details about this endpoint, see the [Get Orders (List) API Reference](/reference/getorders).
### Order Status Values
| Status | Description |
| --------------------- | ------------------------------------------------ |
| `CREATED` | Order has been created and is being processed |
| `AWAITING_PAYMENT` | Waiting for payment to be received |
| `PENDING_USER_ACTION` | Requires user action (e.g., approval in console) |
| `PROCESSING` | Order is being executed |
| `COMPLETED` | Order has been successfully completed |
| `FAILED` | Order execution failed |
| `CANCELED` | Order was canceled |
## Additional Resources
* [Trading API Overview](/docs/trading-api-overview#/)
* [On-Ramp, Off-Ramp, and Bridge/Swap via Account-Based Providers (CeFi)](/docs/on-ramp-off-ramp-and-bridgeswap-via-account-based-providers-cefi#/) - For on-ramp, off-ramp, and other account-based provider use cases
* Fireblocks SDKs: [Python](https://pypi.org/project/fireblocks/) | [TypeScript](https://www.npmjs.com/package/@fireblocks/ts-sdk) | [Java](https://central.sonatype.com/artifact/com.fireblocks.sdk/fireblocks-sdk/overview)
* [Fireblocks Developer Portal](/)
## Support
For questions or issues with the Trading API:
* Contact your Fireblocks Customer Success Manager
* Email: [CSM@fireblocks.com](mailto:CSM@fireblocks.com)
* Check the [Fireblocks Developer Portal](/) for updates
# Sweep Funds
Source: https://developers.fireblocks.com/docs/sweep-funds
## Overview
Once your client, aka the end-user, deposits into an intermediary vault account, most customers will want to perform a sweeping operation. This operation consolidates all deposited funds from the intermediary vault accounts into a single treasury management vault account for various business purposes.
Sweeping funds involves moving assets from address A to address B. It is important to note that this is an on-chain operation and includes **transaction fee payments**.
## Trigger the Sweeping Operation
The trigger for the sweeping operation varies from customer to customer, depending on specific strategies, business needs, and regulatory requirements.
For instance, some customers may choose to sweep the funds immediately after the deposit is completed. In contrast, others may trigger the sweeping mechanism only after a certain amount of deposits (either by total balance or number of deposits). Since sweeping is an on-chain operation that incurs transaction fees, some customers opt to execute the sweeping operation only when the current network fee is below a predefined acceptable threshold. Fireblocks enables customers to monitor current network fees/gas prices using the `GET /estimate_network_fee` [endpoint](/reference/estimatenetworkfee).
There is no right or wrong approach; customers should determine what works best for their business needs.
### Sweep timing strategies
You can sweep deposits from deposit accounts immediately after each deposit, or batch them over time. As deposits accumulate or network fees change, you can use logic-based triggers based on time, balance, or fee conditions.
For example, to minimize fees, you may choose to sweep when the network is less congested or when gas prices fall below a defined threshold. If you want to sweep promptly, sweeping can occur immediately after a deposit or once Gas Station fueling is complete.
### Gas Station
The Gas Station feature allows you to maintain a wallet fueled with relevant base tokens. When a deposit account receives tokens, this wallet can fuel (transfer) base tokens to the deposit account to cover fees and enable sweeping. You can configure this behavior, including when the transfer occurs and how much is transferred.
## Automate Sweeping
To create sweeping transactions, Fireblocks customers can use the `POST /transactions` [endpoint](/reference/createtransaction). First, identify the vault account from which you want to initiate the sweeping operation and then send the sweeping transaction request to the Fireblocks API. This process should be executed for every vault account from which sweeping is desired.
Automating sweeping transactions involves not only creating the transactions in a fully automated manner but also automating the entire signing process. We recommend using an [API Co-Signer](/reference/api-cosigner-installation-flow) to automatically sweep funds according to your organization's logic and fee prices.
When sweeping funds, you also pay a fee in the base asset of the deposited token's blockchain. To ensure you always have enough funds for the sweeping transaction, we introduced the [Fireblocks Gas Station](/docs/work-with-gas-station) feature, which automatically identifies incoming transactions to your predefined vault accounts and deposits enough of the base asset to cover fees for sweeping funds to your main treasury.
### Automation rules
Fireblocks is rolling out an automation feature that allows you to define rules to trigger transactions. In the future, this will include automatic sweeping and reconciliation rules across groups of wallets. Currently, rules can only be applied to specific vault accounts as the source.
For more information, see [About Automation](https://support.fireblocks.io/hc/en-us/articles/14873112741660-About-Automation).
## Reconciliation Processes
Because memo-based wallets function as omnibus wallets, funds can be reconciled to withdrawal wallets or to cold and treasury management workspaces as needed.
UTXO-based wallets also operate as omnibus wallets, allowing multiple deposited UTXOs to be reconciled to target destinations. However, transaction size limits and MPC restrictions apply:
* For Bitcoin-based wallets, a single transaction is limited to 250 UTXOs.
* For Cardano transactions, the overall size is capped at 16 KB.
To determine the maximum spendable amount before initiating a sweep, call the [Get max spendable amount in a transaction](/reference/getmaxspendableamount) endpoint.
UTXO-based chains support multiple destinations, allowing funds to be moved to different targets (for example, cold storage and withdrawal wallets) within a single transaction. For account-based chains, sweeping is done per deposit wallet.
## Fees
Because sweeping is normally less time-sensitive, transaction fees can be set lower than the prevailing network fees required for immediate confirmation.
## Sweeping Tokens
When sweeping tokens, the wallet should have enough native asset balance to cover the transaction fees. However, some chains support models where another account can pay the fee:
* EVM chains: Gasless transactions (currently in development and supported for a limited set of tokens)
* Universal: Gasless transactions once EIP-7702 support is obtained
* Solana: Fee payer model
# Tokenization
Source: https://developers.fireblocks.com/docs/tokenization
Deploy, manage, mint, and burn custom tokenized on-chain assets securely using the Fireblocks API
# What is Tokenization?
The Fireblocks asset tokenization platform is a secure and compliant way to digitalize assets and build blockchain-based applications. Our REST API provides powerful capabilities for automating tasks like creating, redeeming, managing, and issuing tokens, such as stablecoins or security tokens.
[Start developing on Fireblocks today](https://www.fireblocks.com/developer-sandbox-sign-up/?gl=1*19mlzew*_ga*MTY4ODc5Mjc3Ni\[%E2%80%A6]_ga_D39L1D2ZX2*MTY4Nzg2MTQwOS4xNi4xLjE2ODc4Njc3OTMuMjcuMC4w).
# Launch your tokenization project with Fireblocks API
You can use our Fireblocks API for tokenization in different ways:
* Tokenize any asset, including fiat currencies, securities, and other illiquid assets
* Mint new tokens
* Manage smart contracts and whitelisting approval
* Execute any smart contract function
* Secure custody of your tokens
* Trade your tokens on exchanges or through peer-to-peer (P2P) transactions
* Burn tokens that are no longer needed to manage the token supply
* Integrate with other DeFi applications
With the Fireblocks asset tokenization platform, you can use our API to automate minting and token issuance 24/7. You can also manage your daily token operations using our easy-to-use dashboard.
Learn about [our turnkey solution](https://www.fireblocks.com/platforms/tokenization/).
# Guides
## Raw Message Signing
Support more chains and actions. Generate ECDSA and EdDSA signatures to [sign any transaction type or message](/docs/raw-signing).
## Typed Message Signing
Allows you to [sign messages using specific standard formats](/docs/typed-message-signing-1) that prefix the message with a magic string. For ETH\_MESSAGE and EIP712 messages.
## Creating Vaults and Wallets
[Generate Fireblocks vault accounts and asset wallets](/docs/creating-vaults-and-wallets) at scale for both account-based and UTXO asset wallet types using the Fireblocks API and SDKs.
## Whitelisting External Wallets
Use API calls and endpoints that [whitelist external wallet addresses](/docs/whitelisting-external-wallets) so that you can send transactions from wallets that exist outside your Fireblocks Vault.
## Minting an NFT
[Mint and verify Non-Fungible Tokens (NFT)](/reference/mint-an-nft) for your NFT collection using the Fireblocks Hardhat Plugin or Web3 Provider.
## Ethereum Smart Contract Development
Smart contract development frameworks to [develop, test, and deploy smart contracts on EVM-based blockchains](/reference/hardhat-plugin) easily. Four different ways to deploy your contracts.
# Developer Community
Want to learn more from Fireblocks knowledge experts and other developers? [Join our developer community today](https://community.fireblocks.com/)!
# Overview
Source: https://developers.fireblocks.com/docs/trading-api-overview
## Introduction
The Fireblocks Trading API enables several use cases related to liquidity and conversions, executing trades directly from your Fireblocks workspace, integrating dApps and centralized providers. With it, you can create Orders for the following use cases:
* Swap one asset to another on decentralized and centralized providers, over the same network. For example, swap USDC over Ethereum to USDT over Ethereum from one of your vaults via dApps like Uniswap or connected accounts like Scrypt
* On/off ramp via connected accounts with one of the providers. For example, on-ramp MXN to USDC over Polygon via your connected account with Alfred Pay
* Bridge assets between different chains via account-based providers (see [On-Ramp, Off-Ramp, and Bridge/Swap via Account-Based Providers (CeFi)](/docs/on-ramp-off-ramp-and-bridgeswap-via-account-based-providers-cefi))
**Additional use cases:**
* Convert one asset to another within your connected account with account-based providers - to be added in the near future
This guide outlines the process for executing Orders using the Fireblocks API, including prerequisites, a detailed workflow, and necessary code examples for successful operations utilizing the different use cases mentioned above.
## Core Terminology
| Term | Description |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Order** | An instruction created through the trading API that defines what asset to buy or sell, at what price (market or quote), and how to settle it (DVP or prefunded). Each order has a unique ID and a lifecycle status that remains until it is completed or fails. |
| **Quote** | A temporary price offer from a provider that defines the exchange rate and expiry time. Quotes can be Indicative (for price preview only) or Committed (locked and executable until expiration). |
| **Provider** | External trading provider or exchange venue. For example, Bridge or AlfredPay for account-based providers, and Uniswap for direct access providers are commonly used in DeFi. |
| **Settlement Type** | Defines how and when funds move during a trade.- **DVP**: The provider waits for the user's fund deposit before executing the order, ensuring delivery occurs only after payment is received.- **Prefunded**: Executes instantly using the user's existing balance already held with the provider. |
| **Execution Type** | Defines how the order price is determined.- **Market**: Executes immediately at the best available rate from the provider.- **Quote**: Executes at a locked rate from a committed quote created beforehand using the Quote endpoint. |
| **Participants Identification** | Defines the originator and beneficiary involved in an order. Used to determine who initiates and who receives the transaction, and what level of PII data is required by the provider (e.g., first-party vs third-party). |
## Understanding Trading Providers
The Fireblocks Trading API supports two types of providers:
### Direct Access Providers
DeFi platforms that provide direct access to decentralized protocols without requiring account management, such as Uniswap.
**Key Characteristics:**
* **Access Type**: Direct - no account credentials needed
* **Approval**: One-time Terms of Service acceptance
### Account-Based Providers
Centralized providers that require users to open an account with them. Account-based access requires credentials (API keys).
**Key Characteristics:**
* **Access Type**: Account-based - customers need to open an account with the provider before they can use the API to create Orders via Fireblocks. After creating the account, the customer needs to generate API keys within their account in the provider console, and then connect the account via the connected-account page in the Fireblocks console. For detailed instructions, see [Fireblocks Connected Accounts](https://support.fireblocks.io/hc/en-us/articles/360017435399-Fireblocks-connected-accounts)
## Prerequisites
### 1. Fireblocks API Credentials
* Obtain API and Secret Keys from Fireblocks.
* Ensure the credentials have sufficient permissions for trading operations.
### 2. SDK Installation
Install or update the Fireblocks SDK with trading support before proceeding.
### 3. Other Requirements
Different providers have specific requirements:
**For direct access providers:**
* Trades execute on-chain, requiring gas fees in the native blockchain asset. For example, Ethereum-based swap orders via Uniswap will require you to have ETH for gas
* The execution of direct access orders is done via smart contracts. Ensure you have policy rules that allow smart contract calls within your policy
**For account-based orders:**
* Minimum trade amounts vary by platform
* Execution and settlement are handled through connected accounts
* Ensure you have both Orders and Transfer policy rules inside your policy
## High-Level Trading Flow
```text theme={"system"}
1. List Providers
│
├─→ GET /providers
│ └─→ Returns available providers
│
2. Approve Terms (For direct access only)
│
├─→ One-time approval for direct access providers - Approved only from the console
│
3. Create Quote (optional - some providers allow creating Market orders without creating a quote beforehand)
│
├─→ POST /trading/quotes
│ └─→ Get exchange rate, amounts, and fees
│
4. Create Order
│
├─→ POST /trading/orders
│ ├─→ Using quote (quote-based execution)
│ └─→ Direct market order
│
5. Monitor Order
│
└─→ GET /trading/orders/{orderId}
└─→ Track execution status and completion
```
## Next Steps
See the following guides for implementation examples:
* [Swap via Direct Access Providers (DeFi)](/docs/swap-via-direct-access-providers-defi#/) - Step-by-step guide for executing swaps using direct access providers like Uniswap
* [On-Ramp, Off-Ramp, and Bridge/Swap via Account-Based Providers (CeFi)](/docs/on-ramp-off-ramp-and-bridgeswap-via-account-based-providers-cefi#/) - Step-by-step guide for on-ramp, off-ramp, and swap operations using account-based providers
# Transaction Flows
Source: https://developers.fireblocks.com/docs/transaction-flows
For Fireblocks' recommended embedded wallet solution, see [Dynamic Embedded Wallets](/docs/dynamic-embedded-wallets). The documentation below covers the legacy Embedded Wallet APIs and SDKs.
## Deposits
* External -> Fireblocks Embedded Wallet (EW)
* External -> Self-Custodial (vault account)
## Withdrawals
* EW -> One-Time Address
* EW -> Whitelisted Address
* Self-Custodial (vault account) -> One-Time Address
* Self-Custodial (vault account) -> Whitelisted Address
Learn more about [one-time addresses](https://support.fireblocks.io/hc/en-us/articles/4409104568338-One-Time-Address-feature) and [whitelisted addresses](https://support.fireblocks.io/hc/en-us/articles/360017819439-Whitelisting-new-addresses).
## Transfers between peers
* EW -> Self-Custodial (vault account)
* Self-Custodial (vault account) -> EW
* Self-Custodial (vault account) -> Exchange account
* Self-Custodial (vault account) -> Fiat account
* Self-Custodial (vault account) -> Fireblocks Network
Learn more about [exchange accounts](https://support.fireblocks.io/hc/en-us/articles/360017435399-Fireblocks-exchange-connectivity), [fiat accounts](https://support.fireblocks.io/hc/en-us/articles/360018286760-Fiat-accounts), and the [Fireblocks Network](https://support.fireblocks.io/hc/en-us/articles/6107038882460-Overview-of-the-Fireblocks-Network).
## Transfers between Embedded Wallets
The Fireblocks EW feature allows you to transfer funds between your embedded wallets (including self-transfers) forming your exclusive "Fireblocks Network." There's no need to handle destination addresses. You can use wallet IDs for simplified and secure internal transactions.
# Treasury Management
Source: https://developers.fireblocks.com/docs/treasury-management
Store your funds securely in hot and cold wallets, manage your fund operations, and connect to exchanges, DeFi, and trading counterparties with Fireblocks Treasury Management
# What is Treasury Management?
Fireblocks Treasury Management helps maintain a holistic view of your firms’ assets across wallets, connected venues, and fiat providers with a view to managing operational risk and liquidity.
[Start developing on Fireblocks today](https://www.fireblocks.com/developer-sandbox-sign-up/?gl=1*19mlzew*_ga*MTY4ODc5Mjc3Ni\[%E2%80%A6]_ga_D39L1D2ZX2*MTY4Nzg2MTQwOS4xNi4xLjE2ODc4Njc3OTMuMjcuMC4w).
# Set up, maintain, and scale your fund operations through Fireblocks Treasury Management
Using Fireblocks Treasury Management, you can streamline the functionality of your operations, enabling you to grow and scale securely:
* **Protect fund operations:** Safely store tokens and NFTs and securely access exchanges or fiat accounts with our multi-layer security.
* **Set up governance rules:** Use transaction authorization policy rules to create automated preferences catered around specific business requirements. Configure different roles and approval levels for stakeholders, and automate approval workflows to save time and maintain efficiency.
* **Operationalize treasury management:** Use our services to view all treasury assets across hot or cold wallets and track and report the movement of internal funds.
* **Easily move assets around:** Use Treasury Funds in DeFi, Staking, or Tokenized Funds. Use our Gas Station for seamless gas management as you move assets.
* **Make secure transfers:** Connect with counterparties across the Fireblocks Network and transact in a secure channel taking advantage of address resolution while preventing human errors or man-in-the-middle attacks.
* **Trading:** Automate, rebalance, and transfer between exchange accounts while minimizing counterparty risk to exchanges using our treasury management offering.
Learn more about [our Treasury Management](https://www.fireblocks.com/blog/the-4-pillars-of-great-treasury-management-in-web3/).
# Guides
## Raw Message Signing
Support more chains and actions. Generate ECDSA and EdDSA signatures to [sign any transaction type or message](/docs/raw-signing).
## Typed Message Signing
Allows you to [sign messages using specific standard formats](/docs/typed-message-signing-1) that prefix the message with a magic string. For ETH\_MESSAGE and EIP712 messages.
## Creating Vaults and Wallets
[Generate Fireblocks vault accounts and asset wallets](/docs/creating-vaults-and-wallets) at scale for account-based and UTXO asset wallet types using the Fireblocks API and SDKs.
## Whitelisting External Wallets
Use API calls and endpoints that [whitelist external wallet addresses](/docs/whitelisting-external-wallets) so that you can send transactions from wallet types using the Fireblocks API and SDKs.
## Gas Station Setup and Usage
[Auto-fuel a vault account to fund transaction fees](/docs/enabling-the-gas-station-1) with the base asset for EVM-based blockchains to automate and simplify your omnibus vault operations.
## Creating a Transaction
Use transaction API calls to [initiate any Fireblocks transaction operation](/reference/create-transactions), such as transfer, mint, burn, contract call, raw, and more.
## Monitoring Transaction Statuses
Set up automated webhook notifications to [monitor the progression of your transactions](/reference/monitoring-transaction-status) via transaction statuses and sub-status messages.
## Exchange Transfers
Use the `Create a new transaction` endpoint call to [manage external transfers to and from your linked exchange accounts](/docs/exchange-transfers).
# Developer Community
Want to learn more from Fireblocks knowledge experts and other developers? [Join our developer community today](https://community.fireblocks.com/)!
# Sign Typed Messages
Source: https://developers.fireblocks.com/docs/typed-message-signing-1
## What is Typed Message Signing?
Typed Message Signing is a crucial function in the blockchain ecosystem, designed to ensure security, transparency, and user trust when interacting with various blockchain applications.
Typed Message Signing refers to the process of creating and signing structured data that both machines and humans can understand and verify.
Unlike traditional message signing that deals with arbitrary data, Typed Message Signing structures the data according to predefined formats, making it readable and understandable before it is signed. This process ensures that the signer fully comprehends what they are agreeing to, thereby enhancing the security and clarity of blockchain transactions.
## What are the use cases for Typed Message Signing?
* **Proof of Ownership:** Users can sign messages to demonstrate ownership of a particular blockchain address or asset without making any on-chain transaction, crucial for identity verification processes.
* **Proof of Reserves:** Financial institutions can use typed message signing to prove possession of sufficient funds or assets transparently, enhancing trust among users or regulators.
* **Compliance with Regulations:** In scenarios like the Travel Rule and [TRUST Platform](https://www.coinbase.com/blog/introducing-the-travel-rule-universal-solution-technology-trust) in the cryptocurrency space, businesses must share certain transaction details with regulatory bodies. Typed message signing ensures that this information is exchanged securely and verifiably.
* **Smart Contracts and Legal Agreements:** In complex agreements or smart contracts, typed message signing can be used to confirm terms, conditions, and any other contractual obligations clearly and securely.
* **Meta-Transactions:** Typed message signing enables meta-transactions, where users sign transactions that someone else submits to the network. This is particularly useful in dApps that aim to reduce the gas cost burden on users.
* **Authentication:** Users can sign a typed message to prove ownership of a blockchain address without making a transaction. This method can be used for logging into decentralized applications (dApps) securely.
## How does Typed Message Signing work?
* **Data Structuring:** Initially, the data to be signed is structured into a predefined format. This structure includes defining types, fields, and the order in which the fields appear. This data format is often defined in a smart contract or a protocol specification.
* **User Confirmation:** Before signing, the structured data is presented to the user in a human-readable form. This step is vital as it allows the user to verify the details of the data they are about to sign, ensuring transparency and informed consent.
* **Signing:** The user signs the data with their private key. This signature process involves cryptographic algorithms that securely associate the signer's identity with the data they approved.
* **Verification:** The signature can then be verified by anyone who has access to the signer’s public key, confirming that the specific data was signed by the owner of the private key and that it has not been tampered with since signing.
## Typed Message Signing in Fireblocks
### How to enable Typed Message Signing
To sign a Typed Message, [create a Typed Message Policy rule](https://support.fireblocks.io/hc/en-us/articles/19158869149596-Policies-for-EVM-DeFi-operations#h_01JQ1MDMDGZY9C831P67762GCQ).
### Supported assets and methods
Typed message signing in Fireblocks is supported for several assets and can be implemented through various methods:
**Supported Assets:**
* [EVM-based blockchains (EIP191 & EIP712)](/reference/sign-typed-messages-for-ethereum-and-evm-networks)
* [Bitcoin](/reference/signing-typed-messages-in-bitcoin)
* [Tron (TIP191)](/reference/signing-typed-messages-in-tron)
**Creation Methods for Typed Message Signing Requests:**
* By decentralized applications (dApps) using the [Fireblocks Browser Extension](https://support.fireblocks.io/hc/en-us/articles/5403962226332-Connecting-to-Web3-using-the-Fireblocks-Chrome-Extension) or [Wallet Connect integration](https://support.fireblocks.io/hc/en-us/articles/5403817784732-Connecting-to-Web3-using-WalletConnect)
* Through the Fireblocks API, using the [Create Transaction](/reference/createtransaction) API call
### Via the Browser Extension or Wallet Connect
Typed Message Signing requests are created by Decentralized Applications (dApps) when connected via Fireblocks Browser Extension or Wallet Connect integration, for various purposes such as (but not limited to):
* **Session Authentication:** Similar to traditional web applications, dApps can use message signing to manage sessions. Once a user signs a message to prove ownership of an address, the dApp can create a session for the user without requiring them to sign in through traditional methods like username and password
* **Proving Ownership:** dApps often need to verify that a user controls a specific blockchain address. Typed message signing enables users to prove ownership without having to conduct a transaction, which can save on transaction fees
* **Meta-transactions:** Users can sign transactions that are paid for and submitted by another party (like a dApp). This can be used to improve user experience by allowing users to interact with the blockchain without needing to spend Ether for gas
### Via the Fireblocks API
Typed Message Signing requests can also be initiated through the API by using the Create Transaction API. These requests are typically generated for scenarios such as (but not limited to):
* **Proof of Ownership:** Users can sign messages to demonstrate ownership of a particular blockchain address or asset without making any on-chain transaction, crucial for identity verification processes
* **Compliance with Regulations:** In scenarios like the Travel Rule and [TRUST Platform](https://www.coinbase.com/blog/introducing-the-travel-rule-universal-solution-technology-trust) in the cryptocurrency space, businesses must share certain transaction details and regulatory bodies. Typed message signing ensures that this information is exchanged securely and verifiably
* **Proof of Reserves:** Financial institutions can use typed message signing to prove possession of sufficient funds or assets transparently, enhancing trust among users or regulators
### Learn more on Typed Message Signing via API in the following [guide](/reference/typed-message-signing-2)!
# Explore Use Cases
Source: https://developers.fireblocks.com/docs/use-cases
# What can you build with Fireblocks?
Virtually anything! Fireblocks supports a range of use cases, from centralizing treasury management to building a fintech application. Here are some of the use cases we support:
* NFT Marketplaces and Platforms
* Treasury Management
* Digital Asset Custody
* CeFi and DeFi Trading
* Cross Border Payments
* Web3 Gaming
* Tokenization
* Staking
* Smart Contract Security and Management
* Wallets for Retail Applications
# What types of businesses are built on Fireblocks?
Fireblocks enables your business to access the digital asset ecosystem quickly and securely. From Web3 to financial services, almost every type of business is building on Fireblocks.
| Industry | Type |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Financial Institutions | Banks, Hedge Funds, Asset Managers, Lending Desks, OTC Desks, Prime Brokers, Market Makers, Family Offices |
| Web3 Companies | NFT Marketplaces, DAOs, DeFi Protocols, GameFi, Web3 Infrastructure Providers, Protocol Foundations, and B2B Web3 Services |
| Retail Services | Exchanges, Corporates, Fintechs, Neobanks, Challenger Banks, Investment Platforms |
| B2B Services | Payment Service Providers, Banking-as-a-Service Providers |
# Fireblocks Feature Landscape
* [Wallet-as-a-Service](/docs/wallet-as-a-service)
* [Self-Custody Infrastructure](/docs/self-custody-infrastructure)
* [Tokenization](/docs/tokenization)
* [Treasury Management](/docs/treasury-management)
# Use API Co-signers for Signing and Approval Automation
Source: https://developers.fireblocks.com/docs/use-cosigners-for-signing-automation
## Overview
The API Co-signer automates transaction signing and workspace configuration approvals, complementing the default manual process performed via a mobile device using the Fireblocks mobile application. It is ideal for workspaces with high transaction volumes or frequent activity.
The Co-signer is a component installed and hosted in your environment on a machine with enclave support. Enclaves create a secure runtime environment that isolates and protects data and code, even from privileged users. This trusted execution environment safeguards sensitive processes from unauthorized access and tampering.
## Available API Co-signer types
Fireblocks offers multiple deployment options for API Co-signers. These options are available in cloud environments and on-premises, provided the region supports the required enclave technology. Each deployment utilizes enclave technologies to protect your MPC key shares. This allows you to choose a solution that fits your production environment.
API Co-signers are supported on Intel SGX, AWS Nitro, and Google Cloud Confidential Spaces enclaves. Deployments can be made on popular cloud platforms like Azure, AWS, Google Cloud, IBM Cloud, and Alibaba Cloud. On-premises deployments are also supported using Intel SGX-capable servers.
For detailed step-by-step installation guides for each Co-signer type, refer to the articles below:
* [Installing an SGX API Co-signer in Azure](/reference/install-api-cosigner-azure)
* [Installing an SGX API Co-signer via Azure Marketplace](/reference/install-api-cosigner-azure-marketplace)
* [Installing an SGX API Co-signer in IBM Cloud](/reference/install-api-cosigner-ibm)
* [Installing an SGX API Co-signer in Alibaba Cloud](/reference/install-api-cosigner-alibaba)
* [Installing an SGX API Co-signer on-prem](/reference/install-api-cosigner-onprem)
* [Installing a Nitro API Co-signer in AWS](/reference/install-api-cosigner-aws)
* [Installing a Confidential Space API Co-signer in Google Cloud](/reference/install-api-cosigner-gcp)
## Additional resources
Use the articles below to learn more about the Co-signer's architecture and configuration:
* [API Co-signers Architecture Overview](/docs/cosigner-architecture-overview)
* [Intel SGX Co-signer Architecture](/docs/intel-sgx-api-co-signer)
* [AWS Nitro Co-signer Architecture](/docs/aws-nitro-api-co-signer)
* [Google Cloud Confidential Space API Co-signer Architecture](/docs/gcp-confidential-space-api-co-signer)
* [Set up an API Co-signer Callback Handler](/docs/create-api-co-signer-callback-handler)
* [API Co-signer Security Checklist and Recommended Defense and Monitoring Systems](/docs/co-signer-security-checklist-defense-monitoring)
* [Configuring Multiple API Co-Signers in High Availability](/docs/multiple-cosigners-high-availability)
# Validate Balances
Source: https://developers.fireblocks.com/docs/validate-balances
Fireblocks customers can create automated mechanisms to notify their organization about incoming transactions using the following methods:
* Webhook notifications
* Pulling the transaction history log using the Fireblocks API
When monitoring notifications through these methods, only consider incoming transactions for reconciliation after receiving a notification that the transaction’s status has been updated to `COMPLETED` and the `VAULT_BALANCE_UPDATE` webhook has been received.
Fireblocks provides additional information to help clients validate and reconcile their balances according to the blockchain state. This information includes:
* The [`TRANSACTION_STATUS_UPDATED`](/reference/transaction-webhooks#transaction-status-updated) webhook event contains the `blockInfo` object, which includes:
* `blockHeight`: The block height where the transaction was included
* `blockHash`: The block hash where the transaction was included
* The `VAULT_BALANCE_UPDATE` webhook event and the `GET /vault/accounts/{vaultAccountId}/{assetId}` endpoint both include `blockHeight` and `blockHash` properties.
* For UTXO-based assets (e.g., BTC, LTC, BCH, DOGE), `blockHash` is not currently populated in `VAULT_BALANCE_UPDATE` responses. Only `blockHeight` is available. To retrieve `blockHash` for UTXO-based transactions, use `blockInfo.blockHash` from the `TRANSACTION_STATUS_UPDATED` webhook or the `GET /transactions/{txId}` endpoint.
* The [`GET /transactions/{txId}`](/reference/gettransaction) endpoint returns the transaction by its Fireblocks ID and includes the `blockInfo` object with the `blockHeight` and `blockHash` properties
Before crediting the end-user, customers need to run a reconciliation process to ensure that the incoming balance is accurately reflected and up to date according to the same `blockHeight` provided in the transaction notification object. If the balance is not up to date with the network state and the same height value, customers should not credit their clients until the issue is inspected and resolved.
Fireblocks strongly recommends checking the wallet’s balance using the Fireblocks API to verify that the deposit is included and the balance is up to date. This is crucial to prevent potential loss of funds from crediting end-clients before the balance is truly updated. While Fireblocks takes extensive measures to ensure the accuracy and reliability of its services, it is important for customers to implement all necessary validations and follow best practices to avoid any potential issues.
Below is a sequence diagram for additional reference:
# Estimate Transaction Fees
Source: https://developers.fireblocks.com/docs/verify-fee-effeciency
Fireblocks provides clients with two API endpoints to estimate transaction fees:
1. **Estimate Transaction Fee** - [Documentation](/reference/estimatetransactionfee)
2. **Estimate Network Fee** - [Documentation](/reference/estimatenetworkfee)
# Estimate Transaction Fee
The [`Estimate Transaction Fee` endpoint](/reference/estimatetransactionfee) is designed to simulate a real transaction and calculate its potential fee. This process considers factors such as the source and destination amounts, the number of inputs and outputs, and other relevant transaction details. Essentially, it mimics the actual transaction to determine what the fee would be if executed.
When using this endpoint, clients should be aware that it follows the same rules as creating a transaction. This includes requiring the relevant vault wallet in the vault account, ensuring the estimated transaction's balance is in the wallet, and providing a valid destination.
While many clients implement logic to estimate the transaction fee before each execution, it is crucial not to call this endpoint for every minor transaction change. For example, in EVM-based transactions, the gas limit for transferring the base asset or a specific token usually remains the same (barring sudden surges in network fees). The main variable is the current network fee, which can be obtained using the second endpoint.
# Estimate Network Fee
The [`Estimate Network Fee` endpoint](/reference/estimatenetworkfee) returns the current network fee for a specified network. This allows clients to calculate transaction fees or display the current network fee to their users. For instance, it provides the current gas price for ETH, which is part of the entire transaction fee formula, alongside the gas limit and other parameters.
The network fee response is cached for 30 seconds on the Fireblocks side. Clients should consider this interval when using this endpoint, as querying it more frequently than every 30 seconds does not provide additional value and the fee level value would remain the same.
# Fee Levels
Both endpoints return estimated fees or network fees in three levels: LOW, MEDIUM, and HIGH. Here’s how these are determined for different transaction types:
## EVM-Based Transactions
To simplify the gas calculation for each transaction, Fireblocks offers preset fees for both the Console (slow, medium, and fast) and the API (low, medium, and high). These fee calculations are based on recent blocks and a certain percentile of the data collected.
Fireblocks retrieves the latest block data every minute, inspecting the gas prices of recent blocks to determine the fee rate and automatically set the gas limit. In addition to verifying the latest data, Fireblocks also simulates the desired transactions to estimate the fee. The transaction parameters are sent to an API endpoint on the node, which returns an estimated transaction fee.
## UTXO-Based Transactions
* **High**: Fees are based on the previous block’s fee.
* **Medium**: Fees are based on the average of the previous two blocks.
* **Low**: Fees are based on the average of the last four blocks.
Fireblocks' API endpoints for estimating transaction fees provide clients with robust tools to ensure they can accurately predict and manage transaction costs. By using these endpoints, clients can maintain efficient and cost-effective operations while offering transparency and predictability in transaction fees to their users. Whether you are dealing with EVM-based, UTXO-based transactions or any other type of blockchain, understanding and utilizing these endpoints can significantly enhance your transaction management strategy.
# Best Practices
## Calling the Fee Estimation Endpoint
In some workflows, customers call the fee estimation endpoint for every transaction. However, this is not required for chains with relatively constant per-transaction fees, where fees depend mainly on network congestion and number of operations. In such cases, you can explicitly state the network fee instead (for example, on Stellar).
In these flows, the network fee can be cached for several seconds, accounting for differences between chains.
**Fee Estimation Accuracy**
Fee estimation endpoints return the estimated fee at the time of the call. The actual fee may change when the transaction is created due to factors such as network congestion or different UTXO selection caused by newer deposits.
# Learn more about Fees
1. [EVM Networks](https://support.fireblocks.io/hc/en-us/articles/10615179965596-EVM-fees-Overview)
2. [UTXO Based Assets](https://support.fireblocks.io/hc/en-us/articles/10616193193756-UTXO-fees-Overview)
3. [Unique Calculations](https://support.fireblocks.io/hc/en-us/articles/13995244288412-Solana-priority-fee)
### Check out the [Fee Management Developer Guide](/reference/estimate-transaction-fee)
# Wallet-as-a-Service
Source: https://developers.fireblocks.com/docs/wallet-as-a-service
Easily build and integrate custom, secure wallets into your application with Fireblocks' Wallet-as-a-Service API
# What is Wallet-as-a-Service?
Fireblocks Wallet-as-a-Service (WaaS) is an API-based solution that includes the most secure MPC wallets by design. Our APIs generate ECDSA and EdDSA signatures to sign any transaction. It enables anyone to create, manage, and secure wallets for any number of users without performing the security work themselves.
[Start developing on Fireblocks today](https://www.fireblocks.com/developer-sandbox-sign-up/?gl=1*19mlzew*_ga*MTY4ODc5Mjc3Ni\[%E2%80%A6]_ga_D39L1D2ZX2*MTY4Nzg2MTQwOS4xNi4xLjE2ODc4Njc3OTMuMjcuMC4w).
# Manage your digital assets with Fireblocks WaaS
You can easily plug and play Fireblocks Wallet-as-a-Service into your app — allowing your users to own and store digital assets — or facilitate your users to buy, sell, and trade cryptocurrencies, all with our self-custody solutions:
* **Scale without sacrificing security:** With our secure MPC wallets, you can create, manage, and secure deposits for any number of end-users in a compliant and reliable manner.
* **Supports businesses of all sizes:** Our WaaS product is compatible with various industries, including retail service, web3 companies, financial services and banking, exchanges, and financial market infrastructures.
* **Native support for 40+ blockchains:** Store your assets on the blockchain of your choice. And even if we don't support your blockchain, we offer raw signing so you can securely manage assets.
* **Monitor statuses of your transactions:** Using our tools like transaction status API, webhooks, and transaction history, you can stay up-to-date on the progress of your transactions and take action as needed.
* **Policy Engine:** Protect your custody from internal collusion, human error, and external attacks.
With the Fireblocks API, you can manage your workspace, automate your transaction flow, or use webhooks to receive push notifications on what's happening in your workspace. And in addition to the APIs, our Console can help monitor transactions and audits securely and reliably.
Learn more about [Fireblocks Wallet-as-a-Service](https://www.fireblocks.com/platforms/mpc-wallet/).
# Guides
## Deploying an NFT collection
Create an NFT collection using the ERC-721 standard and [deploy it with Fireblocks Hardhat Plugin](/reference/deploy-an-nft-collection).
## Creating Vaults and Wallets
[Generate Fireblocks vault accounts and asset wallets](/docs/creating-vaults-and-wallets) at scale for both account-based and UTXO asset wallet types using the Fireblocks API and SDKs.
## Minting an NFT
[Mint and verify Non-Fungible Tokens (NFT)](/reference/mint-an-nft) for your NFT collection using the Fireblocks Hardhat Plugin or Web3 Provider.
## Raw Message Signing
Support more chains and actions. Generate ECDSA and EdDSA signatures to [sign any transaction type or message](/docs/raw-signing).
## Typed Message Signing
Allows you to [sign messages using specific standard formats](/docs/typed-message-signing-1) that prefix the message with a magic string. For ETH\_MESSAGE and EIP712 messages.
## Creating a Transaction
Use transaction API calls to [initiate any Fireblocks transaction operation type](/reference/create-transactions), such as transfer, mint, burn, contract call, RAW, and more.
# Developer Community
Want to learn more from Fireblocks knowledge experts and other developers? [Join our developer community today](https://community.fireblocks.com/)!
# Wallet Link
Source: https://developers.fireblocks.com/docs/web3-wallet-link
# About the Fireblocks Wallet Link
As the demand for Web3 accessibility and usage grows, more users want to use dApps directly to manage their NFTs, get rewards, and more. The Fireblocks Wallet Link allows your users to connect their Fireblocks wallet addresses directly to Web3 applications (dApps), without your users needing to use their own wallet or any other application. This enables you to offer your users one-stop shopping for anything related to crypto and Web3.
# Creating a Wallet Link connection
The Wallet Link currently supports [WalletConnect](https://walletconnect.com/) connections. WalletConnect is a well-established standard for connecting wallets and Web3 applications and is supported by all of the leading dApps today.
When a user wants to connect to a dApp, they scan a QR code provided by WalletConnect inside the dApp. This QR code contains a URI that represents the connection session to be established between the dApp and the wallet. Passing this URI onto Fireblocks using the API allows the connection to be successful.
To initiate a new connection, pass the URI as follows.
```typescript TypeScript theme={"system"}
const examplePayload = {
feeLevel: "MEDIUM",
vaultAccountId: 0,
uri: "wc:f61647f4-7f98-4cb7-95d2-1db8e58fb0bb@1?bridge=https%3A%2F%2Fv.bridge.walletconnect.org&key=d145d64bda22f2be8fb23c251116b0cd8e3613f6971d193ff89b24e6735aaa6c" // The WalletConnect QR code
}
const connectionResponse: CreateWeb3ConnectionResponse = await fireblocks.createWeb3Connection("WalletConnect", payload);
```
### For Web3 connections from a Non Custodial Wallet, please use the payload below:
JavaScript
```javascript theme={"system"}
const examplePayload = {
feeLevel: "MEDIUM",
ncwId: "b8337f1d-bd61-4d6c-afc1-4c9d60aa2132",
ncwAccountId: 0, // or any other account in the NCW
uri: "wc:f61647f4-7f98-4cb7-95d2-1db8e58fb0bb@1?bridge=https%3A%2F%2Fv.bridge.walletconnect.org&key=d145d64bda22f2be8fb23c251116b0cd8e3613f6971d193ff89b24e6735aaa6c" // The WalletConnect QR code
}
```
The response from Fireblocks includes the relevant data about the connection, such as connection ID, dApp URL, and so on.
```typescript TypeScript theme={"system"}
connectionResponse === {
id: "f3ca1e41-378e-4718-b8d3-51dddb3777d3",
sessionMetadata: { // Provided by the dApp
"appUrl": "https://www.someDapp.com",
"appName": "SomeDapp",
"appDescription": "SomeDapp is the best example dapp",
"appIcon": "https://static.fireblocks.io/prod/wcs/dappIcon/abc123"
}
}
```
# Approving a Web3 connection request
You can approve or reject the Web3 connection request based on the data in the connection response.
```typescript TypeScript theme={"system"}
const approve = true;
const result = await fireblocks.submitWeb3Connection("WalletConnect", connectionResponse.id, approve);
```
### Note
If you want to limit your users to only some dApps, simply reject connection requests from any unapproved dApp.
# Listing connections
To list all your existing Web3 connections, run the following command:
```typescript TypeScript theme={"system"}
const examplePayload = {
pageCursor: "SomePageCursor" // undefined for first page,
pageSize: 10,
filter: {
vaultAccountId: 0,
connectionMethod: "API"
},
sort: "createdAt",
order: "DESC"
}
const response = await fireblocks.getWeb3Connections(examplePayload);
response.paging === { next: "NextPageCursor" }
const exampleSession: Session = response.data[0];
exampleSession === {
id: "f3ca1e41-378e-4718-b8d3-51dddb3777d3",
userId: "abc-123-456-def",
vaultAccountId: 0,
chainIds: ["ETH"],
feeLevel: "MEDIUM",
creationDate: "2023-03-08T11:20:13.823Z",
connectionType: "WalletConnect",
connectionMethod:"API",
sessionMetadata: {
"appUrl": "https://www.someDapp.com",
"appName": "SomeDapp",
"appDescription": "SomeDapp is the best example dapp",
"appIcon": "https://static.fireblocks.io/prod/wcs/dappIcon/abc123"
}
}
```
# Removing a connection
To remove a connection, run the following command:
```typescript TypeScript theme={"system"}
const result = await fireblocks.removeWeb3Connection("WalletConnect", exampleSession.id);
```
# Signing a dApp-originated transaction
Once connected to a dApp, the user can perform an action that will result in a signing operation by Fireblocks. This operation is created by the API user that created the Web3 connection and is subject to the [Policies](https://support.fireblocks.io/hc/en-us/articles/4401998390546-TAP-for-DeFi-operations) like any other operation.
In most cases, a transaction created by a dApp translates into a Contract Call transaction in Fireblocks. Some other operations that require signing on an [off-chain message](https://support.fireblocks.io/hc/en-us/articles/4413379762450-Off-chain-message-signing) will result in a Typed message in Fireblocks, such as signing a registration message when logging into OpenSea.
Make sure to adjust your Policy rules accordingly. You can use the Policy as another layer of limitation by whitelisting the relevant contract addresses of any dApp you want to allow while preventing contract calls to any other contract to go through.
When working with an [API Co-Signer machine](https://support.fireblocks.io/hc/en-us/articles/12006018592156-API-Co-Signer-Overview), you can use the Callback Handler to let the user approve the transaction on their device before it is signed and broadcasted.
# What Is Fireblocks?
Source: https://developers.fireblocks.com/docs/what-is-fireblocks
Fireblocks is a user-friendly platform that uses direct custody to build new blockchain-based products and manage your digital asset operations. Direct custody is a type of self-custody that seamlessly blends high performance, zero counterparty risk, and multiple layers of security. With Fireblocks, you're always the owner and controller of your assets.
The Fireblocks direct custody model follows five core Custody & Risk Principles:
1. Provide an environment with zero counterparty risk.
2. Eliminate external and internal attack vectors.
3. Guarantee business continuity.
4. Ensure granular control and visibility of every transaction.
5. Deliver high-performance products and services with ease of use.
[Learn more about Fireblocks’ Custody & Risk Principles.](https://www.fireblocks.com/principles/)
The Fireblocks platform is comprised of three core components:
### Digital Asset Wallets
Secure, and scalable MPC-based wallets with robust key management to custody digital assets. The Fireblocks MPC-CMP protocol redefines private key security, never gathering a private key as one whole, eliminating risk. Fireblocks customers use our wallets for a range of operations, such as treasury, trading, cold storage, royalties, NFTs, smart contracts, and user wallets.
### Platform Governance
The Policy Engine automates governance policies for transaction rules and admin approvals. It enables you to configure a list of rules that dictate how transactions are handled and approved. A rule can set whether a transaction is blocked, approved, or requires additional signers using filters.
Policy Engine rules for various destinations, such as internal wallets, network connections, exchanges, fiat providers, whitelisted addresses, and contract wallets.
### Treasury Management
Fireblocks' single platform centralizes wallet and address management to simplify crypto and NFT treasury operations. Wallets are organized into Vault accounts (segregated or omnibus) where you can set specific transaction policies to protect the movement of funds.
The Fireblocks Network ensures transfers from Fireblocks wallets are simple and secure. The Network automatically authenticates deposit addresses to avoid manual deposit address entry and the need for test transfers.
Over 30 exchanges and fiat providers are connected to the Fireblocks Network, enabling you to securely deposit and withdraw from their exchange accounts. Thousands of businesses are also connected to the Fireblocks Network for secure peer-to-peer transfers.
# Fireblocks Multi-layer Security
Fireblocks has created a multi-layer security matrix that layers MPC, secure enclaves, our signature Policy Engine, and an asset transfer network to provide the strongest software and hardware defense available against evolving attack vectors.
Because we understand that no security technology alone is unbreakable, our approach to security protects all attack surfaces in a redundant structure to provide multiple fail-safes, in the event one security control fails.
Our security structure provides a truly secure environment for storing, transferring, and issuing digital assets. This ensures that your assets are protected from cyberattacks, internal colluders, and human errors. As a result, Fireblocks serves as the foundation for 1,000s of digital asset businesses and has securely transferred over \$3T in digital assets.
## Multi-Layer Security In-Depth
### Layer 1: MPC-CMP
MPC (multi-party computation) is a cryptographic technology that stores secret information with each party, then solves a problem that requires the unshared, decentralized input of all these parties' secret information. Fireblocks uses MPC over other technologies such as Multisig because MPC is protocol agnostic, operationally flexible, and less costly as signing occurs off-chain.
Fireblocks developed the MPC-CMP protocol that applies this concept to blockchain-based ECDSA and EdDSA signatures (used by all blockchains). The Fireblocks MPC-CMP protocol redefines private key security, never gathering a private key as one whole. MPC-CMP also requires fewer transaction rounds for signing (8x faster than standard MPC) and is available with cold storage signing where key shares are stored offline.
Fireblocks distributes the cryptographic MPC shares across multiple tier-1 cloud environments to ensure an extra layer of security even if one of the physical data centers is compromised. You can also store MPC shares across on-prem data centers or configure a hybrid scenario.
### Layer 2: Secure Enclaves
Fireblocks utilizes Intel SGX, a hardware-level enclave that isolates selected code and data within a system. It is designed to protect the cryptographic material, the cryptographic algorithm (MPC and ZKPs), and the execution of sensitive parts of the software from both insiders (such as rogue admins) and hackers.
As the MPC key shares are stored in SGX, they cannot be extracted even if malware or a hacker has control over the server’s OS – as the memory space and the data in the SGX enclave are encrypted. We also utilize SGX to secure API keys. In the trusted execution environments (TEEs) where we store these exchange credentials, the information cannot be retrieved by hackers, inside colluders, or even Fireblocks employees.
### Layer 3: Policy Engine
Fireblocks’ Policy Engine allows you to configure a list of rules that affect how transactions are handled and approved. A rule can set whether a transaction is blocked, approved, or requires additional signers using filters such as source, destination, asset, and amount.
Fireblocks secures the Policy Engine itself using SGX and distributes policy verification across several MPC servers. Policy rules are signed by a quorum of admins and encrypted within SGX; the engine is implemented inside of the SGX enclave and the code cannot be modified. This prevents both hackers and even insiders from modifying the implemented rules or the logic of the policy engine.
### Layer 4: Fireblocks Network
The Fireblocks Network is an institutional asset transfer network that completely mitigates the risks associated with deposit addresses by automating deposit address authentication and rotation. The Fireblocks Network entirely removes the need to copy and paste deposit addresses, then authenticate them using test transfers and whitelisting procedures.
Without an authentication network, it’s possible for assets to be lost through deposit address spoofing or human errors (such as entering a deposit address for a counterparty that they’ve already rotated out).
## Additional Security Measures
### Admin Quorum
The Admin Quorum defines the minimum number of administrators required to approve connections and workspace changes. This includes whitelisting addresses, approving network connections, exchange accounts, external destination addresses, approving new users, and approving other workspace configuration changes. The admin quorum prevents insider attacks, such as an administrator trying to whitelist their personal wallet address to steal funds.
### Multi-factor Authentication
Two-factor authentication is required at a minimum for all Fireblocks users. Any authenticator app may be used such as apps from Google, Microsoft, LastPass, or Yubico.
### Logging
All activity within the Fireblocks workspace, including administrative changes, and transactions are securely logged for auditing purposes. These logs can be viewed natively within the Fireblocks console, or exported to any log aggregation system, such as a SIEM.
# Overview
Source: https://developers.fireblocks.com/docs/whitelist-addresses
# Overview
To improve the security of transactions from your workspace, we recommend whitelisting destination addresses.
Whitelisting addresses is a general security best practice that helps prevent potential loss of funds. It protects against issues such as malicious address manipulation or human error, like copying and pasting the wrong address and inadvertently sending funds to an unintended recipient.
Each whitelisting request needs approval from the Admin Quorum before funds can be transferred to that address. If any admin rejects the request, the address will not be whitelisted. However, you can submit a new request to whitelist the same address, which can be approved by the Admin Quorum at any time.
In Fireblocks, there are three types of whitelisted address entities, each capable of holding different asset addresses:
* **External Wallets**
* **Internal Wallets**
* **Contracts**
### Best Practice
If you interact with a specific address multiple times, it should be added to the whitelisted addresses in your workspace.
### Default Behavior
By default, to send funds to an address outside of Fireblocks, the address must first be whitelisted. If you want to permit transactions to non-whitelisted addresses, you should enable the [One Time Address (OTA) feature](/docs/whitelist-addresses#work-with-one-time-addresses) in your workspace.
# Whitelisted Addresses Types
## External Wallets
External Wallets are entities that hold addresses external to your Fireblocks workspace and are not under your ownership. These addresses belong to your clients or counterparties. If you intend to whitelist an address that is not under your control, it should be added to the External Wallet entity. Note that External Wallet addresses do not display the on-chain balance of the whitelisted address.
## Internal Wallets
Internal Wallets are entities that hold addresses external to your Fireblocks workspace but are under your ownership. These addresses belong to your other wallets outside of Fireblocks. If you intend to whitelist a wallet address under your control that is outside of Fireblocks, it should be added to the Internal Wallet entity.
## Contracts
Contract Wallets are entities that hold whitelisted contract addresses. If you interact with smart contracts and want to restrict the approved list of contracts, you should whitelist the contract addresses under the Contract Wallet entity.
# Whitelisting at Scale
For businesses with a high volume of outgoing transactions in their fully automated workflows, whitelisting every external address can be cumbersome and disrupt the automation. To address this while maintaining high security standards, you can use one of the following approaches:
1. **API Key with Admin Permissions:** Create an API Key with admin permissions and set the required [approval group](https://support.fireblocks.io/hc/en-us/articles/11500062124188-Approval-groups) for the whitelisting operation to **1**.\
Pair the API Key with an API Cosigner and create a Cosigner Callback Handler server on your end, connecting it to your Cosigner.\
In this setup, you can call the whitelisting address APIs before each transaction while the approval will be fully automated by the API Key acting as part of the admin quorum.\
Additionally, each request will be sent to your callback handler, allowing you to programmatically decide whether the address should be whitelisted.
2. **Fireblocks One Time Address Feature:** Utilize the Fireblocks One Time Address (OTA) feature to send funds to a non-whitelisted address. This can be done by combining the appropriate Policy rules and potentially implementing internal validations on your callback handler.
# Work with One Time Addresses
The One Time Address (OTA) feature lets you transfer assets to non-whitelisted addresses in your Fireblocks workspace.
Unlike whitelisted addresses, one-time addresses do not require approval by the Admin Quorum to transfer funds to them. However, enabling the OTA feature requires approval by the workspace Owner and the Admin Quorum.
You can enable the OTA feature [via the Fireblocks Console](https://support.fireblocks.io/hc/en-us/articles/4409104568338-One-Time-Address-OTA-feature) or the [Fireblocks API](/reference/setotastatus).
### This feature poses security risks!
We recommend [setting up a strict Policy](https://support.fireblocks.io/hc/en-us/articles/7361652234524-TAP-best-practices) before enabling it. You can set a variety of such Policy protective limitations, such as:
* Restricting one-time address transfers only to certain preselected users or groups
* Requiring approval for one-time address transfers above a certain threshold
# Whitelist IPs for API Keys
Source: https://developers.fireblocks.com/docs/whitelist-ips-for-api-keys
The IP allowlist (whitelist) enables you to restrict API calls to only accept specific IP addresses for each API key. Only allowing access to a select number of IP addresses can lower the chances of a security threat or malicious attack.
If you have workspace owner permissions, you can follow [these instructions](https://support.fireblocks.io/hc/en-us/articles/4405980040210-Whitelisting-API-IP-Addresses) on the Help Center to add IP addresses to the allowlist.
Alternatively, you can also submit a ticket to Fireblocks Support with the IP addresses of the machines running your API client(s) and their matching API key(s).
# Work with Fireblocks Gas Station
Source: https://developers.fireblocks.com/docs/work-with-gas-station
# Overview
Most Ethereum Virtual Machine (EVM)-based blockchains require a fee, called *gas*, to be paid in their base asset to execute transactions of both the base asset and other tokens. Gas is deducted from the account that initiated the transaction.
The Fireblocks Gas Station auto-fuels a vault account with the required base asset when it is enabled for them. Using the Gas Station helps cases of Fireblocks customers who choose to use the omnibus account vault structure or similar.
All transfers on Fireblocks, including those between vault accounts, occur on the blockchain. Therefore, you must pay gas fees when transferring funds from the deposit accounts to your omnibus vault account.
The auto-fuel transaction is triggered whenever a withdrawal or deposit is detected to or from that vault account. Fireblocks checks the balance of the vault and transfers gas according to the [Gas Station parameters](/docs/enabling-the-gas-station-1#gas-station-parameters).
The Gas Station removes the need to monitor your base asset levels and manually transfer funds to your vault accounts to cover future transaction fees when funds are swept to your central vault (omnibus) account, where they can be invested.
# Supported networks
Ethereum and all EVM-based networks available in your Fireblocks workspace are supported.
[See a complete list of Fireblocks Gas Station's supported networks with additional information](https://support.fireblocks.io/hc/en-us/articles/360016557960-Fireblocks-Gas-Station).
# Common use cases for Gas Station
Many retail businesses use the omnibus structure, making the Gas Station a helpful feature when many vault accounts are required to receive individual direct deposits from end clients.
1. In this case, you'd [monitor the Transaction status using webhooks](/reference/monitoring-transaction-status).
2. Then, upon receiving the `COMPLETED` transaction status, [trigger a sweep from the end-client vault account to your omnibus deposits vault account](/docs/sweep-funds).
Other business types using the Gas Station include exchanges, lending desks, neobanks, and commercial and investment banks.
# Workspace Comparison
Source: https://developers.fireblocks.com/docs/workspace-environments
# Overview
Fireblocks has three types of workspaces. The workspace type you use will determine your capabilities, so knowing which type you're working in is important.
* Developer Sandbox environments and Testnet workspaces are used for development and testing.
* Mainnet workspaces are used to deploy into production (with real funds).
Even though each workspace type has different capabilities, they all utilize similar APIs and SDKs, allowing you to develop and test your code against "lower" environments before deploying to your live production environment.
# Workspace Types
| | Developer Sandbox | Testnet | Mainnet |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Purpose** | The [Fireblocks Developer Sandbox](/docs/quickstart) is a unique workspace built for developers to quickly start using Fireblocks APIs and SDKs. | Recommended for API testing. Before you go live, we recommend performing a test transaction on the Mainnet using both the Console UI and the API. | This is a full-production workspace. |
| **Workflow testing** | Quick experimentation | Pre-production development & testing | Staging & production |
| **Console URL** | sandbox.fireblocks.io | console.fireblocks.io | console.fireblocks.io |
| **API URL** | sandbox-api.fireblocks.io | api.fireblocks.io/v1 | api.fireblocks.io/v1 |
| **Derivation paths** | [Sandbox workspace exceptions](https://support.fireblocks.io/hc/en-us/articles/16097541672732-Path-differences-between-Sandbox-Testnet-and-Mainnet-workspaces) | [Testnet workspace exceptions](https://support.fireblocks.io/hc/en-us/articles/16097541672732-Path-differences-between-Sandbox-Testnet-and-Mainnet-workspaces) | [Fireblocks vault HD derivation paths](https://support.fireblocks.io/hc/en-us/articles/360014330819-Fireblocks-Vault-HD-derivation-paths) |
| **Assets** | Testnet assets that are independent of Mainnet assets and operate on their own Testnet blockchains. | Testnet assets that are independent of Mainnet assets and operate on their own Testnet blockchains. | Mainnet / Real assets. |
| **API** | Full API access with the most limited rate limits. Used for testing the API. | Full API access with limited rate limits. Used for testing the API. | Full API access with increased rate limits. Used for implementing the tested API configuration. Requires a separate API key from a Testnet workspace; this can be done with the same CSR file. |
| **Policies** | Non-editable | [Fully editable](/docs/set-transaction-authorization-policy) | [Fully editable](/docs/set-transaction-authorization-policy) |
| **API Co-Signer** | Only [Fireblocks-provided API Co-Signer](/reference/use-communal-cosigner). | Fireblocks-provided or self-hosted API Co-Signer. | Self-hosted API Co-Signer. |
| **API user limit** | Up to 5 users | Limited to the client setting | Limited to the client setting |
| **Webhooks** | Available for testing | Available for testing | Available |
| **Mobile access** | N/A | Fireblocks mobile app (iOS and Android) to sign and authorize transactions, approve external connections, and workspace changes. | Fireblocks mobile app (iOS and Android) to sign and authorize transactions, approve external connections, and workspace changes. |
| **Fireblocks Network** | N/A | N/A | All Fireblocks Network connections are available. |
| **Exchanges** | Limited exchange integration support (only testnets). | Limited exchange integration support (only testnets). We recommend setting Policy rules that apply to transactions on exchanges to accommodate test transactions that are processed approximately once per day. | All Fireblocks exchange connectivity is available. |
| **Fiat** | Testnet only | Testnet only | All Fireblocks fiat integrations |
| **DeFi/Web3** | Testnet protocols with WalletConnect Desktop integration. | Testnet protocols with WalletConnect Mobile and Desktop integrations. | Full support. Requires a specific policy implementation to enable. |
| **AML** | N/A | N/A | Most assets are supported via Chainalysis or Elliptic. |
| **Raw Signing enabled** | Yes | Requires a signed commercial agreement + Support enablement | Requires a signed commercial agreement + Support enablement |
| **Support & Help Center** | [Developer Community support](https://community.fireblocks.com/) with Help Center access | Full Support with Help Center access | Full Support with Help Center access |
# Mainnet
Mainnet is a production-level blockchain network with cryptocurrency transactions being broadcast, verified, and recorded. Mainnets have a base asset that can be used as funds in transactions or to pay network fees. All assets on Mainnets have real-world monetary value.
A Mainnet workspace is a fully developed and deployed environment that allows you and your organization to conduct your real-world financial operations on the Fireblocks platform.
In Mainnet workspaces, you can securely:
* Transfer digital assets
* Add users
* Create a Vault account or multiple
* Whitelist new addresses
* Connect to supported exchanges
* Connect to other Fireblocks Network members
* Configure MPC-CMP devices
* Establish network connections
### Moving to Mainnet workspaces
When you’re ready to use your Mainnet workspace, there are a few things to keep in mind before you get started.
* When testing new functions in Mainnet (production) environments, use small amounts first to confirm intended functionality before upscaling to larger amounts.
* Other than the users you add to both, your Mainnet and testnet workspaces are completely different workspaces. Your Mainnet workspace will require its own vault accounts and asset wallets, exchange and fiat account connections, policies, users, and more.
* You must define the Mainnet workspace’s Policy rules to work in accordance with the Mainnet workspace’s various users, user groups, sources, destinations, and assets. These parameters will likely be different from what you used in your testnet workspace.
* You must configure your Mainnet workspace to work with any API integrations and third-party accounts you want to carry over from your testnet workspace. This includes creating a new API key for and provisioning your API Co-Signer. Note that you can add Fireblocks Console users, adjust the Admin Quorum, and connect to exchange accounts, fiat accounts, and Fireblocks Network members before or after you configure your API integrations.
# Testnet
Testnet is a blockchain test network used by developers to run tests with the blockchain. Testnets operate on blockchains separate from their associated Mainnet. Testnet assets have no monetary value, and many of them reset periodically.
A Testnet workspace is a testing-level environment that only allows you to use Testnet assets for integration and testing purposes. You can also perform many of the same actions you can in a Mainnet workspace without incurring real-world fees.
In the Fireblocks Console, the "**Testnet Environment**" badge appears at the top of the page to help you identify your Testnet workspace.
## Limitations of Testnet workspaces
The Testnet workspace will have certain conditions to protect you from losing real assets and compromising security while you test, such as:
* Only Testnet assets and Testnet blockchains are supported (e.g., Ethereum Sepolia Testnet)
* Simplified signing process that removes many security features in favor of simple setup and testing, such as no mobile signing application support and no client co-signer support
* Limited exchange integrations since not all exchanges support Testnet blockchains and may not work as they would on Mainnet
* Fiat integrations will only work on fiat test networks
* DeFi and Web3 have limited blockchain and Web3 dApp test network support
* The Fireblocks Network is not available
* Transaction screening AML/KYT integrations are not available
* Reduced API rate limits (production-level load testing is not available)
# Developer Sandbox
Sandbox workspaces are freely available to sign up for. These workspaces are geared towards quick development and experimentation. Here are some of the highlights of Sandbox environments:
* When creating API users, the CSR certificate required to generate the private key is automatically created in the browser.
* Access to the Developer Area API Monitoring feature that displays the workspace's API calls and errors over 24-hour and 7-day periods.
* No mobile signing devices are needed since all transactions are auto-approved, reducing the complexity of trying out the Fireblocks API.
## Differences in Sandbox User Roles
When creating new Console or API users in Developer Sandbox workspaces, there are only three workspace roles available:
* Non-Signing Admin
* Editor
* Viewer
In Sandbox workspaces, the Owner role is taken up by a backend service that manages auto-approvals to make experimentation and development easier. Therefore, the Non-Signing Admin replaces this role type and has the highest level of permissions, which are not present in Mainnet/Testnet workspaces, such as:
* Creating and deleting users
* Resetting 2FA for workspace users
* Signing transactions (despite the "non-signing" in the role's name)
For more information about workspace roles and permissions in production Mainnet and Testnet workspaces, [visit our Help Center](https://support.fireblocks.io/hc/en-us/articles/360012832959-User-roles).
# Supported Mainnets, Testnets, and Assets
Visit the [Supported blockchain networks](https://support.fireblocks.io/hc/en-us/articles/8993656344092-Supported-blockchain-networks) page in our Help Center to learn more about supported Mainnets, Testnets, and assets.
# Add Tokens
Source: https://developers.fireblocks.com/reference/add-your-tokens
Fireblocks allows clients to add tokens across various blockchains via the Fireblocks API. To register a new token, use the [Register a New Asset](/reference/registernewasset) endpoint with the appropriate parameters for the supported blockchain.
The blockchains supported for self-token addition via the API include:
* EVM-based chains
* Algorand
* NEAR
* Solana
* Stellar
* Sui
* TON
* TRON
The API requires a `POST` request with the following parameters:
* **blockchainId:** The unique network identifier (e.g., `ETH`).
* **address:** The asset address:
* **EVM-based chains:** Token contract address
* **Algorand (ALGO):** Asset ID
* **NEAR:** Token address
* **Solana:** Token's mint account address
* **Stellar (XLM):** Issuer address
* **Sui:** The token's type
* **TON:** Token address
* **TRON (TRX):** Token contract address
* **symbol:** Required for XLM tokens only
## Code example
Below is a code example for adding a new token to your workspace:
```javascript theme={"system"}
import { readFileSync } from 'fs';
import { Fireblocks, BasePath } from "@fireblocks/ts-sdk";
const FIREBLOCKS_API_SECRET_PATH = "";
// Initialize a Fireblocks API instance with local variables
const fireblocks = new Fireblocks({
apiKey: "",
basePath: BasePath.US,
secretKey: readFileSync(FIREBLOCKS_API_SECRET_PATH, "utf8"),
});
(async() => {
const addTokenRes = await fireblocks.blockchainsAssets.registerNewAsset({
registerNewAssetRequest: {
blockchainId: "ETH",
address: "0xdBA8e8021FE321af91FC3A08e223EF15908cB2bB"
}
})
console.log(JSON.stringify(addTokenRes, null, 2))
})();
```
In this example, we are adding the`0xdBA8e8021FE321af91FC3A08e223EF15908cB2bB` token (Smart Contract address) on the Ethereum network.
# Address Registry
Source: https://developers.fireblocks.com/reference/address-registry
# Overview
Address Registry lets you verify the legal entity controlling a blockchain address before sending or receiving a transaction. When enabled, Address Registry allows you to query blockchain addresses and receive certain legal entity information about the institution controlling the associated vault. The Address Registry is designed solely to facilitate counterparty discovery and verification in connection with digital asset transactions.
Address Registry is a free capability available to all Fireblocks customers and enabled by default. Coverage is currently limited to addresses within the Fireblocks network.
**Early access**
This feature is currently in Early Access (a Beta Service). To request access, enable it in [Settings > Labs](https://console.fireblocks.io/v2/settings/labs) or contact your Fireblocks Customer Success Manager. Early Access features are subject to the beta terms under [Product Specific Terms](https://www.fireblocks.com/product-specific-terms#beta-services).
## Look up an address
Query a blockchain address to retrieve the legal entity information associated with it.
### Request
```http theme={"system"}
GET /v1/address_registry/legal_entities/{address}
```
| Parameter | Type | Required? | Description |
| --------- | ------ | --------- | ---------------------------------- |
| `address` | string | Yes | The blockchain address to look up. |
### Response
If the address resolves to an opted-in Fireblocks customer:
```json theme={"system"}
{
"verified": true,
"entityName": "ACME Corporation",
"jurisdiction": "US",
"lei": "254900GC33RBE6FQA817",
"travelRuleProviders": [
"TRAVEL_RULE_PROVIDER_NOTABENE",
"TRAVEL_RULE_PROVIDER_SYGNA"
],
"email": "compliance@example.com"
}
```
| Field | Type | Description |
| --------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `verified` | boolean | `true` if entity data is sourced from an approved LEI and validated by Fireblocks. `false` if sourced from Fireblocks data without independent validation. |
| `entityName` | string | Legal entity name associated with the vault controlling the address. |
| `jurisdiction` | string | ISO country code of the legal entity. |
| `lei` | string | Legal Entity Identifier (LEI) of the counterparty, if available. |
| `travelRuleProviders` | array | Travel Rule providers the counterparty supports, if declared. |
| `email` | string | Counterparty's Travel Rule contact email, if declared. |
If the address is not found — because the counterparty is not a Fireblocks customer, has opted out, or is on an unsupported environment — the response returns HTTP 404:
```json theme={"system"}
{
"code": "2142",
"message": "Address could not be resolved"
}
```
**Notes about the Address Registry lookup**
* A `not_found` result does not indicate that the address is unhosted, illicit, or non-compliant.
* The registry is designed to prevent bulk data extraction or misuse. We put in place various controls like query authentication, API rate limiting, daily request caps, and alerts to ensure the number of queries remains proportional to the number of transactions. See [the FAQ](https://support.fireblocks.io/hc/en-us/articles/26105830582940-Address-Registry#h_01KP5Z8EQMTNW36W3RSNQJV9C9) for more details.
## Register a legal entity
To appear as a verified entity when counterparties look up your addresses, register your Legal Entity Identifier (LEI) with Fireblocks. This step is optional if you only want to query addresses, but required to return verified data and to use Address Registry in compliance workflows.
Each workspace can register multiple legal entities.
### Request
```http theme={"system"}
POST /v1/legal_entities
```
```json theme={"system"}
{
"lei": "529900HNOAA1KXQJUQ27",
"travelRuleProviders": [
"MY_OWN"
],
"travelRuleContactEmail": "compliance@example.com"
}
```
| Parameter | Type | Required? | Description |
| ------------------------ | ------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lei` | string | Yes | A valid 20-character LEI present in the GLEIF registry. |
| `travelRuleProviders` | array | No | Travel Rule providers to associate with this entity. Enum: `CODE`, `GTR`, `MY_OWN`, `NOTABENE`, `SYGNA`, `SUMSUB`, `TRISA`, `TRUST`, `TWENTY_ONE_ANALYTICS`, `VERIFY_VASP`. |
| `travelRuleContactEmail` | string | No | Contact email for Travel Rule communications. |
### Response (success)
```json theme={"system"}
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"lei": "529900HNOAA1KXQJUQ27",
"status": "PENDING",
"isDefault": false,
"travelRuleProviders": [
"MY_OWN"
],
"travelRuleContactEmail": "compliance@example.com",
"gleifData": {
"lei": "529900HNOAA1KXQJUQ27",
"legalName": "Example Corporation Ltd.",
"otherNames": [
"ExCorp",
"Example Corp"
],
"legalAddressRegion": "NY",
"legalAddressCountry": "US",
"nextRenewalDate": "2025-12-31T00:00:00Z"
},
"createdAt": "1700000000000",
"updatedAt": "1700000000000"
}
```
### Error responses
| Code | Meaning |
| -------- | --------------------------------------------------------------------- |
| HTTP 400 | Invalid LEI or request parameters. |
| HTTP 404 | LEI not found in the GLEIF registry. |
| HTTP 409 | A legal entity with this LEI is already registered for the workspace. |
### LEI states
After you submit an LEI, it moves through the following states:
| State | Description |
| ---------- | -------------------------------------------------------------------------------------------------------------- |
| `Pending` | Submitted and under Fireblocks review. Your addresses appear as unverified to counterparties during this time. |
| `Approved` | Verified by Fireblocks. Queries against your addresses return your legal entity name, jurisdiction, and LEI. |
| `Denied` | Rejected by Fireblocks. You can view the reason and resubmit. |
| `Revoked` | Previously approved, then revoked due to an expired or invalid LEI. |
### Map vault accounts to legal entities
After Fireblocks approves your first LEI, all vault accounts map to that entity by default. If you register additional legal entities and want to map specific vault accounts to them, refer to the [legal entity endpoints in the API reference](https://docs.fireblocks.com/api/swagger-ui/#/Compliance/assignVaultsToLegalEntity). Each vault account supports a maximum of one legal entity.
## Opt out of Address Registry
You can opt out your entire workspace or individual vault accounts. When you opt out, lookups against your addresses return `not_found`. You can disable and re-enable at any time.
**Notes about opting out**
* Opting out prevents you from querying addresses or using compliance workflows that depend on Address Registry.
* Opting out disables all compliance workflows built on Address Registry. Re-enabling restores them.
### Opt out an entire workspace
```sql theme={"system"}
DELETE /v1/address_registry/tenant
```
No request body is required. A successful response returns a status of `OPTED_OUT` using the same JSON structure as the [GET participation status endpoint](https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getAddressRegistryTenantParticipationStatus).
### Opt out individual vault accounts
Add vault account IDs to the opt-out list:
```http theme={"system"}
POST /v1/address_registry/vaults
```
```json theme={"system"}
{
"vaultAccountIds": [
10001,
"10002"
]
}
```
| Parameter | Type | Required? | Description |
| ----------------- | ----- | --------- | -------------------------------------------------------------------------------- |
| `vaultAccountIds` | array | Yes | Vault account IDs to add to the opt-out list. Accepts both integers and strings. |
## Use Address Registry in compliance workflows
You can use Address Registry inside your transaction screening policy to automate compliance decisions based on counterparty identity. The workflow has two parts: define counterparty groups, then apply rules to those groups in a screening policy.
**Feature coming soon**
Compliance workflows are not yet available but will be added during the Early Access phase.
### Define counterparty groups
A *counterparty group* is a named set of counterparties that share specific attributes. You can create as many groups as you need. Jurisdiction is the only available grouping attribute initially. Additional attributes such as business type and license type are planned.
**API endpoints:**
```http theme={"system"}
POST /v1/counterparty-groups # Create a group
GET /v1/counterparty-groups # List all groups
PUT /v1/counterparty-groups/{id} # Update a group
DELETE /v1/counterparty-groups/{id} # Delete a group
```
### Set a screening policy
The screening policy consists of two parts:
* **Transaction screening policy**: Defines which transactions trigger a counterparty check. Build rules using source, destination, asset, and amount. Rules evaluate from top to bottom, and the first match wins. A catch-all default rule is required as the last entry. You also configure timeout behavior separately to define what happens if the registry check times out during a transaction (accept or reject).
* **Post-screening policy**: Defines the action to take based on the counterparty check result.
| Condition | Action |
| ------------------------------- | ---------------- |
| Counterparty is in \[Group] | Accept or Reject |
| Counterparty is not in \[Group] | Accept or Reject |
| Address not found in registry | Accept or Reject |
**API endpoints:**
```http theme={"system"}
PUT /v1/counterparty-groups/policy # Configure screening policy
GET /v1/counterparty-groups/policy # Get current policy
GET /v1/counterparty-groups/address # Get group context for an address
```
## Availability and limitations
Fireblocks does not currently support Address Registry for workspaces hosted on European or Swiss environments due to infrastructure isolation between production instances. We plan to add support for these environments shortly after the initial release. In the meantime, queries against addresses from European or Swiss-hosted workspaces return `not_found`.
Address Registry is not available in Developer Sandbox workspaces.
# Android SDK errors
Source: https://developers.fireblocks.com/reference/android-sdk-errors
| Error Code | Error Message | Description |
| ---------- | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 102 | Invalid Certificate | Invalid Certificate, it might be expired or the device clock is out of sync |
| 106 | Missing algorithms | Indicates that `com.fireblocks.sdk.Fireblocks.generateMPCKeys` was called with an empty set of algorithms. |
| 108 | Incomplete device setup | Indicates that our device setup is incomplete. For example if we generated a key but we didn't perform backup |
| 107 | Missing private keys | The client failed to load the keys' content provided by the `com.fireblocks.sdk.keys.FireblocksKeyStorage` implementation. This implementation is provided to `com.fireblocks.sdk.Fireblocks` via the initialization method. |
| 110 | Invalid physical device id | Indicates that we have an invalid physical device id. Please check if your device was recovered from a different physical device |
| 111 | Max devices per wallet reached | The maximum number of devices in a wallet is reached while trying to add a new device. |
| 200 | Timeout during key creation, didn't get startup message | During key creation, several messages from the backend are handled. The first message did not arrive in the expected amount of time. |
| 201 | Unknown algorithm | Indicates that `com.fireblocks.sdk.Fireblocks.generateMPCKeys` was called with an invalid algorithm. |
| 202 | Failed to generate key, key exists in server but not on the device | The metadata of the key was previously sent to the backend, but the key is no longer on the client. |
| 203 | Timeout during key creation | During key creation, several messages from the backend are handled. One of the second-to-last messages did not arrive in the expected amount of time. |
| 204 | Failed to send public key | The public key failed to back up with the backend after key creation. |
| 205 | Failed to request key | One or more of the key requests failed to initiate. |
| 206 | Failed to enroll player | The process to register the `deviceId` with the backend failed. |
| 207 | Failed to create key | During key creation, several messages from the backend are handled. One of the messages failed to process on the device. |
| 208 | Failed to confirm key | Used in `com.fireblocks.sdk.Fireblocks.generateMPCKeys` during key creation, a key was not fully confirmed in the backend |
| 300 | Failed to request end-user takeover | A failure to receive keys for takeover from the backend. |
| 301 | Failed to takeover keys | There was an error while processing the takeover request on all keys. |
| 302 | Timeout during key takeover | A failure to receive keys for takeover from the backend in the expected amount of time. |
| 400 | Failed to export keys | The client failed to export all the available keys. |
| 401 | Missing public keys | Some of the data needed to export the key is unavailable. |
| 402 | Missing public key | The client failed to load the keys provided by the `com.fireblocks.sdk.keys.FireblocksKeyStorage` implementation. This implementation is provided to `com.fireblocks.sdk.Fireblocks` via the initialization method. |
| 403 | Failed to derive asset key | Deriving the asset key failed. |
| 404 | Missing cloud private keys | The cloud key share is not the full key share. |
| 405 | Missing chain code | The relevant chain code is missing. |
| 406 | Missing private key | The client failed to load the keys provided by the `com.fireblocks.sdk.keys.FireblocksKeyStorage` implementation. This implementation is provided to `com.fireblocks.sdk.Fireblocks` via the initialization method. |
| 407 | Failed to export key, recovered PublicKey is not equal to the original PublicKey | The recovered key is not equal to the original key. |
| 408 | Failed to export key | The key export failed. The reason for failure may be located in the logs. |
| 500 | Failed to sign transaction, unknown txId | Indicates that `com.fireblocks.sdk.Fireblocks.signTransaction` was called with an invalid transaction ID. |
| 501 | Error during transaction signing creation, didn't get start signing message | During transaction signing, several messages from the backend are handled. The first message failed to arrive in the expected amount of time. |
| 502 | Failed to sign transaction | The message processing failed. |
| 503 | Timeout during transaction signing | During transaction signing, several messages from the backend are handled. One of the second-to-last messages failed to arrive in the expected amount of time. |
| 504 | Transaction signing was stopped | Used in `com.fireblocks.sdk.Fireblocks.signTransaction` Indicates that the transaction signing was stopped |
| 600 | Backup not available | There are no keys to recover from the backend. |
| 601 | Failed to recover keys | The key recovery process failed. |
| 603 | Wrong passphrase | The provided passphrase is wrong |
| 700 | Failed to get key IDs | The client failed to fetch the key's metadata from the backend. |
| 701 | Missing key IDs in server for backup | The client failed to fetch the key's metadata from the backend. |
| 702 | We have a discrepancy between valid key IDs between server and client | A discrepancy exists between the `keyId` parameters stored on the client and the backend. |
| 703 | Failed to backup keys, missing keys | The client failed to fetch the key's metadata from the backend. |
| 704 | Failed to backup key | The key backup process with the backend failed. |
| 705 | Invalid passphrase error | The used passphrase is invalid. |
| 800 | Invalid add device setup data | The request to add a device failed due to invalid data. |
| 900 | Failed to join wallet | The request to join an existing wallet failed. |
| 901 | Timeout during join wallet | The request to join an existing wallet timed out. |
| 902 | Join wallet was stopped | The request to join an existing wallet was stopped. |
| 1000 | Failed to approve join wallet | The request to approve a new device joining an existing wallet failed. |
| 1001 | Timeout during approve join wallet | The request to approve a new device joining an existing wallet timed out. |
| 1002 | No keys to provision | Indicates that `com.fireblocks.sdk.Fireblocks.approveJoinWalletRequest` was called with an empty set of algorithms. |
| 1003 | Approve join wallet was stopped | The request to approve a new device joining an existing wallet was stopped. |
# API Co-signer Deployment Options and Installation Flow
Source: https://developers.fireblocks.com/reference/api-cosigner-installation-flow
This article outlines the available deployment options and the process for setting up a Co-signer to enable automatic transaction signing and approval of workspace configuration changes.
## API Co-signer installation flow
After installing the Co-signer, configure the [Policy](https://support.fireblocks.io/hc/en-us/articles/7354983580316-About-the-TAP) to [designate the API user](https://support.fireblocks.io/hc/en-us/articles/7365877039004-Rule-parameters#h_01HGBN9QQ0T42NR8XT4Y96V7YH) paired with the Co-signer as the signer. This ensures that when a transaction meets the criteria defined in the policy, it will be automatically signed by the Co-signer that is paired to the specified API user.
### Step 1: Setup and configure your deployment environment
Setup and configure the resources needed for the Co-signer to function within your environment. Additionally, configure your network and security services to allow access to the domains required for the Co-signer's installation and operation.
### Step 2: Add a new Co-signer to the workspace using an API user
Using the Fireblocks Console or APIs, create an API user and use it to add a new Co-signer to the workspace.
### Step 3: Install and connect the Co-signer to the workspace
After preparing and configuring all necessary resources, download and run the installation script that matches your Co-signer type. Please select to deployment options below depending on which environment you have.
## API Co-signer deployment options
> **The environment setup and Co-signer installation process vary based on the chosen Co-signer type and deployment environment.**
>
> Click on the links below for detailed step-by-step setup and installation instructions
Install in Microsoft Azure
Install On-Premise
Install in Amazon Web Services
Install in Google Cloud
Install in Alibaba Cloud
Install in IBM Cloud
# API Co-signer Maintenance
Source: https://developers.fireblocks.com/reference/api-cosigner-maintenance
This article outlines the most common maintenance operations for Co-signers. Since each Co-signer type has a unique architecture and is installed in a specific environment, refer to the relevant article for detailed maintenance instructions for your Co-signer type.
> **Note**: Due to the enclave architecture of the Google Cloud Confidential Space Co-signer, maintenance operations can only be performed through Google Cloud's portal or using `gcloud`.
Co-signer maintenance include:
* View the logs
* Observe the status
* List the paired API users
* Retrieve the public key (used for the Callback Handler JWT authentication)
* Stop the Co-signer
* Restart the Co-signer
* Retrieve the running version
* Update the Co-signer
* Migrate to a new machine
* Configure a proxy server
* Configure the communication protocol
Use the [Co-signer management tab](https://support.fireblocks.io/hc/en-us/articles/17923671680540-The-Co-signer-management-tab) to observe the Co-signer's online / offline status and the list of paired API users and refer to the following guides to learn about platform-specific Co-signer maintenance:
\[
## AWS Nitro
AWS Nitro Co-signer maintenance]\(/reference/api-cosigner-maintenance-aws-nitro)
\[
## GCP Confidential Space
Google Cloud Confidential Space Co-signer maintenance]\(/reference/api-cosigner-maintenance-gcp-confspace)
\[
## Intel SGX
SGX-based Co-signer maintenance on Azure, On-Premise, IBM Cloud, or Alibaba Cloud]\(/reference/api-cosigner-maintenance-sgx)
# AWS Nitro API Co-signer Maintenance
Source: https://developers.fireblocks.com/reference/api-cosigner-maintenance-aws-nitro
> **Note:** You must have root privileges on the Co-signer machine to perform maintenance operations. Ensure you are logged in as a root user or use `sudo` to execute the commands.
## View the logs
You can export the logs to a file in the local directory, tagged with the current date and time, by running the following command:
```bash theme={"system"}
./fireblocks/cosigner logs
```
Append a number to the command to retrieve the specified most recent amount of lines.
The Co-signer's logs are saved on the EC2 instance in the following file location: `/var/log/customer_cosigner.log`
The log policy is as follows:
```xml theme={"system"}
``
``
``
```
***
## Observe the status
You can observe the Co-signer's status by running the following command from the EC2 instance:
```bash theme={"system"}
./fireblocks/cosigner get-status
```
It should return an output similar to the following:
```json theme={"system"}
[root@ip-x-x-x-x ~]# ./fireblocks/cosigner get-status
========= Cosigner Status =========
Enclave Name: cosigner
Enclave ID: i-0b11aeabc7d3bee3d-enc190641e6f0ce80a
Process ID: 377331
Enclave State: RUNNING
Service State: ACTIVE
===================================
Latest Service Messages:------------------------
Jun 29 13:10:41 ip-x-x-x-x.us-east-2.compute.internal start_service.sh[377329]:
Jun 29 13:10:41 ip-x-x-x-x.us-east-2.compute.internal start_service.sh[377329]:
1,
3
Jun 29 13:10:41 ip-x-x-x-x.us-east-2.compute.internal start_service.sh[377329]: ],
Jun 29 13:10:41 ip-x-x-x-x.us-east-2.compute.internal start_service.sh[377329]:
"MemoryMiB": 4096
Jun 29 13:10:41 ip-x-x-x-x.us-east-2.compute.internal start_service.sh[377329]: }
===================================
```
If you get anything other than `ACTIVE` in the "Service State" field, there’s a problem. Contact Fireblocks support and **attach the Co-signer’s logs so we can investigate**.
***
## List the paired API users
You can list all API users paired with the Co-signer across the connected workspaces by running the following command:
```bash theme={"system"}
./fireblocks/cosigner list-users
```
The output will display a list of all API users paired with your Co-Signer, including the workspace name they are connected to, the API user's ID (its API key), and the associated Callback Handler server URL (if applicable).
***
## Retrieve the public key
You can retrieve the Co-signer's public key, used by your optional Callback Handler server to authenticate requests from the Co-signer, by running the following command:
```bash theme={"system"}
./fireblocks/cosigner print-public-key
```
***
## Stop the Co-signer
You can stop the Co-signer by running the command:
```bash theme={"system"}
./fireblocks/cosigner stop
```
***
## Start the Co-Signer
You can Start the Co-signer by running the command:
```bash theme={"system"}
./fireblocks/cosigner start
```
***
## Restart the Co-Signer
You can restart the Co-signer by running the command:
```bash theme={"system"}
./fireblocks/cosigner restart
```
***
## Update the Co-signer
Retrieve the URL of the AWS Nitro installation package from the Console and use the `wget` command to download the package directly to the EC2 machine. Paste the appropriate URL into the following command:
```bash theme={"system"}
wget -O nitro-cosigner.tar.gz "URL"
```
> **Note:** If you have any issues with finding the installation package URL, please contact [Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new?ticket_form_id=360003372200\&tf_360023089139=global_settings\&tf_360023089159=get_api_co-signer_installation_script).
Unpack the installation package by running the following command:
```bash theme={"system"}
tar -xzf nitro-cosigner.tar.gz
```
Now stop the Co-signer run the following commands to stop the Co-signer service and update it by forcing a new installation, overwriting the existing one:
```bash theme={"system"}
systemctl stop cosigner
./install.sh --force
```
The script will prompt for the following parameters:
* Pairing token
* S3 bucket
* ARN of the CMK
Use the same settings that were used to install the existing running version. These settings can be found in the file `/opt/fireblocks/env.txt`, where they are labeled as follows:
* PAIRING\_TOKEN
* BUCKET\_NAME
* KEY\_ARN
It will take about a minute to reinstall, and then the Co-signer will load using the new version.
***
## Migrate to a new machine
> **Note:** Since the logs are saved to the EC2 instance, you might want to save them before terminating the machine.
Throughout the migration process, refer to the [AWS Nitro Co-signer installation guide](/reference/install-api-cosigner-aws), as some operations are identical.
Follow these steps to migrate the Co-signer to a new EC2 machine:
1. Set up a new EC2 Nitro-capable instance.
2. Download the installation package to the new instance.
3. Create a new API user that will be used to connect to the new Co-signer instance.
4. Stop the running Co-signer operation by executing the command `systemctl stop cosigner` on the existing EC2.
5. Run the installation script and provide the same S3 bucket and CMK values when prompted to enter parameters during the installation.
***
## Configure a proxy server
By default, the Co-signer is configured to communicate directly with Fireblocks SaaS without using a proxy server. Since the Co-signer uses certificate pinning for secure communication with Fireblocks SaaS, **only a transparent proxy can be used** between the Co-signer and Fireblocks SaaS.
To configure a proxy server, add the key value `HTTPS_PROXY="URL"` as an environment variable to the following file:
`/opt/fireblocks/env.txt`
```bash theme={"system"}
HTTPS_PROXY="URL" # Replace URL with your transparent proxy server
```
Changing the proxy server settings requires restarting the Co-signer. Run this command to restart it:
```bash theme={"system"}
systemctl restart cosigner
```
***
## Configure the communication protocol
By default, the Co-signer is configured to use WebSocket to communicate with Fireblocks SaaS. You can switch to HTTPS Long Polling by turning WebSocket off.
To turn WebSocket off, add the key value `WEBSOCKET=0` as an environment variable to the following file:
`/opt/fireblocks/env.txt`
```bash theme={"system"}
WEBSOCKET=1 # Use WebSocket
WEBSOCKET=0 # Use HTTPS Long Polling
```
Switching between the communication modes requires restarting the Co-signer. Run this command to restart it:
```bash theme={"system"}
systemctl restart cosigner
```
# GCP Confidential Space API Co-signer Maintenance
Source: https://developers.fireblocks.com/reference/api-cosigner-maintenance-gcp-confspace
> **Note:** You must have the necessary privileges to your Google Cloud account to perform maintenance operations.
## View the logs
To view the Co-Signer's logs, go to the [GCP's VM instances page](https://console.cloud.google.com/compute/instances) and validate that you see the right project (for example, "GCP-Customer-Cosigner-Dev"). After that, click on the relevant VM name and then press "logging" (which appears under "Logs"). This will open a new window with the customer Co-signer's logs.
## Observe the status
To check the Co-signer's health, run the following command:
```bash theme={"system"}
gcloud compute instances describe --zone= | grep status
```
Search for the `status` field of the VM in the output and confirm it is set to `RUNNING`. However, this does not guarantee the health of the Co-signer. To verify its functionality, monitor the transaction activity passing through it.
Also, use the [Co-signers management tab](https://support.fireblocks.io/hc/en-us/articles/14492251068060-The-Co-signer-management-tab) to observe the online / offline status.
## List the paired API users
Use the [Co-signers management tab](https://support.fireblocks.io/hc/en-us/articles/17923671680540-The-Co-signer-management-tab) to observe the paired API users.
## Retrieve the public key
You can view the Co-signer's logs in Google Cloud's console to find the public key used by the Callback Handler's server for JWT-encoded signed message authentication. Search for `public key` in the logs, as shown in the example below.
## Stop the Co-signer
You can stop the Co-signer by running:
```bash theme={"system"}
gcloud compute instances stop --zone=
```
> **Note**: This operation will not delete the VM.
You can also stop the VM from the GCP console.
## Restart the Co-Signer
In case the Co-signer's VM is down, given the Co-signer was already created, you can restart the Co-signer by running:
```bash theme={"system"}
gcloud compute instances start --zone=
```
When you restart the Co-signer after installing it, it will use the same configuration (metadata), so you don't need to enter all the parameters again.
## Retrieve the running version
Use Google Cloud's console to check the Co-signer's running image version by observing the `tee-image-reference` field in `Custom metadata` in the `Details` section.
Alternatively, you can search for `Initializing CustomerCosignerGCPConfidentialSpace, commit sha` within the instance logs.
## **Update proxy settings**
You can update or remove proxy settings on a running Co-signer without performing a full upgrade. The `--update-proxy` flag on the install/upgrade script handles this. It updates the VM's instance metadata in place and resets the VM to apply the change. No new VM is created.
The operation causes approximately 2 minutes of downtime while the VM restarts.
### **Run the update**
```bash theme={"system"}
./client_install_upgrade_api_cosigner_script.sh --update-proxy cloud-resources-.yaml
```
Replace `cloud-resources-.yaml` with the resources file generated during your installation.
#### **What the script does**
1. Loads your current configuration from the resources YAML file and displays a summary, including whether a proxy is currently configured.
2. Prompts you for the new proxy URL. To remove an existing proxy, press **Enter** without entering a value.
3. If a proxy URL is provided, encrypts it using your Cloud KMS key (credentials are never stored in plaintext), then prompts for `NO_PROXY` patterns. The current `NO_PROXY` value is shown as the default; press **Enter** to keep it.
4. Displays a summary of the changes and asks for confirmation before touching the running VM.
5. Updates the VM's instance metadata with the new configuration and resets the VM.
6. Writes the updated proxy settings to your resources YAML file.
#### **Proxy URL format**
```http theme={"system"}
http://proxy.example.com:8080
```
To authenticate to the proxy, include credentials in the URL:
```http theme={"system"}
http://username:password@proxy.example.com:8080
```
#### **Effect on WebSocket vs. long-polling**
When a proxy is configured, the Co-signer uses long-polling (REST) for communication with Fireblocks. WebSocket connections cannot reliably traverse proxies. When you remove a proxy, the Co-signer reverts to the WebSocket setting that was active before the proxy was added.
#### **Verify the update**
Once the VM is back online (approximately 2 minutes after the reset), proxy activity appears in Cloud Logging. To stream recent logs:
```bash theme={"system"}
gcloud logging read 'resource.type=gce_instance AND labels.instance_name=YOUR_VM_NAME' \
--limit=50 \
--order=desc
```
Replace `YOUR_VM_NAME` with your Co-signer VM name (visible in the summary the script prints before confirmation).
## Update the Co-signer
You can update the Co-signer by running the following script:
```bash theme={"system"}
client_stop_and_update_gcp_api_cosigner_script.sh
```
This script performs the following:
* Stops the existing VM running the current Co-signer.
* Updates the OIDC workload identity pool provider's attestation verification with the new image's SHA of the new version.
* Create a new VM that runs the new image.
The new Co-Signer VM utilizes the same database, keys, and cloud resources as the previous one.
> **Important notes:**
>
> * **Delete the old VM once the new one is fully operational.** Because the policy is configured to protect the VM from deletion, use the GCP console to disable the deletion protection under `VM > Edit > UNtag "Enable deletion protection"` and save the new settings before deleting the VM.
> * If a proxy was configured when the Co-signer was installed, the upgrade carries that configuration forward automatically. No additional input is required. To change or remove proxy settings on a running Co-signer, use the `--update-proxy` flag instead of performing an upgrade. See the [Update proxy settings](https://fireblocks.atlassian.net/browse/DOC-3350# "#") section.
> * Please make sure to refer this [doc](/reference/api-cosigner-versions-gcp) to get the Image SHA number.
## Migrate to a new machine
Stop the current Co-signer VM and set up a new one using the same resources besides the VM.
## Configure the communication protocol
WebSocket is the default protocol the Co-signer uses to communicate with the Fireblocks SaaS. You can switch to HTTP Long Polling by configuring the `client_install_gcp_api_cosigner_script.sh` script.
To configure the Co-signer to use HTTP long polling, you can create a new VM that will use the same resources, but ensure you remove the `\"--websocket\"` parameter from the `create_vm_cmd` line so that it will look like this:
```bash theme={"system"}
--metadata
^~^tee-image-reference=$image_ref~tee-container-log-redirect=true~tee-cmd='[\"--initial-config\", \"$initial_config\", \"$bucket\", \"$key_path\"]'"
```
Instead of:
```bash theme={"system"}
--metadata
^~^tee-image-reference=$image_ref~tee-container-log-redirect=true~tee-cmd='[\"--initial-config\", \"$initial_config\", \"$bucket\", \"$key_path\",\"--websocket\"]'"
```
If you don't want to create a new VM, you can edit the VM's metadata and instruct it to restart in HTTP Long Polling.
* Stop the Co-signer0 VM
* From the GCP console, locate `VM > Edit > Metadata`
* Remove "`--websocket`" from the "`Value 1`" matching Key 1 which is "`tee-cmd`"
* Click Save and restart the VM to apply the changes to the Co-signer
# SGX API Co-signer Maintenance
Source: https://developers.fireblocks.com/reference/api-cosigner-maintenance-sgx
> **Note:** You must have root privileges on the Co-signer machine to perform maintenance operations. Ensure you are logged in as a root user or use `sudo` to execute the commands.
## View the logs
You can export the logs to a file in the local directory, tagged with the current date and time, by running the following command:
```bash theme={"system"}
./cosigner logs
```
Append a number to the command to retrieve the specified most recent amount of lines.
By default, the Co-signer uses the Docker logging container. However, for better monitoring, the logs can be streamed to an external log delivery service, such as ELK, Splunk, or Datadog.
The SGX Co-signer generates two different types of logs for troubleshooting and auditing:
* `run.log` is an automatically generated log containing all of your Co-signer setup and configuration history.
* `customer_cosigner.log` contains workspace operation data, such as the workspace's transaction approving and signing history and new connection approvals. These log files are separated into 10 files limited to 4.1MB each. They are automatically overwritten in chronological order.
Your API Co-signer logs are structured using the following Regular Expression (RegEx):
```bash theme={"system"}
${AppName}:${Line} ${LogLevel} ${dd/MM/yyyy} ${HH:mm:ss,fff} ${ClassName} ::${MethodName} - ${LogMessage}
```
These logs are collected by the Docker container’s `STDOUT` stream and written into a log file on the container’s host machine at the location specified below. These log files are rotated with a max file size of 4MB for each log file.
```text theme={"system"}
/databases/cosigner/log/customer_cosigner.log
/databases/cosigner/log/customer_cosigner.log.1
/databases/cosigner/log/customer_cosigner.log.2
...
```
> **Note:** The Co-signer is Docker-based and uses the Docker JSON file driver for logging. By default, the driver uses a standard logging output but can be configured to support other logging mechanisms. Refer to the official Docker documentation for more detailed information.
***
## Verify SGX is enabled on the machine
After completing your server creation or installation, verify that SGX is enabled on the server. The Fireblocks API Co-Signers can only run on SGX-enabled servers with the latest patches, and verifying your configuration helps ensure you do not run into any potential issues later on.
1. Run the following commands on the server:
```bash theme={"system"}
sudo apt update
sudo apt upgrade
sudo apt install cpuid
cpuid -1 | grep -i sgx
```
2. Verify the following:
1. SGX: Software Guard Extensions supported is `true`.
2. SGX\_LC: SGX launch config supported is `true`.
> Note: Azure Standard\_DC\*\_v2 instances do not support SGX2, but it is not necessary to run the signer.
***
## List the paired API users
You can list all API users paired with the Co-signer across the connected workspaces by running the following command:
```bash theme={"system"}
./cosigner list-users
```
The output will display a list of all API users paired with your Co-Signer, including the workspace name they are connected to, the API user's ID (its API key), and the associated Callback Handler server URL (if applicable).
***
## Retrieve the public key
You can retrieve the Co-signer's public key, used by your optional Callback Handler server to authenticate requests from the Co-signer, by running the following command:
```bash theme={"system"}
./cosigner print-public-key
```
***
## Stop the Co-signer
You can stop the Co-signer by running the following command:
```bash theme={"system"}
./cosigner stop
```
***
## Start the Co-signer
You can Start the Co-signer by running the following command:
```bash theme={"system"}
./cosigner start
```
***
## Restart the Co-Signer
You can restart the Co-signer by running the following command:
```bash theme={"system"}
./cosigner restart
```
***
## Retrieve the running image version
You can retrieve your running Co-Signer version by running the following command:
```bash theme={"system"}
docker inspect cosigner | jq -r '.[0].Config.Image' + " " + '.[0].Image'
```
***
## Retrieve the script version
You can retrieve your current Co-Signer script version by running the following command:
```bash theme={"system"}
head cosigner -n 3 | grep -i ver
```
***
## Update the Co-signer
Retrieve the URL of the SGX installation script from the Console and use the `curl` command to download the script to the path where the existing Co-Signer script is present. Paste the appropriate URL into the following command:
```bash theme={"system"}
curl -o cosigner "URL Download Link"
```
> **Note:** If you have any issues with finding the installation script URL, please contact [Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new?ticket_form_id=360003372200\&tf_360023089139=global_settings\&tf_360023089159=get_api_co-signer_installation_script).
After downloading the installation script, navigate to the directory containing the script and modify the script's permissions to make it executable:
```bash theme={"system"}
chmod +x cosigner
```
Stop the Co-signer container by running the following command:
```bash theme={"system"}
./cosigner stop
```
Run `docker ps -a` and check the output. There should be no Co-signer container running.
Backup the Co-signer's database by running the following command:
```bash theme={"system"}
mv /databases/cosigner/enclave/enclave.signed.so /databases/cosigner/enclave/enclave.signed.so_old
```
Remove the current revision file:
```bash theme={"system"}
sudo rm -f .revision
```
You can now update the Co-signer to the latest version by running the following command:
```bash theme={"system"}
./cosigner start
```
You can update to a specific image version by replacing the `` :
```bash theme={"system"}
./cosigner start
```
Run `docker ps -a` and check the output. You should see the Co-signer container running.
If the update process did not succeed, try re-installing the Co-signer using the same version, but first remove the current version of the Co-Signer by running the following commands:
```bash theme={"system"}
sudo rm -rf /databases
sudo rm -f .local_config .revision
```
and then run:
```bash theme={"system"}
./cosigner setup
```
If that still doesn't work, refer to [API Co-signer Troubleshooting](/reference/api-cosigner-troubleshooting).
***
## Migrate to a new machine
Begin by setting up a new SGX-capable machine in your cloud or on-premises environment.
Migrating the SGX Co-Signer to a new machine is most effectively performed using backup data from the existing machine. This approach minimizes downtime and reduces the risk of interruptions to your workspace operations.
The following files and folders are generated automatically during the SGX Co-signer setup and are essential for backup and recovery purposes:
1. `/databases/cosigner/db`: The Co-signer DB folder stores the `secrets.db` file, the Co-Signer's secrets database. This file is encrypted with a key generated in a secure SGX enclave.
2. `/databases/cosigner/backup`: The backup folder maintained by the Co-Signer stores the backup upon any change to the database. The files are formatted using the following timestamp: `%Y%m%d%H%M%S.db` (e.g. `20220710184350.db`) based on the backup's date.
3. `/databases/cosigner/enclave/ra_loader_enclave.signed.so` - The enclave loader.
Backup the files `secrets.db` and `ra_loader_enclave.signed.so` and copy them to the same folder locations on the new server:
* `/databases/cosigner/db/secrets.db`
* `/databases/cosigner/enclave/ra_loader_enclave.signed.so`
After the above files have been copied to the new server, run `./cosigner start`.
If you don't have backups of either `secrets.db` or `ra_loader_enclave.signed.so` files, unpair (re-enroll) the API users that are associated with the Co-signer and set up a new Co-signer on the new machine. Refer to the [API Co-signer Installation Flow and Deployment Options](/reference/api-cosigner-installation-flow) article to find the specific SGX Co-signer environment you have.
# API Co-signer Management
Source: https://developers.fireblocks.com/reference/api-cosigner-management
In addition to manual transaction signing and Workspace configuration approvals using a mobile device, you can automate signing and approvals with an API Co-signer. This is ideal for workspaces that handle high transaction volumes or frequent activity.
A Co-signer is connected to a workspace by pairing it with an [API user](https://support.fireblocks.io/hc/en-us/articles/4407823826194-Adding-new-API-Users). Once connected, assuming the API user has a [Signer](https://support.fireblocks.io/hc/en-us/articles/360012832959-User-roles#h_01H9P4D2W1436XZYXESPTQE2J7) or [Admin](https://support.fireblocks.io/hc/en-us/articles/360012832959-User-roles#h_01H9P4D2W138W3F36TX45S8WFX) role, you will be asked to approve MPC key shares for that API user.
To activate automatic signing through the Co-signer, configure the [Policy](https://support.fireblocks.io/hc/en-us/articles/7354983580316-About-the-TAP) to [designate the API user](https://support.fireblocks.io/hc/en-us/articles/7365877039004-Rule-parameters#h_01HGBN9QQ0T42NR8XT4Y96V7YH) paired with the Co-signer as the signer. When a transaction you initiate meets the criteria defined in the policy, it will be automatically signed by the Co-signer associated with the configured API user.
At that point, you can add multiple API users to the Co-signer and configure the Callback Handler for each API user paired with it.
Use the articles below for detailed guides and information.
***
## CO-SIGNER INSTALLATION
[Co-signer installation flow](/reference/api-cosigner-installation-flow)
[Install AWS Nitro](/reference/install-api-cosigner-aws)
[Install GCP Confidential Space](/reference/install-api-cosigner-gcp)
[Install SGX on Microsoft Azure](/reference/install-api-cosigner-azure)
[Install SGX via Azure Marketplace](/reference/install-api-cosigner-azure-marketplace)
[Install SGX on IBM Cloud](/reference/install-api-cosigner-ibm)
[Install SGX on Alibaba Cloud](/reference/install-api-cosigner-alibaba)
[Install SGX On-Premise](/reference/install-api-cosigner-onprem)
## SETUP AND TESTING
[Using the Communal Test Co-signer](/reference/use-communal-cosigner)
[Establishing Secure Communication Between the Co-signer and the Callback Handler](/reference/cosigner-callbackhandler-secure-communication-authentication)
[Callback Handler Response Object](/reference/response-object)
[Approve Transactions](/reference/approve-transactions)
[Approve Configuration Changes](/reference/approve-configuration-changes)
[Callback Handler Code Example](/reference/basic-code-example)
[Use the Plugin-based Callback Handler](/reference/plugin-based-callback-handler)
[Validate ETH Raw Transactions](/reference/validate-eth-raw-transactions)
MAINTENANCE
[Overview](/reference/api-cosigner-maintenance)
[SGX Co-signer Maintenance](/reference/api-cosigner-maintenance-sgx)
[AWS Co-signer Maintenance](/reference/api-cosigner-maintenance-aws-nitro)
[GCP Co-signer Maintenance](/reference/api-cosigner-maintenance-gcp-confspace)
## CO-SIGNER OPERATION
[Using APIs, Console and Command-Line Interface to Operate the Co-signer](/reference/api-cosigner-operate)
## VERSIONS
[Overview](/reference/api-cosigner-versions)
[SGX Co-signer Version History](/reference/api-cosigner-versions-sgx)
[AWS Co-signer Version History](/reference/api-cosigner-versions-aws)
[GCP Co-signer Version History](/reference/api-cosigner-versions-gcp)
## SUPPORT
[Troubleshooting](/reference/api-cosigner-troubleshooting)
# Operating the API Co-signer
Source: https://developers.fireblocks.com/reference/api-cosigner-operate
Once the Co-signer is connected to your workspace, you can manage it through the Console or APIs. This includes sending commands such as pairing additional API users or configuring the Callback Handler for a paired API user.
For all types of SGX Co-signers and the AWS Nitro Co-signer, all operations can also be performed via the command-line interface (CLI) on the Co-signer's host machine.
However, due to the enclave architecture of the Google Cloud Confidential Space Co-signer, all operations on this type of Co-signer must be performed exclusively through the Console or APIs.
## Co-signer API operations
Refer to [Fireblocks Cosigners API](/reference/getcosigners) for the list of Co-signer operations you can do using Fireblocks APIs.
The operations include:
* Get all the Co-signers that are connected to the workspace
* Get the details of a specific Co-signer that is connected to the workspace
* Rename the Co-signer
* Get a list of all the API users that are paired with the Co-signer
* Get the details of a specific API user that is paired with the Co-signer
* Add a Co-signer to the workspace
* ❗ Pair an additional API user with a Co-signer
* Unpair an API user from a Co-signer
* ❗Update the callback handler of a paired API user
> **The operations that are marked with ❗ will only work with Co-signers with the following versions:**
>
> * SGX Co-signer: version 3.7.1 or later
> * AWS Nitro Co-signer: version 2.0.5 or later
> * Google Cloud Confidential Space Co-signer: version 0.9.4 or later
***
## Co-signer Console operations
For a detailed description of the Co-signer operations available through the Console, visit the [Co-signer Management tab](https://support.fireblocks.io/hc/en-us/articles/17923671680540-The-Co-signers-management-tab) in the Help Center.
***
## Co-signer command-line operations
This section covers operations related to Co-signer management, including adding and configuring API users. For maintenance operations such as viewing logs, updating the Co-signer, and more, refer to the [API Co-signer maintenance](/reference/api-cosigner-maintenance) article.
### List the paired API users
You can list all API users paired with the Co-signer across the connected workspaces by running the following command:
```bash theme={"system"}
./cosigner list-users
```
The output will display a list of all API users paired with your Co-Signer, including the workspace name they are connected to, the API user's ID (its API key), and the associated Callback Handler server URL (if applicable).
### Add API user
You can pair an additional API user with your Co-Signer instance by running the following command:
```bash theme={"system"}
./cosigner add-user
```
> **Note:** This command works only after the first API user has been paired during the Co-Signer installation.
You will be prompted to provide the API user's pairing token, which can be retrieved from the Console. If you opt to connect this API user with a Callback Handler, you must also provide the Callback Handler's URL and its public key or certificate. For more information, refer to the **Setup API Co-Signer Callback Handler** article.
### Setup and update Callback Handler for API user
You can setup the Callback Handler for an API user paired with the Co-signer, provided it does not already have a configured Callback Handler, by running the following command:
```bash theme={"system"}
./cosigner callback-update [API user ID]
```
If only one API user is paired with your Co-Signer, you don't have to specify the `API user ID` , which is its API key.
If you want to configure the URL of the Callback Handler of an API user that is paired with the Co-signer, run the following command:
```bash theme={"system"}
./cosigner callback-update [API user ID]
```
You will be prompted to enter the URL and public key or certificate parameters, but **only the URL you provide will be updated**. To change the Callback Handler's public key or the certificate through the CLI, you must unpair (re-enroll) the API user and pair it again with the Co-Signer using the `add-user` CLI command.
Note that if only one API user is paired with your Co-Signer, unpairing (re-enrolling) the API user results in a full Co-signer setup to initialize the API user and pair it with the new Callback Handler.
Alternatively, instead of unpairing the API user and pairing it again, you can configure the Callback Handler's public key or certificate of an API user that is paired with the Co-signer using APIs or through the Console.
> Note: To configure the Callback Handler's public key or certificate using APIs or through the Console, your Co-signer should meet the requirements for Co-signer platform commands, as described in the [Co-signer API operations section](/reference/api-cosigner-operate#co-signer-api-operations) within this article,
# API Co-signer Troubleshooting
Source: https://developers.fireblocks.com/reference/api-cosigner-troubleshooting
## Contacting Fireblocks API Co-signer Support
If you have a question or need assistance, [contact Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new) and include the following information in your request:
* Your workspace name
* The first four characters of the API key associated with the API user used to connect the Co-signer to the workspace.
* Indicate whether the API user is paired with an active Co-signer or is in the process of completing the initial setup.
Copy the logs from the API Co-signer and include them in the support ticket. Refer to [the Co-signer maintenance documentation](/reference/api-cosigner-maintenance) to locate the logs for your specific type of Co-signer.
***
## Error codes
| Error Code | Description | Possible Cause |
| --------------- | ------------ | ------------------------------------------------------- |
| 401 | Unauthorized | User account-related issue. |
| 403 | Forbidden | Your firewall, proxy, or WAF is blocking communication. |
| 500 / 502 / 504 | Server error | Temporary server-side issue. |
***
## Error messages
### Error message "MPC setup not completed"
This error message indicates that the workspace Owner must still approve the API user's MPC key shares.
#### Resolution
Check the Owner's device for pending MPC key share approval notifications.
* If the notification is less than 12 hours old, the Owner can still approve the key shares, and the API user will be ready to sign transactions. Once the owner approves your new MPC keys on their Fireblocks mobile app. You have 6 hours to complete the MPC registration.
* If the Owner is unable to approve the request due to [Error 52](https://support.fireblocks.io/hc/en-us/articles/9108149928092-Error-52), deny the pending request and [submit a request to Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new).
* If there is no notification or another error, unpair the API user and then pair it with the Co-signer again to resend the approval request.
### API Co-signer does not sign transactions
The API Co-signer may not sign transactions if its transaction queue is full. In this case, the API logs will include an error stating that the "**queue is full**". This means the API Co-signer's internal queue is overloaded and must be restarted. This is separate from your workspace transaction queue.
#### Resolution
To resolve a full Co-signer queue:
1. Cancel all the pending transactions.
2. Make sure there are no pending requests on the Co-signer.
3. Restart the Co-signer.
4. Wait a few minutes to confirm that the queue is empty.
5. Submit a new transaction.
6. Confirm the transaction is signed by the Co-signer as expected.
> **Confirm your Co-signer meets minimum hardware requirements**
>
> The root cause of the full queue may be server CPU capabilities. Confirm that your Co-signer server meets the recommended hardware requirements.
### API Co-signer does not sign raw-signing transactions
When this issue occurs, the API Co-Signer signs some raw signing transactions but not others. This usually results from [signature caching for off-chain messages](https://support.fireblocks.io/hc/en-us/articles/4413379762450).
> **Signature caching enabled by default**
>
> Signature caching for raw signing is enabled by default. [Submit a request to Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new?ticket_form_id=5129187878556\&tf_5465594782876=api_co-signer_setup_and_configuration__what_are_you_trying_to_do___other) if you want this feature disabled.
### IO Exception: status code = 28
This error is a generic Linux filesystem error. It indicates that the disk is full, and your infrastructure and DevOps teams need to add additional disk space.
### SGX Co-signer: failed attestation to Fireblocks, try to perform microcode update
This error indicates that the OS or BIOS microcode version is outdated and can’t perform the SGX attestation with the Fireblocks server.
#### Resolution
Make sure the threads/processor, and hyperthreading (HT) are disabled and that SGX, DCAP, and FLC are enabled.
To verify whether HT is enabled, run the following command:
```bash theme={"system"}
hostname# lscpu | grep Thread
```
This command should output:
```text theme={"system"}
Thread(s) per core: 1
```
To verify the microcode version, run the following command:
```bash theme={"system"}
# cat /proc/cpuinfo | grep -E "model name|microcode"
# dmesg | grep microcode
# dpkg -l | grep intel-microcode
```
### SGX Co-signer: migration options when an Azure region outage occurs
When Azure region issues occur where an API Co-signer instance is running, it can have the following effects:
* Connectivity issues
* An instance crashing, becoming unavailable, or being damaged and irrecoverable
* Withdrawals are not being processed and are getting stuck in the `PENDING_SIGNATURE` or `QUEUED` statuses due to the API Co-signer being unable to sign transactions.
> **Check your Azure region status**
>
> To check your Azure region's status, visit the [Azure status page](https://status.azure.com/en-us/status).
#### Workarounds
During an Azure region outage, you can use one of the following workarounds to ensure your financial operations continue uninterrupted. After the outage is resolved, you can return to your normal setup and resume operations.
#### Step 1: Install a new API Co-signer instance in another region
After doing that, you can unpair your existing API user and pair it with your new Co-signer.
#### Step 2: Define a user's mobile device as a designated signer on your Policy
You can define a user's mobile device as the designated signer for Policy rules that previously required your Co-signer to sign. However, this solution may not be ideal for some customers since it requires you to manually cancel all already submitted transactions, resubmit them, and then have them signed manually.
If you decide to change your Policy rules, [contact Fireblocks Support](https://support.fireblocks.io/hc/en-us/articles/4808588554396).
#### Step 3: Migrate an existing Co-signer instance to an unaffected region
Follow the [official guide from Microsoft](https://learn.microsoft.com/en-us/azure/site-recovery/azure-to-azure-move-overview). If you require any additional clarification, contact Azure for technical assistance. Note that this operation might take a considerable amount of time.
#### Checking the instance's health post-migration
To verify the Co-signer is healthy after the maintenance reboot, run `docker ps -a` and check the output. You should be able to confirm that the `cosigner-init` container is not running and the `cosigner` container is not restarting.
Also, cancel any transactions that are stuck in the `PENDING_SIGNATURE` status and verify that the status of your `QUEUED` transactions have changed to `PENDING_SIGNATURE`, meaning that the Co-signer can process them.
### SGX Co-signer: setup fails with error "Failed to download loader enclave"
This error typically occurs during the initial setup process of an API Co-signer.
During the initial setup process, the First user on this machine checkbox must be selected when the first API user to be added to the Co-signer machine is created. If the API user is created and the checkbox is not selected, the error below appears in the `date_time_run.log` file (located in the same directory in which the API Co-signer script runs):
```text theme={"system"}
customer_cosigner:24 ERROR 31/12/2000 20:03:21,462
untrusted/ra_loader.cpp(457)fireblocks::common::ra_loader::download_loader_with_access_token - Failed to download loader enclave file, http status 401
customer_cosigner:24 FATAL 31/12/2000 20:03:21,463
main.cpp(490) ::init - Failed to download ra loader
```
#### Resolution
There are two resolutions for this issue.
#### Resolution 1: Start over with a new API user
1. Delete the API user that you attempted to pair with the Co-signer.
2. Create another API user. Make sure to select the **first user in this machine** checkbox.
3. Run the following command on the Co-signer instance:
```bash theme={"system"}
./cosigner stop
docker kill $(docker ps -q)
docker rm $(docker ps -aq)
docker rmi $(docker images -q)
```
4. Run the following command to begin the setup process again:
```bash theme={"system"}
./cosigner setup
```
#### Resolution 2: Contact Fireblocks Support
If you cannot create an API user or require the setup to be completed with the existing API user, contact Fireblocks Support.
### SGX Co-signer: syntax error near unexpected token: “newline” or “ `` ”
This error indicates that the link for downloading the Co-signer script has expired. To confirm, run the following command:
```bash theme={"system"}
head cosigner
```
If the link has expired, you should get the following response:
```xml theme={"system"}
``
SignatureDoesNotMatch``
The request signature we calculated does not match the signature you provided. Check your key and signing method.``
AKIA5QO5IU7PYPUJ7AU6``
AWS4-HMAC-SHA256
```
#### Resolution
To resolve this issue, download a new SGX Co-signer install script from the Console and run it again.
### SGX Co-signer: setup fails with the error "gathering device information while adding custom device, "/dev/sgx\_enclave", or unable to find file or directory"
This error indicates that the target instance doesn't support SGX or its SGX is not enabled, or that other machine specs don't match or are missing. For example, the correct size should be `DC4s_V3`.
#### Resolution
* You can find a list of SGX-supported instance types [here](https://docs.microsoft.com/en-us/azure/confidential-computing/quick-create-portal).
* For product availability in different regions, see [here](https://azure.microsoft.com/en-us/global-infrastructure/services/?products=virtual-machines\®ions=all).
### SGX Co-signer: invalid reference format
This error indicates that you upgraded an existing Azure instance with an older version installed, and the older version files are stored in your temp files (.local\_config / .revision).
#### Resolution
To resolve this issue:
1. Make sure to keep the docker-compose files and the script in the correct directory
(`.local_config` / `.revision`) before performing the API Co-signer setup.
2. Remove all files in the directory except the docker-compose files and the script.
3. Run the following command:
```bash theme={"system"}
./cosigner setup
```
4. When you are prompted to pair the token, exit that installation but continue with the docker installation.
### SGX Co-singer: curl command to [https://mobileapi.fireblocks.io/broadcast\\\_mpc\\\_m](https://mobileapi.fireblocks.io/broadcast\\_mpc\\_m) failed with error "Couldn't resolve host 'mobile-api.fireblocks.io'"
> **Warning**
>
> This error is not common, so we recommend contacting Fireblocks Support before you take action.
This error indicates that the request failed to send a message for the signed transaction and will remain in the **Pending** status until it is canceled. This is typically due to a network issue. However, in one case, we found that the DNS prevented the message from reaching the signing phase.
#### Resolution
To resolve this issue:
1. Go to the `vi/etc/systemd/resolved.conf` directory.
2. Under the Resolve heading, change the DNS value to **8.8.8.8 8.8.4.4**.
3. Run the following command:
```bash theme={"system"}
systemctl restart systemd-resolved.service
```
# API Co-signers Versions
Source: https://developers.fireblocks.com/reference/api-cosigner-versions
Below are the version details for each of the Co-signer types:
* [SGX Co-signer version history](/reference/api-cosigner-versions-sgx)
* [AWS Nitro Co-signer version history](/reference/api-cosigner-versions-aws)
* [Google Cloud Confidential Space Co-signer version history](/reference/api-cosigner-versions-gcp)
# AWS Nitro API Co-signer Version History
Source: https://developers.fireblocks.com/reference/api-cosigner-versions-aws
Fireblocks updates the API Co-signer software to include stability enhancements and new features. This article details the most recent AWS Nitro Co-signer versions. Always use the latest version listed here for optimal performance.
## Latest version
### **Version 2026.04.27 (April 2026)**
**Version hash:** `1d5b48eeef`
* Performance improvements and bug fixes
***
## Version history
### Version 2026.03.02 (March 2026)
**Version hash:** 95a317d3c7
* Added support for POLICY\_CHANGE approval request type (the customer co-signer can now approve policy changes via Policy Service v2)
* Performance improvements and bug fixes
### Version 2026.01.29 (January 2026)
**Version hash:** 340d9f6057
* Bug fixes and performance improvements
### Version 2025.12.30 (December 2025)
**Version hash:** a294449c1b
* Added support for "Protected Tags" approval requests
### Version 2025.12.11 (December 2025)
**Version hash:** c44604398e
* The callback can now return a “retry” response in an exchange withdraw operation
### Version 2025.11.20 (November 2025)
**Version hash:** 82a5cc0078
* Fixed a bug that may cause the Co-signer not to load correctly after a graceful shutdown
### Version 2025.10.09 (October 2025)
**Version hash:** 4e34888c01
* Fixed bug parsing messages after websocket reconnect
* Fixed bug sending messages on half closed websocket connections
### Version 2025.08.12 (August 2025; US environments only)
**Version hash:** 19c07421dc
* Fixed WebSocket bug causing performance issues
### Version 2025.07.16 (July 2025)
**Version hash:** bb61e507
* Fixed bugs and increased performance
* Better support for web sockets
### Version 2.1.1 (April 2025)
**Version hash:** 7160d7b833
* Bug fixes and performance improvements
### Version 2.0.5 (September 2024)
**Version hash:** d177e696c3
* Decreased signing latency along with general performance increases
* Extended filtering of environment variables
* Improvements to key handling within the enclave
* Bug fixes
### Version 2.0.4 (August 2024)
**Version hash:** 41d1888dc8
* Fixed the issue when setting AWS region using environment variables
* Removed unnecessary testing artifacts
### Version 2.0.2 (August 2024)
* Modified KMS CMK ARN prompt
* Added start, stop and restart commands
* Added echo to show where logs are saved to
* Fixed AWS NTP sync issue
* Fixed Callback Handler public key issue on install
* Removed unnecessary testing artifacts
### Version 2.0.1 (July 2024)
* Added check for force flag and existence of destination before the user is prompted for details
* Added route DNS queries to the DNS server defined on the host EC2 instance
### Version 2.0.0 (June 2024)
* Initial release
# GCP Confidential Space API Co-signer Version History
Source: https://developers.fireblocks.com/reference/api-cosigner-versions-gcp
Fireblocks updates the API Co-signer software to include stability enhancements and new features. This article details the most recent Google Cloud Confidential Space Co-signer versions. Always use the latest version listed here for optimal performance.
***
## Latest version
### **Version 2026.04.27 (April 2026)**
**Version hash:** `1d5b48eeef`
* The cosigner can now connect through a proxy. User/password authentication and no\_proxy values are also supported.
* Performance improvements and bug fixes
***
## Version history
### Version 2026.03.02 (March 2026)
**Version hash:** `95a317d3c7`
* Added support for POLICY\_CHANGE approval request type (the customer co-signer can now approve policy changes via Policy Service v2)
* Performance improvements and bug fixes
### Version 2026.01.29 (January 2026)
**Version hash:** 340d9f6057
* Bug fixes and performance improvements
### Version 2025.12.30 (December 2025)
**Version hash:** a294449c1b
* Added support for "Protected Tags" approval requests
### Version 2025.12.11 (December 2025)
**Version hash:** c44604398e
* The callback can now return a “retry” response in an exchange withdraw operation
### Version 2025.08.12 (August 2025; US environments only)
**Version hash:** 19c07421dc
* Fixed WebSocket bug causing performance issues
* Image digest SHA (US): sha256:61f951f0b8a66e906ab3ef742a3aa6b0312b279190c3e6478feae6d4b002be3f
* Image path (US): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:2025.08.12
### Version 2025.07.16 (July 2025)
**Version hash:** bb61e507
* Fixed bugs and increased performance
* Better support for web sockets
* Image digest SHA (US): sha256:19b651f855f697ffc67ba97c33639f5a4c6db717019412df62e3ee5994ea6c44
* Image Path (US): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:2025.07.16
* Image details for EU:
Digest SHA - sha256:4318bf2b9c0eccf8fd2cda2291366a6cf406e426c8a97b3d754a3d9bcc4e1d13 Path - us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:2025.07.16.eu
* Image details for EU2:
Digest SHA - sha256:1f11be136216311532d1277d7fe9e4aba3e4394c6f699904f8969aca097c3dc0 Path - us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:2025.07.16.eu2
* Image details for Sandbox:
Digest SHA - sha256:5155a2258fba75b7321ca3136aab47f2af0a14dd0cdf29e0132ab06da1ab6086 Path - us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:2025.07.16.sandbox
### Version 1.1.1 (April 2025)
**Version hash:** 7160d7b833
* Bug fixes and performance improvements
### Version 1.1.0 (March 2025)
**Version hash:** 2584ed02d1
* Image SHA (US): sha256:40893bdf713df66f4cfa857420989b583c0011c84fee0b8f92acd182d37a7f81
* Image Path (US): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:1.1.0
* Image SHA (EU): sha256:2e4f02f5c90e92819111fd93822cf557ab1ffd5a8faed919bd3144ce0563e6cc
* Image Path (EU): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:1.1.0.eu
* Image SHA (EU2): sha256:af2178f2f80a64107b04d7627e3e0e2483c745f999fdf30f60c2808900ae40ff
* Image Path (EU2): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:1.1.0.eu2
* Bug fixes and performance improvements
### Version 1.0.0 (January 2025)
**Version hash:** 27de90bb6f
* Image SHA (US): sha256:af6b7e6276af09e20e389ec2f63299bca293f646154e48b8144a2a9179c0b06e
* Added helper script for updating an existing GCP Customer Co-Signer to a newer image
* Validated + handled if missing physicalDeviceId in the Co-Signer’s config (relevant to all Co-Signers)
* Added default image path and image SHA to GCP Customer Co-Signer scripts
* Image SHA (US): sha256:af6b7e6276af09e20e389ec2f63299bca293f646154e48b8144a2a9179c0b06e
Image Path (US): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:1.0.0
* Image SHA (EU): sha256:5c456aa3e5953e0fedfa80717d8cc977e9d9ee94eb561cbabe69379baa587386
* Image Path (EU): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:1.0.0.eu
* Image SHA (EU2): sha256:861c5d90fdb345a794cea4a8ce2c886c2cb3a9d531b825da38cc27848b978a0c
* Image Path (EU2): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:1.0.0.eu2
* Image SHA (Sandbox): sha256:18018d945f1bf7f8cd82273798d997c0bdef56db67a1c101c87d8e12aaf6df79
* Image Path (Sandbox): us-docker.pkg.dev/fireblocks-customer-cosigner/fireblocks-customer-cosigner-repository/gcp-cosigner:1.0.0.sandbox
### Version 0.9.5 (October 2024)
**Version hash:** 121b4c2775
* Image SHA: sha256:894c4e573b52e785cf7b2ad2e10f73d766b4a88cb1078daf087ce8ab8703f928
* Security policy enhancements
* Bug fixes
### Version 0.9.4 (November 2024; EU version)
**Version hash:** d177e696c3
* Image SHA: sha256:30aca13b7dcb7db41a4138066ca3bc6e601ad1cdc417484f8c6a7433851eba62
* Added support for platform remote commands
* Performance optimizations
* Security policy enhancements
* Bug fixes
### Version 0.9.4 (October 2024; non-EU version)
**Version hash:** d177e696c3
* Image SHA: sha256:7ecfc480ccb65613db0f2b1cedfcd765be944bbadb5da1e0e098fa0ccb0876cb (Prod, not EU)
* Added support for platform remote commands
* Performance optimizations
* Security policy enhancements
* Bug fixes
### Version 0.9.3 (August 2024)
**Version hash:** 6647aa5291
* Image SHA: sha256:ed12b926a7d46e98be9943791c4e350dd193a4bc5f7c222ce1c765715b11bf9e
* Added printing the Co-signer Public Key to the logs
### Version 0.9.2 (July 2024)
**Version hash:** 257b33246b
* Image SHA: sha256:5bd371e9a877bcf7cc662ecaae5791b3b5c8b797348e1540faaf272cc153cb39
* Initial release
# SGX API Co-signer Version History
Source: https://developers.fireblocks.com/reference/api-cosigner-versions-sgx
Fireblocks updates the API Co-signer software to include stability enhancements and new features. This article provides details about the most recent SGX Co-signer versions. Always use the latest version listed here for optimal performance.
## Latest SGX Co-signer image version
### **Version 2026.04.27 (April 2026)**
**Version hash:** `1d5b48eeef`
* Performance improvements and bug fixes
***
## SGX Co-signer image version history
### Version 2026.03.02 (March 2026)
**Version hash:** 95a317d3c7
* Added support for POLICY\_CHANGE approval request type (the customer co-signer can now approve policy changes via Policy Service v2)
* Performance improvements and bug fixes
### Version 2026.01.29 (January 2026)
**Version hash:** 340d9f6057
* Bug fixes and performance improvements
### Version 2025.12.30 (December 2025)
**Version hash:** a294449c1b
* Added support for "Protected Tags" approval requests
### Version 2025.12.11 (December 2025)
**Version hash:** c44604398e
* The callback handler can now authenticate using a certificate signed by a root CA certificate preloaded to the Co-signer
* The callback handler can now authenticate using both JWT and a certificate provided directly to the Co-signer (or signed by a root CA certificate provided to the Co-signer)
* The callback can now return a "retry" response on exchange withdraw operation
### Version 2025.10.09 (October 2025)
**Version hash:** 4e34888c01
* Fixed bug parsing messages after websocket reconnect.
* Fixed bug sending messages on half-closed websocket connections.
### Version 2025.08.12 (August 2025; US environments only)
**Version hash:** 19c07421dc
* Fixed WebSocket bug causing performance issues
### Version 2025.07.16 (July 2025)
**Version hash:** bb61e507
* Fixed bugs and increased performance
* Better support for web sockets
### Version 3.10.1 (April 2025)
**Version hash:** 7160d7b833
* Bug fixes and performance improvements
### Version 3.7.1 (October 2024)
**Version hash:** 4ec196aec5
* Decreased signing latency, along with general performance increases
* Remote management capabilities through Fireblocks Console
* Support for more types of approval requests
* Various fixed and improved handling of internal errors
* Timing details are logged after every outgoing network request
* The cosigner version will be reflected in the HTTP User-Agent header
### Version 3.6.5 (February 2024)
**Version hash:** 3b807e2af7
* Improved logging for easier problem-solving
* Improved stability, security, and performance
* Enhanced deployment flexibility
* Added support for the Callback Handler retry mechanism, enabling the Callback Handler to respond asynchronously
* Updated major and minor dependencies
* Preliminary support for upcoming features
* Bug fixes
### Version 3.5.0 (August 2023)
* [MPC-CMP security enhancements](https://support.fireblocks.io/hc/en-us/articles/10167020461596-MPC-CMP-security-enhancements-version-update-August-2023)
* Bug fixes
### Version 3.3.0 (January 2022)
* Added support for HTTP network proxy on outbound requests
* Bug fixes
***
## Latest SGX Co-signer script version
### Version 2025.10.11 (December 2025)
* New default Docker image: 2025.10.11
## SGX Co-Signer script version history
### Version 2025.10.09 (October 2025)
* New default Docker image: 2025.10.09
* Switched to Calendar Versioning to align script versions with default image versions
### Version 1.1.13 (August 2025)
* New default Docker image 2025.08.12
### Version 1.1.11 (April 2025)
* New default Docker image 3.10.1
### Version 1.1.10 (January 2025)
* New default Docker image 3.7.1
### Version 1.1.9 (February 2024)
* New default Docker image 3.6.5
### Version 1.1.8 (January 2024)
* Added support for Callback Handler configuration via Azure Marketplace
* Same default Docker image as in image version 3.5.0 and used as in script version 1.1.7
### Version 1.1.7 (August 2023)
* New default Docker image 3.5.0
### Version 1.1.6 (February 2023)
* Added support for Docker version 1.29.2
* Added validation for microcode:
* Additional information about the microcode version appears in the logs
* Relevant only to customers with SGX Co-signers installed on-prem
* Added validation to make sure Hyper-Threading is disabled
* If Hyper-Threading is enabled, additional information appears in the logs
* Relevant only to customers with SGX Co-signers installed on-prem
### Version 1.1.5 (February 2022)
* New default Docker image 3.3.0
* Added support for Co-signers in high-availability
* Updated authentication model
* Added support for HTTP network proxy on outbound requests
***
## Checking SGX Co-signer versions
### How do I check the version of my running SGX Co-signer image?
To check your running SGX Co-signer image version, run the following command on your VM:
```bash theme={"system"}
docker inspect cosigner | jq -r '.[0].Config.Image +" " + . [0].Image'
```
### How do I check the version of my running SGX Co-signer script?
To check your running SGX Co-signer script version, run the following command on your VM:
```bash theme={"system"}
head cosigner -n 3 | grep -i ver
```
# API Endpoints Overview
Source: https://developers.fireblocks.com/reference/api-endpoints-overview
The **API Endpoints** section lists every REST endpoint in the Fireblocks API. Each endpoint page includes:
* **Description** — What the endpoint does and when to use it
* **Parameters and request body** — Required and optional fields
* **Response schema** — Response shape and status codes
* **Playground** — Try the request with your credentials (when enabled)
The reference is generated from our [OpenAPI 3.0 specification](https://docs.fireblocks.com/api/v1/swagger.yaml). You can import the spec into Swagger UI, ReDoc, Postman, or use it to generate client libraries.
## Before you call the API
* **[Authentication](/reference/signing-a-request-jwt-structure)** — Sign requests with JWT using your API key and secret
* **[Rate limiting](/reference/rate-limiting)** — Request limits and best practices
## Testing your calls
Each endpoint page has a **playground** where you can try requests with your credentials. If you prefer to test from Postman instead, use the [Postman Guide](/reference/explore-postman-collection).
## Next steps
Use the sidebar to browse endpoints by category, or search for a specific operation. For high-level concepts and SDKs, see the [API Overview](/reference/api-overview).
# API responses and error codes
Source: https://developers.fireblocks.com/reference/api-error-codes
# HTTP status code summary
| HTTP Status Code Summary | | |
| ------------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| 200 | OK | The request was processed as expected. |
| 400 | Bad Request | The request is not well-formed, violates the schema, or has incorrect fields. |
| 401 | Unauthorized | The API key doesn't match the signature or have the necessary permissions to perform the request. |
| 403 | Forbidden | The API key doesn't have the necessary permissions to complete the request. |
| 404 | Not Found | The requested resource doesn't exist. |
| 429 | Too Many Requests | Too many requests hit the API too quickly. Blocked due to rate limiting. We recommend an exponential backoff of your requests. |
| 5XX | Server Errors | Something went wrong on Fireblocks' end. (These are rare.) |
# API error codes
The tables below contain all error codes (along with their corresponding HTTP status codes) for the Fireblocks API. We recommend reviewing the codes related to the features you want to implement for your workspace and customers.
## 4XX Error Codes
| Error Code | HTTP Status Code | Relevant Features | Issue and Remediation |
| ---------- | ---------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| -1 | 401 | All | **Invalid signature** If you receive this error message, ensure the private key you used is correct. |
| -2 | 401 | All | **Missing API Key in the JWT** Verify that you specify the API key |
| -3 | 401 | All | **The entire JWT is missing** - Uncommon\_ - Potential code change, or bad parameters passed to Fireblocks SDK constructor |
| -4 | 401 | All | **Wrong URL in the JWT** - Uncommon\_ - Potential code change to the Fireblocks SDK source code on your device |
| -5 | 401 | All | **Unauthorized: Invalid token format** This error code typically indicates the certificate associated with the API user making the call has expired. |
| -6 | 401 | All | **Wrong User in the JWT** The user being used as part of the request is incorrect. Verify that the correct user is being used |
| -7 | 401 | All | **Unauthorized: Token was not accepted** This error code typically indicates that the JSON Web Token (JWT) supplied with the API user’s request was not accepted. API requests to Fireblocks are authenticated using the provided JWT. If the JWT is invalid, you will receive the error code. The cause of the error is likely either the wrong API key being used or the wrong baseURL being used. For SDK users, this typically means an incorrect API key was used to create the client. For users with native API client implementations, this typically indicates an error with your JWT creation logic. |
| -8 | 401 | All | **Insufficient permissions** This error code typically indicates that the API user initiating this request does not have access to the requested operation based on their user role |
| -10 | 401 | All | **The request has expired** This error typically indicates the JSON Web Token (JWT) supplied with the API user’s request has timed out. Please note: - For Fireblocks SDK users, the JWT expiration time is defined based on the system time. - For users with their own API client implementations, the JWT data is defined by the user’s implementation. |
| -12 | 401 | All | **The request is with a future issuance timestamp (iat)** This error code typically indicates the JSON Web Token (JWT) supplied with the API user’s request is not yet valid for processing. - For SDK users, the JWT “initiated–at” time is defined based on the system time. - For users with their own API client implementations, the JWT data is defined by the user’s implementation. |
| 1000 | 400 | Vault | **GetVaultAccounts request has invalid values** Check that you pass a valid `minAmountThreshold` (if you pass it) and only one of `namePrefix`, `nameSuffix` if you pass it |
| 1002 | 400 | Vault | **Create Vault Account failed** Verify that the values provided to the create vault account request are valid and conform to the types specified in the API Docs |
| 1004 | 404 | Vault | **Vault account ID was not found** Verify that the vault account you're trying to query is valid and exists |
| 1006 | 404 | Asset, Balance | **Asset doesn't exist** The asset requested for the given vault account does not exist. Verify that the vault account contains the asset you're requesting. |
| 1008 | 400 | Wallet, Asset (EOS Specific) | **EOS Wallet Creation failed** The eosAccountName parameter is invalid |
| 1010 | 400 | Wallet | **Renaming a deposit address failed** You're trying to add an address to a blockchain that does not support more than 1 address (such as ETH) |
| 1013 | 400 | Vault | **Vault account renaming failed** Verify that the parameters passed to the vault account renaming operation are valid |
| 1015 | 400 | Wallet | **Rename a deposit address failed** Verify that the parameters that were passed are valid and that the asset you're trying to rename exists |
| 1016 | 400 | Wallet | **Rename a deposit address failed** The rename operation failed due to a backend issue - open a ticket to support |
| 1017 | 400 | Vault | **Hide vault account failed** The vault account you requested to hide does not exist. Please verify you're using the correct vault account ID |
| 1019 | 400 | Vault | **Hide on a hidden vault account request** You're requesting to hide a vault account that is already hidden. Please verify you're using the correct vault account ID |
| 1020 | 400 | Vault | **Unhide vault account failed** The vault account you requested to unhide does not exist. Please verify you're using the correct vault account ID |
| 1022 | 400 | Vault | **Unhide on a visible vault account request** You're requesting to unhide a vault account that is not hidden. Please verify you're using the correct vault account ID |
| 1023 | 400, 404 | Wallet | **Get legacy address failed** There is no legacy address used for this specific asset |
| 1024 | 400, 404 | Wallet | **Get legacy address for an asset without one** The asset you're trying to get the legacy address for does not have one (for example, ETH) |
| 1025 | 400 | Asset, Vault, Wallet | **Usage of an unsupported asset** The asset you specified in your request is invalid. Please check it against the supported asset list |
| 1026 | 400 | Asset, Vault, Wallet | **Creation of a wallet that already exists** You've requested to create a wallet for an asset that already has a wallet in the vault account. Please check whether you're using the correct vault account and the correct asset |
| 1027 | 400 | Asset, Balance | **Requested max spendable amount for asset that doesn't support that request** You've requested to know the max spendable amount for an asset, which does not support this request. Verify you're using one of the assets according to the API docs |
| 1028 | 400 | Asset, Balance | **Max Spendable Amount invalid value** The parameters you provided for the request are invalid. Please verify you provided the correct type of values, as well as a valid asset and vault account ID |
| 1031 | 400 | Asset, Balance | **Get balance by assets** The request to balance of assets in all vault accounts is invalid, only one of `accountNamePrefix` and `accountNameSuffix` can be provided |
| 1032 | 400, 404 | Asset, Balance | **Get balances by assets or get balance for asset failed** The asset requested does not exist in the vault account |
| 1034 | 400 | Wallet | **Create testnet asset failed** You're requested to create a testnet asset on a workspace that does not have testnet support |
| 1035 | 400 | Asset | **Activate wallet failed** The request to activate the wallet failed. Please open a ticket to support |
| 1037 | 400 | Vault | **Get vault accounts endpoint is disabled** Workspaces created after May 2022 do not support the get vault accounts endpoint; use the paged request |
| 1038 | 400 | Wallet, Asset | **Adding a token without base asset** Before adding a token to the vault account, please create a base asset wallet |
| 1039 | 400 | Wallet, Asset | **Insufficient base asset for token wallet** Before creating a token asset, make sure you have sufficient base asset to cover token transactions |
| 1040 | 401 | Vault | **Unauthorized user to create vault account** The user who is trying to add a vault account does not have the proper permissions needed to create a vault account. Make sure you use the correct user |
| 1048 | 400 | Vault | **The vault account type is not supported by the workspace** You attempted to create/use a vault account with a type that isn’t enabled or recognized for your tenant (plan/feature flag/environment). Use a supported type (or omit it to use the default), or contact Fireblocks to enable the feature. |
| 1103 | 400 | Exchange, Fiat | **No such exchange/fiat account ID** The exchange or fiat account ID does not exist. Make sure you're using the correct one |
| 1105 | 400 | Exchange | **Exchange account for asset by ID does not exist** The exchange account's asset does not exist for the specified exchange account ID. Make sure you're using the correct exchange account ID and asset |
| 1106 | 400 | Exchange Transfers | **No such exchange account ID** The exchange account ID specified does not exist |
| 1108 | 408 | Exchange | **Exchange timeout when adding an account** We faced an internal timeout when trying to add the exchange account |
| 1111 | 400 | Exchange Transfers | **Exchange convert failed** Failed to perform a convert operation. Please check the message reply to understand the issue |
| | | | |
| 1202 | 400 | Internal Wallets | **Create internal wallet failed** Internal wallet name must be specified, not empty, and to not already exist in a different wallet |
| 1204 | 400 | Internal Wallets | **Get internal wallet by id failed** The internal wallet specified does not exist. Make sure you're querying the correct internal wallet ID |
| 1206 | 400 | Internal Wallets | **Delete internal wallet failed** Failed to delete the internal wallet. Please make sure you've specified the correct internal wallet parameters |
| 1208 | 400 | Internal Wallets | **Create an internal wallet failed** Failed to create an internal wallet. Please verify you've provided the correct parameters for the creation as per the API docs |
| 1209 | 400 | Internal Wallets | **Getting the wallet's asset failed** The internal wallet based on the ID and asset specified does not exist. Please make sure you're using the correct asset and wallet ID |
| 1212 | 400 | Internal Wallets | **Deleting specific asset from wallet failed** Please verify that you specified the correct wallet ID and asset ID for deletion |
| 1213 | 400 | Internal Wallets | **Create an unsupported asset address in a wallet** The asset you're trying to add to the wallet is not supported. Verify the asset you're trying to use |
| 1214 | 400 | Internal Wallets | **Create an asset from a different network in the wallet** The asset you're trying to add to the wallet is in a different network (mainnet or testnet), and your workspace does not support this network. Please verify the network of the asset and that your workspace correlates |
| 1215 | 400 | Internal Wallets | **Add an asset in a wallet that already has it** You're trying to add an asset to the internal wallet, but it already has this asset. Please make sure you're adding a new asset and not one that already exists |
| 1216 | 400 | Internal Wallets | **Add an asset with an invalid address to the wallet** You're trying to add an asset to the internal wallet, but the address does not match the asset's conventions. Please check the address you're trying to add |
| | | | |
| 1302 | 400 | External Wallets | **Create external wallet failed** External wallet name must be specified, not empty, and to not already exist in a different wallet |
| 1304 | 400 | External Wallets | **Get external wallet by Id failed** The external wallet requested does not exist. Please make sure you're using the correct wallet ID |
| 1306 | 400 | External Wallets | **Delete external wallet failed** Failed to delete the external wallet. Please make sure you've specified the correct external wallet parameters |
| 1308 | 400 | External Wallets | **Create an external wallet failed** Failed to create an external wallet. Please verify you've provided the correct parameters for the creation as per the API docs |
| 1309 | 400 | External Wallets | **Getting the wallet's asset failed** The external wallet based on the ID and asset specified does not exist. Please make sure you're using the correct asset and wallet ID |
| 1312 | 400 | External Wallets | **Deleting specific asset from wallet failed** Please verify that you specified the correct wallet ID and asset ID for deletion |
| 1313 | 400 | External Wallets | **Create an unsupported asset address in a wallet** The asset you're trying to add to the wallet is not supported. Verify the asset you're trying to use |
| 1314 | 400 | External Wallets | **Create an asset from a different network in the wallet** The asset you're trying to add to the wallet is in a different network (mainnet or testnet), and your workspace does not support this network. Please verify the network of the asset and that your workspace correlates |
| 1315 | 400 | External Wallets | **Add an asset in a wallet that already has it** You're trying to add an asset to the external wallet, but it already has this asset. Please make sure you're adding a new asset and not one that already exists |
| 1316 | 400 | External Wallets | **Add an asset with an invalid address to the wallet** You're trying to add an asset to the external wallet, but the address does not match the asset's conventions. Please check the address you're trying to add |
| | | | |
| 1351 | 400 | Contract Wallets | **Create contract wallet failed** Contract wallet name must be specified, not empty, and to not already exist in a different wallet |
| 1354 | 400 | Contract Wallets | **Get contract wallet by Id failed** The contract wallet requested does not exist. Please make sure you're using the correct wallet ID |
| 1356 | 400 | Contract Wallets | **Delete contract wallet failed** Failed to delete the contract wallet. Please make sure you've specified the correct contract wallet parameters |
| 1358 | 400 | Contract Wallets | **Create an contract wallet failed** Failed to create an contract wallet. Please verify you've provided the correct parameters for the creation as per the API docs |
| 1359 | 400 | Contract Wallets | **Getting the wallet's asset failed** The contract wallet based on the ID and asset specified does not exist. Please make sure you're using the correct asset and wallet ID |
| 1362 | 400 | Contract Wallets | **Deleting specific asset from wallet failed** Please verify that you specified the correct wallet ID and asset ID for deletion |
| 1363 | 400 | Contract Wallets | **Create an unsupported asset address in a wallet** The asset you're trying to add to the wallet is not supported. Verify the asset you're trying to use |
| 1364 | 400 | Contract Wallets | **Create an asset from a different network in the wallet** The asset you're trying to add to the wallet is in a different network (mainnet or testnet), and your workspace does not support this network. Please verify the network of the asset and that your workspace correlates |
| 1365 | 400 | Contract Wallets | **Add an asset in a wallet that already has it** You're trying to add an asset to the contract wallet, but it already has this asset. Please make sure you're adding a new asset and not one that already exists |
| 1366 | 400 | Contract Wallets | **Add an asset with an invalid address to the wallet** You're trying to add an asset to the contract wallet, but the address does not match the asset's conventions. Please check the address you're trying to add |
| | | | |
| 1401 | 400 | Transaction | **The operation requested is not supported** The operation argument that you provided in the create transaction is not supported. Please verify it's correct |
| 1402 | 400 | Transaction | **Source balance insufficient** The balance of the source account is not sufficient to cover the transaction |
| 1403 | 400 | Transaction | **Destination balance is insufficient** Some blockchains (such as NEAR) require a minimal amount of assets to be activated. You tried to pass less than the minimal amount to a vault account that does not have such a wallet, thus the wallet can't be created. Please verify you're transferring a sufficient amount, or have the destination create a wallet and deposit a sufficient amount of base asset |
| 1404 | 400 | Transaction | **Invalid Peer type** When creating the transaction, verify that the type of the source and destination are valid and one of the defined enums in the API docs |
| 1405 | 404 | Transaction | **No such transaction** The transaction ID you used to try and get the transaction object is invalid and was not found in the system. Make sure you're using the correct transaction ID |
| 1406 | 400 | Transaction | **Failed to cancel transaction** Cancelling the transaction failed for some reason. Please open a support ticket |
| 1407 | 400 | Transaction | **User can't create a transaction** The user trying to create the transaction does not have sufficient permissions to do so. Please verify the user's permission level and that you're using the correct user |
| 1408 | 400 | Transaction | **Paged get tried to change direction** When getting transactions in a paged fashion, you can only go in one direction (forward or backward) and can't change direction mid execution. Make sure you're only querying the information in one direction |
| 1409 | 400 | Transaction | **Transaction creation parameters are invalid** Here is a list of items to check: 1. The asset type is valid and is supported 2. You can only specify `destination` or `destinations`, not both 3. For OTA, you must specify the address 4. Typed messages only supported BTC, LTC, DASH, and ETH 5. AML Customer reference ID can only use `-_:` and alpha-numeric 6. You can not have more than 650 destinations in the `destinations` parameters 7. Invalid `nodeControls` parameters |
| 1410 | 400 | Transaction | **Transaction destination wallet does not exist** The destination is sending the transaction to an external/internal/contract wallet by an ID, but the ID specified does not exist. Check that the ID you're using is correct |
| 1411 | 400 | Transaction | **Transaction destination wallet asset does not exist** The destination is sending the transaction to an external/internal/contract wallet by an ID, but the asset used in the transaction does not exist. Check that the asset has an address in the wallet ID |
| 1412 | 400 | Transaction | **Transaction destination wallet address is suspended** The destination is an external/internal/contract wallet that has not been approved yet. Approve it and try again |
| 1421 | 400 | Transaction | **Confirmation number change failed** Changing the number of confirmations for the transaction failed. Please verify that the transaction exists; otherwise, open a support ticket |
| 1422 | 400 | Transaction | **Confirmation number change failed** Changing the number of confirmations for the transaction by transaction hash failed. Please make sure you're using the correct transaction hash; otherwise, open a support ticket |
| 1423 | 400, 404 | Transaction | **Get transaction by transaction hash failed** Couldn't find a transaction with the specified transaction hash. Please verify the transaction hash and try again |
| 1424 | 400 | Transaction, Network Connection | **Destination address invalid** Here is a list of parameters to check: 1. The address used is invalid for the asset you're using 2. The target (in case of a network transfer) does not contain a wallet for the specified asset 3. You're using the internal/external/contract wallet for a different workspace than the one you're performing the transaction on 4. You are trying to send a transaction to a network connection that you do not have 5. You're using `destinations` and one of the destinations is a network connection - this is not supported |
| 1425 | 400 | Transaction | **Missing a tag** You're trying to send a transaction to an address that requires a tag. Please verify you're providing a tag |
| 1426 | 400 | Transaction | **Unfreeze failed** You tried to unfreeze a transaction, but it was neither rejected nor failed by AML; therefore, it can't be unfrozen |
| 1427 | 400 | Transaction | **Source type of transaction is invalid** You tried to send a transaction with the source being invalid. Verify that the source is one of: `VAULT_ACCOUNT`, `EXCHANGE_ACCOUNT`, `GAS_STATION` or `FIAT_ACCOUNT` |
| 1428 | 400 | Transaction | **Destination of transaction is invalid** The destination type of one of the destinations is not one of the defined enums in the API docs. Verify that it is correct and try again |
| 1429 | 400 | Asset, Transaction | **Validate address failed** The asset you tried to use for the `validate_address` endpoint is not supported |
| 1431 | 400 | Asset, Transaction | **Validate address didn't find an address** The address provided to the `validate_address` endpoint is invalid. |
| 1432 | 400 | Transaction | **Invalid amount specified** The amount must be a number or a numeric string; verify it is so |
| 1433 | 400 | Transaction | **Invalid tag specified** The tag/memo specified does not comply with the rules of the blockchain. Verify the tag/memo is valid |
| 1434 | 400 | Transaction | **Freeze failed** or **Cannot freeze** Depending on the context of the error code, you will see one of the above responses. Typically, freezing fails because of one of the following reasons: - The transaction is not in either the **Confirming** or the **Completed** status. - An input is not available. - There is an insufficient balance for freezing. - The transaction direction or asset type is not supported for freezing. |
| 1435 | 400 | Transaction | **List unspent for unknown asset** You tried to get the unspent inputs (UTXO) for an asset that does not have such values, or no UTXOs exist |
| 1437 | 400 | Exchange, Transaction | **Unsupported transfer** Direct transfers (Exchange to OTA) is not supported for the Kraken exchange |
| 1438 | 400 | Transaction | **External Tx ID Duplicate** The `externalTxId` specified in the transaction was already used in the past. Please use a different one |
| 1439 | 404 | Transaction | **No such External Tx ID** The external Tx ID used does not exist. Please verify the external Tx ID you're using |
| 1440 | 400 | Transaction | **Drop for unsupported blockchain** You're trying to run a drop transaction request for a blockchain that is not `ETC` or `ETH` |
| 1441 | 400 | Transaction | **Replace by fee too low** You're attempting to perform an RBF transaction, but the gas price you specified is too low. Please check it and submit a higher gas price |
| 1443 | 400 | Transaction | **Too late for RBF** You're trying to replace by fee, but the transaction was already mined |
| 1445 | 403 | Transaction | **User can't freeze** The user who is trying to perform a freeze does not have the permissions to perform this. Check the user's permissions and that you're using the correct user |
| 1446 | 403 | Transaction | **User can't unfreeze** The user who is trying to perform an unfreeze does not have the permissions to perform this. Check the user's permissions and that you're using the correct user |
| 1448 | 400 | Transaction | **Fee payer is not allowed for asset** You're trying to define a fee payer for an asset that does not support it. Please check whether the asset you're using allows for a fee payer configuration |
| 1449 | 400 | Transaction | **Fee payer can't pay** The defined fee payer does not have a wallet with the base asset to pay the fee. Verify that you specified the correct fee payer and check that it contains a base asset wallet with a sufficient amount to pay for the transaction |
| 1450 | 400 | Transaction | **Transactions are blocked for this blockchain** We have temporarily disabled transactions for the specified blockchain. Check the [status page](https://status.fireblocks.com) for more details |
| 1451 | 400 | Transaction | **Transaction confirmations don't match Fireblocks restrictions** Fireblocks requires a specific number or a minimum number of confirmations for some blockchains. Manually setting confirmations for a transaction must meet these requirements. For more, see [Deposit Control & Confirmation Policy](https://support.fireblocks.io/hc/en-us/articles/360013034359) . |
| 1454 | 400 | Transaction | **Missing license for creating a MEV protected transaction** This feature is not enabled in your workspace, and you should contact your Customer Success Manager or the Fireblocks Support team |
| 1455 | 400 | Transaction, Gasless (meta-tx) | **Missing Gasless configuration** Gasless transactions aren’t set up for this workspace/asset. Configure Gasless (relayer/fee payer) or send a standard transaction. |
| 1502 | 400 | Asset, Transaction | **Trying to use a deprecated asset** The asset specified in the transaction is deprecated and can't be used. Please check the asset and use a different one |
| 1503 | 400 | Asset, Balance, Transaction | **Unsupported asset** The asset specified is not supported. Please check the asset you've specified |
| | | | |
| 1601 | 404 | Network Connection | **Network Connection Id does not exist** The network connection you're trying to query by ID does not exist. Please check the ID you're using |
| 1603 | 400 | Network Connection | **Delete Network Connection but id is not specified** The delete network connection request does not have a `connectionId` parameter specified, please make sure one is provided and exists |
| 1604 | 400 | Network Connection | **Create a network connection failed** The network connection creation failed. Check the error message for more information and open a support ticket if insufficient |
| 1605 | 404 | Network Connection | **Get Network Connection for unknown id** The network connection ID provided could not be found. Please verify you're using the correct ID |
| 1606 | 404 | Network Connection | **Delete network connection for unknown id** The network connection ID provided could not be found. Please verify you're using the correct ID |
| 1607 | 400 | Network Connection | **Setting the routing policy for a network connection failed** Verify that you used the proper parameters for the call |
| 1608 | 404 | Network Connection | **Set routing policy for an unknown network connection id** The ID you provided for the call was not found. Verify you're using the correct ID and it exists |
| 1609 | 400 | Network Connection | **Validating routing policy failed** The attempt to validate whether the network connection's routing will lead to a third party or not for a given asset failed. Please verify you passed the correct parameters and open a support ticket if needed |
| 1610 | 404 | Network Connection | **Validating routing policy for an unknown network connection id** The ID you provided for the call was not found. Verify you're using the correct ID and it exists |
| 1611 | 403 | Network Connection | **No multiple network profiles** The workspace does not support multiple network profiles. Contact us to request support |
| 1612 | 422 | Network Connection | **The counterparty rejected the connection request** The Counterparty has to send a connection request. |
| 1613 | 422 | Network Connection | **The counterparty is already an active connection** The network connection already exists |
| 1614 | 422 | Network Connection | **The connection is pending approval** You can request approval from the workspace admins |
| 1615 | 422 | Network Connection | **The connection is pending approval** You can request approval from your counterparty |
| 1616 | 403 | Network Connection | **Network connection cannot be deleted** There is an active Smart Transfers ticket with the connection, which must be closed before deleting the Network connection |
| 9007 | 404 | Network Connection | **The Fireblocks Network is not activated in the workspace** Reach out to Fireblocks Support to resolve this |
| 9011 | 403 | Network Connection | **Cannot delete network ID** The default ID cannot be deleted before making another ID the default |
| 9012 | 403 | Network Connection | **Network profile cannot be deleted** It is the last remaining ID. There must be at least one Network profile per tenant |
| 9013 | 403 | Network Connection | **Network profile cannot be deleted** There is an active Smart Transfers ticket with the Network profile, which must be closed before deleting the Network profile |
| 9014 | 422 | Network Connection | **Invalid network name** The name cant contain the `<` and `>` characters |
| 9015 | 403 | Network Connection | **Could not add an additional network ID** Contact Fireblocks Support to activate the feature |
| 9016 | 422 | Network Connection | **The selected asset is not supported on the Fireblocks Network** Reach out to Fireblocks Support to resolve this |
| 9017 | 422 | Network Connection | **Invalid routing policy > non-custom scheme** A routing destination type or ID is required |
| 9018 | 422 | Network Connection | **Invalid routing policy > destination ID incompatible with selected asset.** Make sure you are sending a supported asset |
| 9019 | 422 | Network Connection | **Invalid routing policy > selected routing policy is not allowed** Select a valid [routing policy](https://support.fireblocks.io/hc/en-us/articles/5671826748316-Flexible-Network-Routing) |
| 9020 | 422 | Network Connection | **Invalid routing policy > selected routing destination is not supported** Select one of the [supported destination](https://support.fireblocks.io/hc/en-us/articles/5671826748316-Flexible-Network-Routing) s |
| 9021 | 422 | Network Connection | **Invalid routing policy > selected crypto destination is not supported** Select a vault or a connected exchange account. |
| 9022 | 422 | Network Connection | **Invalid routing policy > third-party account provided is invalid** Make sure you are adding a supported third-party destination |
| 1706 | 400 | FIAT Accounts | **FIAT Account id provided is unknown** The exchange account ID you provided was not found. Please verify you're using the correct account ID |
| 1708 | 400 | FIAT Accounts | **FIAT Account id provided is unknown** The exchange account ID you provided was not found. Please verify you're using the correct account ID |
| | | | |
| 1901 | 400 | Asset, Transaction | **Estimate fee for unknown asset** The asset you specified for the estimate fee call is unknown. Please make sure you're using a supported and known asset |
| 1902 | 400 | Asset, Transaction | **Estimate fee for an invalid asset** The asset you specified does not support the estimate fee call. Please make sure you're using a supported and allowed asset |
| 1904 | 400 | Asset, Transaction | **Estimate fee with invalid parameters** Make sure when calling the estimate fee endpoint that you do not have `destination` and `destinations` parameters both used, and that the `source` parameter is a vault account |
| 1905 | 400 | Asset, Transaction | **Estimate fee failed due to insufficient funds** The funds you have in the source vault are not sufficient, and thus the estimate fee call failed. Make sure you have sufficient base asset in the source vault and try again |
| 1907 | 400 | Asset, Transaction | **Estimate fee failed due to smart contract error.** The transaction reverted during its simulation as part of estimating the gas limit. There are three ways to properly handle this error: 1. Initiate the transaction again while using different parameters. 2. Try using a different vault to perform the transaction. 3. Read the contract’s source code to better understand the error. |
| 1908 | 400 | Asset, Transaction | **Estimate fee failed since the amount you are sending is too small** The transaction failed since the amount you tried to send was not enough to pass our balance validation and internal tx checks. Confirm the transfer amount is above the required minimum for this blockchain or more than the transaction fees necessary before resubmitting the transaction. Minimum transfer amounts vary per blockchain. Known minimums: Bitcoin (BTC) - 546 satoshi Cardano (ADA) - 1 ADA + applicable transaction fees |
| 1909 | 400 | Asset, Transaction | **Estimate failed due to insufficient gas fees** The transaction failed since you didn't have enough gas fees. Make sure you have sufficient gas money and try again. |
| 2002 | 400 | Public Key | **Public key could not be found** Make sure that the information you provided to the public key query is valid, and a wallet for this asset exists in the specified vault account |
| | | | |
| 2101 | 400 | Gas Station | **Invalid gas station parameters** When editing the gas station configuration, make sure you provide both `gasCap` and `gasThreshold` |
| 2110 | 400 | Gas Station | **Invalid asset for gas station** When editing the gas station configuration, the asset you specified is not supported for this operation. Make sure you're using a supported and valid asset |
| | | | |
| 2201 | 400 | Balance, Private Ledger | **Lock/Release allocation for unsupported asset** The asset you specified in the lock or release allocation call is not supported. Make sure it is a valid and supported asset |
| 2202 | 400 | Balance, Private Ledger | **Lock/Release Allocation for unknown account** The virtual account you specified does not exist. Please make sure you're using a valid virtual account that exists |
| 2204 | 400 | Private Ledger, Off-Exchange | **Allocation not allowed** The vault account you specified does not have off-exchange set up; therefore, locking allocation is not allowed. Make sure you have off-exchange set up and then try again |
| 2205 | 400 | Private Ledger, Balance | **Insufficient amount for fee in allocation** The call you're trying to perform requires that a sufficient amount for the fee bank be allocated. The allocation amount you've specified does not meet this demand. Please increase the allocation amount |
| | | | |
| 2501 | 400 | Webhooks | **Resend webhook for specific tx id failed** Make sure one of the parameters `resendCreated` and `resendUpdated` is marked as true, and try again |
| | | | |
| 2602 | 404 | Off-Exchange | **Unknown virtual account id** The virtual account ID specified does not exist. Make sure you're using a virtual account ID that exists |
| 2604 | 404 | Off-Exchange | **Unknown virtual account id** The virtual account ID specified does not exist. Make sure you're using a virtual account ID that exists |
| | | | |
| 2702 | 403 | Users | **Insufficient permissions for operation** The user who is trying to perform this call does not have sufficient permissions for it. Make sure you're using the correct user and that they have the proper permissions to view the user list |
| | | | |
| 2814 | 400 | Fee Payer | **Fee Payer not configured** No fee payer was configured for this workspace. Configure one and try again |
| 2816 | 400 | Fee Payer | **Asset wallet does not exist** You've attempted to set a fee payer by specifying a vault account and asset; however, the specified asset does not have a wallet in the specified vault account. Please create a wallet in the specified vault account and fund it, then try again |
| 2817 | 400 | Fee Payer | **Non-base asset** You've specified a fee payer asset that is not the base asset. This is not allowed. Please specify the base asset and try again |
| 2818 | 400 | Fee Payer | **Unsupported asset** You've tried to set a fee payer for an asset that is not supported. Please verify you're using a supported asset and try again |
| | | | |
| 2902 | 403 | Audits | **Getting audits is not allowed** The user trying to get the audits is not allowed to due so due to a permissions matter. Make sure that the user has the proper permissions and that you're using the correct user |
| | | | |
| 3001 | 404 | Smart Transfers | **Ticket not found** Fireblocks could not find the Smart Transfer ticket. |
| 3002 | 403 | Smart Transfers | **Ticket should be open** The attempted action can only be performed on an open Smart Transfer ticket. |
| 3003 | 403 | Smart Transfers | **Ticket should be draft** The attempted action can only be performed on a Smart Transfer ticket draft. |
| 3004 | 403 | Smart Transfers | **Ticket should be draft or open** The attempted action can only be performed on an open Smart Transfer ticket or a Smart Transfer ticket draft. |
| 3005 | 403 | Smart Transfers | **Ticket action allowed for owner** Only the Smart Transfer ticket creator can perform the attempted action. |
| 3006 | 403 | Smart Transfers | **Ticket cancel can be done by payer** You cannot close the Smart Transfer ticket because the connection has already funded it. |
| 3007 | 403 | Smart Transfers | **Ticket terms are missing** You must define all required terms before you can open the Smart Transfer ticket. |
| 3008 | 403 | Smart Transfers | **Ticket expiration date passed** The Smart Transfer ticket has expired. |
| 3009 | 400 | Smart Transfers | **Term not found** No Smart Transfer ticket term matches your search criteria. |
| 3010 | 403 | Smart Transfers | **Term should be created status** The submitted or updated Smart Transfer ticket term is incorrect. |
| 3011 | 403 | Smart Transfers | **Term should be funded status** Only a funded Smart Transfer ticket can be closed. |
| 3012 | 403 | Smart Transfers | **Term should be funding failed status** The attempt to fund the Smart Transfer ticket failed. |
| 3013 | 403 | Smart Transfers | **Term amount required** You must enter a term amount before you can open a Smart Transfer ticket. |
| 3014 | 403 | Smart Transfers | **Term asset required** You must select an asset before you can open a Smart Transfer ticket. |
| 3015 | 403 | Smart Transfers | **Term asset not supported** Fireblocks does not support the selected asset for Smart Transfer tickets. |
| 3016 | 403 | Smart Transfers | **Term from to should be different** The Smart Transfer ticket must include two different connections. |
| 3017 | 403 | Smart Transfers | **Term amount is different than fund amount** The entered fund amount does not match the term amount on the Smart Transfer ticket. |
| 3018 | 403 | Smart Transfers | **Term asset is different than fund asset** The asset selected for funding does not match the term's asset on the Smart Transfer ticket. |
| 3019 | 403 | Smart Transfers | **Counterparty not found** Fireblocks could not find the counterparty connection. |
| 3020 | 403 | Smart Transfers | **Network does not belong to tenant** You can only open a Smart Transfer ticket using a Fireblocks Network profile belonging to you. |
| 3021 | 403 | Smart Transfers | **Networks not connected** The selected counterparty is not a Fireblocks Network connection. |
| 3022 | 403 | Smart Transfers | **Term should be created or funding failed status** The Smart Transfer ticket has already been funded or is currently being funded. |
| 3023 | 403 | Smart Transfers | **Term transaction can be made by counterparty of term who should pay** Your Fireblocks Network profile cannot fund the Smart Transfer ticket. |
| 3024 | 403 | Smart Transfers | **Network connection does not belong to peers** The Fireblocks Network connection funding the Smart Transfer ticket does not match the connection listed on the term. |
| 3025 | 403 | Smart Transfers | **Transaction fee and fee level defined** You cannot set a fee level (low, medium, or high) and specify a custom fee at the same time. |
| 3027 | 403 | Smart Transfers | **Tickets can have at most two terms** Smart Transfer tickets can only have two transfer terms. |
| 3029 | 403 | Smart Transfers | **Network doesn't have FF enabled** The Fireblocks Network connection does not use the Smart Transfer feature. |
| 3030 | 400 | Smart Transfers | **Ticket missing expire in** You must set an expiration date before you can open a Smart Transfer ticket. |
| 3031 | 403 | Smart Transfers | **Ticket creator must receive asset** You can only open a Smart Transfer ticket for receiving assets. |
| 3101 | 404 | Trading | **Provider Not Found** The trading provider you requested does not exist or is not available. |
| 3102 | 403 | Trading | **Terms Approval Not Supported** This provider does not support terms of service approval. |
| 3103 | 400 | Trading | **On-Chain Swap Required** Both assets must be on the same blockchain network for this trade. |
| 3104 | 400 | Trading | **Cross-Chain Swap Required** Input and output assets must be on different chains. |
| 3105 | 400 | Trading | **Unsupported Input Blockchain** The input asset blockchain is not supported by this provider. |
| 3106 | 400 | Trading | **Unsupported Output Blockchain** The output asset blockchain is not supported by this provider. |
| 3107 | 400 | Trading | **Unsupported Trading Pair** Input and output assets pair is not supported with this provider. |
| 3108 | 400 | Trading | **Settlement Required** This trade requires settlement information to be provided. |
| 3109 | 400 | Trading | **DVP Settlement Source/Destination Invalid** Source and destination accounts must be of type vault accounts. |
| 3110 | 400 | Trading | **Settlement Pair Invalid** The source and destination must be the same vault account. |
| 3111 | 400 | Trading | **DeFi Side Not Supported** DeFi trades only support selling (not buying) at this time. |
| 3112 | 400 | Trading | **Execution Type Not Supported** This type of trade execution is not supported. |
| 3114 | 404 | Trading | **Quote Not Available** No pricing quote is available for this trade at the moment. |
| 3115 | 400 | Trading | **Quote Expired** The price quote has expired or is no longer valid. please try creating a new quote. |
| 3116 | 404 | Trading | **Order Not Found** The trading order you requested does not exist. |
| 3117 | 404 | Trading | **Source Account Not Found** The account address required to extract funds was not found. |
| 3118 | 404 | Trading | **Provider Account Not Found** The specified provider account was not found. |
| 3119 | 403 | Trading | **Provider Account Not Active** The specified provider account is not active |
| 3120 | 403 | Trading | **Terms of Service Approval Required** You must approve the terms of service before trading with this provider. |
| 3121 | 400 | Trading | **Quotes Unsupported** The provider does not support quote operation. |
| 3122 | 403 | Trading | **Unmanaged Wallet Approval Required** Please approve the unmanaged wallet request before sending the Order |
| 3123 | 400 | Trading | **Rates unsupported** The provider does not support rate operation |
| 9001 | 400 | Wallet | **Invalid customer reference id** The customer reference ID specified is invalid. Make sure it only consists of `\-\_:a-zA-Z0-9` |
| 9003 | 400 | Transaction | **Invalid idempotency key length** The idempotency key must be no longer than 40 characters. Please verify that if you've specified one, it has a proper length **Idempotency key used on internal error request, returning bad request** This operation doesn't support the usage of the same idempotency key after an internal error |
| 9004 | 400 | Vault | **An existing vault account by the same name already exists** Please try to create a different vault account using a different name. |
| 9005 | 400 | Transaction | **A transaction with the same idempotency key is in progress** Please wait until the previous transaction for this idempotency key is done before issuing a new one |
| 9006 | 400 | Network Connection | **Missing required parameter in request body** The request you've sent is missing the `isDiscoverable` parameter in the body, make sure it exists and is a boolean, then try again |
| 9007 | 404 | Network Connection | **Unknown network id** The network ID specified could not be found. Please verify it exists and try again |
| 9009 | 400 | Network Connection | **Parameters passed are invalid** The parameters passed to the `set_routing_policy` call are invalid, please make sure they are correct and conform to the API docs, then try again |
| 11001 | 400 | All | **The specified vault account is invalid** Please make sure that the vault account you've specified is correct, valid, and exists |
| 12000 | 400 | All | **Cloud provider issue** There is an issue with one of our cloud providers. Please check the [status page](https://status.fireblocks.com) for more details |
## 5XX Error Codes
### 10XX codes
| Error Code | Feature | Description |
| ---------- | -------------- | ------------------------------------------------ |
| 1001 | Vault | Get Vault accounts paged failed |
| 1003 | Vault | Create vault account failed |
| 1005 | Vault | Get vault account failed |
| 1007 | Asset, Balance | Get balance for vault account and asset failed |
| 1009 | Wallet, Asset | Create wallet for asset failed |
| 1011 | Wallet | Adding a new address failed |
| 1012 | Wallet | Getting the addresses for the given asset failed |
| 1014 | Vault | Renaming a vault account failed |
| 1018 | Vault | Hide vault account failed |
| 1021 | Vault | Unhide vault account failed |
| 1029, 1030 | Asset, Balance | Get max spendable amount failed |
| 1033 | Asset | Get balance for assets or specific asset failed |
| 1036 | Asset | Fetching max BIP44 index used failed |
### 11XX codes
| Error Code | Feature | Description |
| ---------- | ------------------ | ------------------------------------------------------------------ |
| 1101 | Exchange, Fiat | Failed to get exchange/fiat accounts |
| 1102 | Exchange | Failed to get exchange account by ID |
| 1104 | Exchange | Failed to get exchange account by ID and asset |
| 1107 | Exchange Transfers | Failed to perform an exchange account transfer (internal transfer) |
| 1110 | Exchange Transfers | Convert operation failed |
### 12XX codes
| Error Code | Feature | Description |
| ---------- | ---------------- | -------------------------------------------- |
| 1201 | Internal Wallets | Failed to get internal wallets |
| 1202 | Internal Wallets | Failed to create an internal wallet |
| 1203 | Internal Wallets | Failed to get internal wallet by ID |
| 1205 | Internal Wallets | Failed to delete internal wallet |
| 1207 | Internal Wallets | Failed to create an internal wallet by asset |
| 1210 | Internal Wallets | Failed to get wallet by asset and wallet ID |
| 1211 | Internal Wallets | Failed to delete specific asset from wallet |
### 13XX codes
| Error Code | Feature | Description |
| ---------- | ---------------- | -------------------------------------------- |
| 1301 | External Wallets | Failed to get external wallets |
| 1302 | External Wallets | Failed to create an external wallet |
| 1303 | External Wallets | Failed to get external wallet by ID |
| 1305 | External Wallets | Failed to delete an external wallet |
| 1307 | External Wallets | Failed to create an external wallet by asset |
| 1310 | External Wallets | Failed to get wallet by asset and wallet ID |
| 1311 | External Wallets | Failed to delete specific asset from wallet |
| 1350 | External Wallets | Failed to get external wallets |
| 1352 | External Wallets | Failed to create an external wallet |
| 1353 | External Wallets | Failed to get external wallet by ID |
| 1355 | External Wallets | Failed to delete external wallet |
| 1357 | External Wallets | Failed to create an external wallet by asset |
| 1360 | External Wallets | Failed to get wallet by asset and wallet ID |
| 1361 | External Wallets | failed to delete specific asset from wallet |
### 14XX codes
| Error Code | Feature | Description |
| ---------- | ------------------ | -------------------------------------------- |
| 1404 | Transaction | Transaction creation or get failed |
| 1430 | Asset, Transaction | Validate destination address endpoint failed |
| 1436 | Transaction | List unspent inputs (UTXO) failed |
| 1444 | Transaction | Failed to get the transactions list |
| 1447 | Transaction | Failed to get transaction by external Tx ID |
### 15XX codes
| Error Code | Feature | Description |
| ---------- | ------- | --------------------------- |
| 1501 | Asset | Get supported assets failed |
### 17XX codes
| Error Code | Feature | Description |
| ---------- | ------------- | ----------------------------- |
| 1702 | Fiat Accounts | Get fiat account by ID failed |
| 1707 | Fiat Accounts | Redeem funds to DDA failed |
| 1709 | Fiat Accounts | Deposit funds from DDA failed |
### 19XX codes
| Error Code | Feature | Description |
| ---------- | ------------------ | ------------------------------- |
| 1903 | Asset, Transaction | Estimate fee calculation failed |
### 20XX codes
| Error Code | Feature | Description |
| ---------- | ---------- | ------------------------------------- |
| 2001 | Public Key | Getting public key information failed |
### 21XX codes
| Error Code | Feature | Description |
| ---------- | ---------------------- | -------------------------------------- |
| 2102 | Fireblocks Gas Station | Setting gas station information failed |
### 22XX codes
| Error Code | Feature | Description |
| ---------- | ----------------------- | --------------------------- |
| 2203 | Balance, Private Ledger | Lock allocation call failed |
### 25XX codes
| Error Code | Feature | Description |
| ---------- | ------- | --------------------- |
| 2501 | Webhook | Resend webhook failed |
### 26XX codes
| Error Code | Feature | Description |
| ---------- | ------------ | ------------------------------------------------------------- |
| 2601 | Off-Exchange | Get off-exchange failed |
| 2603 | Off-Exchange | Couldn't settle off-exchange with provided virtual account ID |
| 2605 | Off-Exchange | Failed to get off-exchange with specified ID |
### 27XX codes
| Error Code | Feature | Description |
| ---------- | ------- | --------------------------------- |
| 2701 | Users | Failed to get users for workspace |
### 28XX codes
| Error Code | Feature | Description |
| ---------- | --------- | ------------------------------------------- |
| 2813 | Fee Payer | Failed to get fee payer |
| 2815 | Fee Payer | Setting the fee payer failed |
| 2819 | Fee Payer | Deleting the fee payer configuration failed |
### 29XX codes
| Error Code | Feature | Description |
| ---------- | ------- | -------------------- |
| 2901 | Audits | Failed to get audits |
# API Idempotency
Source: https://developers.fireblocks.com/reference/api-idempotency
The Fireblocks API supports idempotent requests (multiple requests which have the same result as making a single request). This is helpful when you don’t get a response or the API call isn’t completed successfully.
## Idempotency key
> **Notes**
>
> * You can use idempotency keys with **POST** requests. Using `Idempotency-Key` in your request header for **GET** and **DELETE** will not work as they are inherently idempotent.
> * The \`\` value in your idempotent request can have a maximum of 40 characters.
To submit an idempotent request, you must add `Idempotency-Key: ` to the header of your POST request.
Resubmission of the same request with the same idempotency key will not trigger the same operation, but will instead return the original response. This ensures a transaction request with the same idempotency key is not executed multiple times if you try to re-submit it due to network errors or delays experienced for a prior submission.
Fireblocks stores the responses for all requests with the `Idempotency-Key` header and resends them for every request with the same idempotency key for 24 hours. After 24 hours, you will need a new key.
## Transaction Idempotency
When creating transactions, Fireblocks strongly recommends using the `externalTxId` parameter in the [Create Transaction API](/reference/create-transactions) call. This parameter ensures that the transaction is idempotent. If another transaction request is made with the same `externalTxId` value, it will be rejected with an HTTP 400 code an [error message](/reference/api-responses#:~:text=for%20Kraken%20exchange-,1438,-400) .
Learn more about the `externalTxId` parameter [here](/docs/manage-withdrawals-at-scale#idempotent-transactions)
# API Overview
Source: https://developers.fireblocks.com/reference/api-overview
## REST API
Fireblocks offers a robust REST API that enables developers to leverage Fireblocks' capabilities programmatically. Our REST API serves as the foundation for all Fireblocks SDKs.
If you prefer to work directly with the Fireblocks API, read our [REST API Guide](/reference/rest-api-guide-1).
To practice with our API before implementing any code, read the [Postman Guide](/reference/explore-postman-collection) containing the pre-defined API endpoints.
## Language-specific SDKs & guides
Fireblocks supports and maintains SDKs in JavaScript and Python to help you interact with the Fireblocks API. We also offer guides for languages in which we don't have an active SDK.
These guides provide you with a simple example to get you started and quickly pass the first hurdles of securely signing API requests:
* [Typescript SDK](/reference/typescript-sdk)
* [Python SDK](/reference/new-python-sdk)
* [Java SDK](/reference/java-sdk)
## Need help deciding which language to use?
Use the following decision tree to help you decide which Fireblocks SDK is best for your use case.
# Web3/Smart Contract
Fireblocks offers Web3 connector SDKs for developers who use a base library as part of their tech stack and want Fireblocks to act as the underlying wallet and security layer:
* [EVM Web3 Provider](/reference/evm-web3-provider): Learn about using `ethers.js`, `web3.js` or `web3.py` with Fireblocks as the Web3 Provider.
# Additional Tools
* [Fireblocks Hardhat Plugin](https://github.com/fireblocks/hardhat-fireblocks) - An easy-to-use plugin to enable Fireblocks signing for smart contract deployment using Hardhat. More information at [Fireblocks Hardhat plugin guide](/reference/hardhat-plugin).
* [Fireblocks Local JSON RPC](https://github.com/fireblocks/fireblocks-json-rpc) - A locally running EVM JSON RPC module that uses the Web3 Provider to use Fireblocks as the signing mechanism. This allows you to plug Fireblocks into any of the tools that require a JSON RPC URL, including different development and deployment tools. More information at [Fireblocks Local JSON RPC Guide](/reference/evm-local-json-rpc).
# Webhooks
Webhook notifications allow you to get push notifications for events that happen in your Fireblocks workspace directly to an HTTP webhook URL of your choice. This saves you the need to constantly check the API for updates.
Read more at [Configure Webhooks](/reference/configure-webhook-urls).
# Approve configuration changes
Source: https://developers.fireblocks.com/reference/approve-configuration-changes
## Configuration Approval Callback
`POST /v2/config_change_sign_request`
This request expects a [CallbackResponse](/reference/response-object) object from the callback handler. If the callback handler does not respond within 30 seconds, Fireblocks fails the request. If your callback handler can't respond within 30 seconds, you can use the [retry mechanism](/reference/response-object) by responding with `RETRY`.
***
## Request parameters
| Parameter | Type | Description |
| --------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| requestId | string | A unique identifier of this request. It must be returned in the response. |
| type | string | The type of configuration request: `UNMANAGED_WALLET`, `EXCHANGE`, `POLICY_APPROVAL`,`FIAT_ACCOUNT`, `ADD_USER`, `RE_ENROLL_DEVICE`, `ENABLE_ONE_TIME_ADDRESS`, `CHANGE_QUORUM_THRESHOLD`, `ADD_NETWORK_CONNECTION`, `SET_NETWORK_CONNECTION_ROUTING_POLICY`, `SET_NETWORK_ID_POLICY`, `UPDATE_APPROVAL_GROUP_MAPPING`, and `USERS_GROUP_APPROVAL` |
| extraInfo | object | Additional information about the request, depending on the type: For `UNMANAGED_WALLET`, this is an [AddressInfo](#addressinfo) object. For `EXCHANGE` or `FIAT_ACCOUNT`, this is a [ThirdPartyInfo](#thirdpartyinfo) object. |
***
## Type descriptions
| Type | Description |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------- |
| UNMANAGED\_WALLET | An event that involves address whitelisting |
| EXCHANGE | An event that involves adding an exchange to your workspace |
| FIAT\_ACCOUNT | An event which involves adding a Fiat account to your workspace |
| ADD\_USER | An event that involves adding a user to your workspace |
| RE\_ENROLL\_DEVICE | An event where an admin re-enrolls a mobile device for one of the users |
| ENABLE\_ONE\_TIME\_ADDRESS | An event which involves enabling a particular transaction to a one-time address in the workspace |
| CHANGE\_QUORUM\_THRESHOLD | An event where the admin updates the quorum threshold |
| ADD\_NETWORK\_CONNECTION | An event of adding a Fireblocks Network new connection |
| SET\_NETWORK\_CONNECTION\_ROUTING\_POLICY | An event where the admin configures the routing policy for each network connection |
| SET\_NETWORK\_ID\_POLICY | An event of setting up the Fireblocks Network *Network ID* in case its profile is not discoverable |
| UPDATE\_APPROVAL\_GROUP\_MAPPING | An event involving gathering a list of approvers for a particular admin operation |
| USERS\_GROUP\_APPROVAL | An event that involves approving a new user group in your workspace |
| POLICY\_APPROVAL | An event that involves updating the Transaction Authorization Policy |
***
## Data objects
### AddressInfo
The AddressInfo object contains additional information for whitelisting a destination address.
| Parameter | Type | Description |
| ---------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| subType | string | `INTERNAL` - Internal Wallets are addresses you control outside your Fireblocks workspace. Internal addresses display their current balance and are included in your workspace's total billable address count. `EXTERNAL` - External Wallets are addresses managed by your clients and counterparties. `CONTRACT` - Contract Wallets are addresses of smart contracts you want to interact with. Currently, this only applies to smart contracts on EVM-compatible blockchains. |
| walletName | string | The name of the internal, external, or contract wallet you want to approve adding an address to. |
| walletId | string | The ID of the internal, external, or contract wallet that you want to approve adding an address to. |
| asset | string | The ID of the asset to add to this wallet. Use [GET supported assets](/api-reference/blockchains-&-assets/list-assets-legacy) request to retrieve more information about an asset. |
| address | string | The asset deposit address requested to be added to the wallet. |
| tag | string | Destination address tag for Ripple; destination memo for EOS, Stellar, Hedera, & DigitalBits; destination note for Algorand; bank transfer description for fiat providers. - *Note:*\* For Stellar, the memo must be a string representation of an integer between “0” and “2147483647”. Setting the memo to other values for Stellar assets will result in a failed request with an error message. |
### ThirdPartyInfo
| Parameter | Type | Description |
| ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| subType | string | The exchange account, fiat account, or unmanaged wallet (INTERNAL, EXTERNAL). |
| accountName | string | The account's name. |
| accountId | string | The account's ID. |
| apiKey | string | The third-party service's API key. |
| addresses | string | (Optional) A JSON-formatted "key":"value" string, where "key" is an asset symbol and "value" is its address. There can be multiple entries in the JSON. Use [supported\_assets](/api-reference/blockchains-&-assets/list-assets-legacy) to retrieve asset symbols. |
### AddNetworkConnection
| Parameter | Type | Description |
| ------------------- | ------ | -------------------------------------------- |
| networkConnectionId | string | ID of network connection |
| note | string | Connection note |
| localNetworkID | string | ID of local networkId |
| remoteTenantID | string | ID of remote peer tenantId |
| routingPolicy | string | JSON representation of routing policy object |
### NetworkConnectionRoutingPolicy
| Parameter | Type | Description |
| ------------- | ------ | -------------------------------------------- |
| connectionId | string | ID of network connection |
| routingPolicy | string | JSON representation of routing policy object |
### NetworkIdRoutingPolicy
| Parameter | Type | Description |
| ------------- | ------ | -------------------------------------------- |
| networkID | string | ID of networkID |
| routingPolicy | string | JSON representation of routing policy object |
# Approve transactions
Source: https://developers.fireblocks.com/reference/approve-transactions
## Transaction Signing Callback Handler
`POST /v2/tx_sign_request`
This request is used for transaction signing and approval and expects a [CallbackResponse](/reference/response-object) object from the callback handler. If the callback handler does not respond within 30 seconds, Fireblocks fails the request. If your callback handler can't respond within 30 seconds, you can use the [retry mechanism](/reference/response-object) by responding with `RETRY`.
If both approval and signing are requested for a transaction, one callback handles both requests.
To differentiate whether this request is for signing, approving, or both, these parameters are included only with signing requests:
* `fee`
* `displayDstAddress` within the transaction's [destinations array](#TransactionRequestCallbackDestination)
***
## Request parameters
| Parameter | Type | Description |
| ---------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| txId | string | The transaction's internal ID in Fireblocks. |
| operation | string | The [transaction operation](#transactionoperation) type. The default is `TRANSFER`. |
| sourceType | string | The [source](/reference/transaction-sources-destinations) of the transaction. |
| sourceId | string | The transaction’s source vault account ID or exchange account UUID. |
| destType | string | The transaction's destination type. The type can be VAULT, EXCHANGE, ONE\_TIME, or UNMANAGED. |
| destId | string | The destination's vault account ID or exchange account UUID. |
| asset | string | The asset ID in Fireblocks. |
| amount (Deprecated) | number | Use the **amountStr** field for accuracy. If the transfer is a withdrawal from an exchange, the actual transfer amount. Otherwise, the requested amount. |
| amountStr | string | The amount of the transfer in string format. |
| requestedAmount (Deprecated) | number | Use the **requestedAmountStr** field for accuracy. The requested transfer amount. In gross transactions, transaction fees are deducted from this amount. |
| requestedAmountStr | string | The requested transfer amount in string format. In gross transactions, transaction fees are deducted from this amount. |
| fee | string | (Optional) The transaction's estimated fee. |
| destAddressType | string | The destination's address type. For one-time addresses on EVM-compatible blockchains, this is the smart contract address. |
| destAddress | string | The destination address of the transaction. |
| destinations | array | An array of [TransactionRequestCallbackDestination](#transactionrequestcallbackdestination) objects with all details for all destination(s). |
| players | array (string) | A list of the Co-signers that signed the transaction. (Two Fireblocks SaaS and at least one user device or one API Co-signer). Each signer is represented by a Device ID. |
| requestId | string | A unique identifier of this request is returned in the response. |
| signerId | string | The user that signed the transaction. |
| extraParameters | object | (Optional) Parameters that are specific to some transaction operation types and blockchain networks. Learn more [below](#transactionextraparameters). |
| note | string | (Optional) Custom note that describes this transaction in your Fireblocks workspace. The note isn’t sent to the blockchain. |
| rawTx | array | An array of [RawTX](#rawtx). Contains a list of the actual transaction payload sent to the blockchain. Note that some signing requests represent multiple transactions. When this occurs, the list contains more than one object. This parameter is not included in the CallbackResponse object when using a Fireblocks EU cloud environment. This field is included for the following blockchains: ADA, BTC, DASH, DOGE, LTC, BSV, BCH, XEC, ZEC, EVMs, all Cosmos based chains, SOL, XLM, XTZ, TRX, NEAR, XRP and TON. This is an opt-in feature. Please contact [Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new) to include this feature in your workspace. **Note:** This field appears only for the signing stage of a transaction, and not during the approval stage. |
| externalTxId | string | An optional but highly recommended parameter. Fireblocks will reject future transactions with same ID. You should set this to a unique ID representing the transaction, to avoid submitting the same transaction twice. This helps with cases where submitting the transaction responds with an error code due to Internet interruptions, but the transaction was actually sent and processed. To validate whether a transaction has been processed, Find a specific transaction by external transaction ID. There is no specific format required for this parameter. |
| action (deprecated) | object | Includes information about the transaction authorization policy rule that matched this transaction. This field and its contents are not officially supported or maintained. Fireblocks may delete or change the contents of this field at any time. |
***
## TransactionOperation
| Parameter | Type | Description |
| --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| operation | string | `TRANSFER`: Default. Transfers funds from one account to another. UTXO blockchains allow multi-input and multi-output transfers. All other blockchains allow transfers with one source address and one destination address. `MINT`: Mints new tokens. Supported for Stellar, Ripple, and EVM-based blockchains. `BURN`: Burns tokens. Supported for Stellar, Ripple, and EVM-based blockchains. `CONTRACT_CALL`: Calls a smart contract method for web3 operations on any EVM blockchain. The [Fireblocks development libraries](/reference/evm-web3-provider#convenience-libraries) are recommended for building contract call transactions. `TYPED_MESSAGE`: An off-chain message in either Ethereum Personal Message or EIP712 format. Use it to sign specific readable messages that are not actual transactions. [Learn more about typed messages](/docs/typed-message-signing-1). `RAW`: An off-chain message with no predefined format. Use it to sign any message with your private key, including protocols such as blockchains and custom transaction types that are not natively supported by Fireblocks. [Learn more about raw signing transactions](/docs/raw-signing). `ENABLE_ASSET`: Algorand, DigitalBits, Solana, and Stellar require an on-chain transaction to create an asset wallet and enable the deposit address. This transaction is automatically created when adding assets on these blockchains to a vault account. `STAKE`: Assign assets to a staking pool managed by a staking validator. [Learn more about staking transactions and supported blockchains](/reference/staking-overview). This transaction is automatically created when performing staking operations. `UNSTAKE`: Remove assets from a staking pool managed by a staking validator. [Learn more about staking transactions and supported blockchains](/reference/staking-overview). This transaction is automatically created when performing staking operations. `WITHDRAW`: Transfer assets from a dedicated staking vault account to another address. [Learn more about staking transactions and supported blockchains](/reference/staking-overview). This transaction is automatically created when performing staking operations. **Note:** Fireblocks will rename `WITHDRAW` to a different name soon. There will be at minimum a 7-day notice regarding the new type name. |
### TransactionExtraParameters
| Parameter | Type | Description |
| ---------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| inputsSelection | [InputsSelection object](/reference/transaction-objects#inputsselection) | For UTXO-based blockchain multi-input selection, use the `inputsSelection` field with values set to the input selection structure. The inputs can be retrieved using the Retrieve Unspent Inputs endpoint. |
| rawMessageData | [RawMessageData object](/reference/raw-signing-objects#rawmessagedata) | For `RAW` operations, use the rawMessageData field with the values set to the raw message data structure. |
| contractCallData | string | For `CONTRACT_CALL` operations, use the contractCallData field with the value set to the Ethereum smart contract Application Binary Interface (ABI) payload. The [Fireblocks development libraries](/reference/evm-web3-provider#convenience-libraries) are recommended for building contract call transactions |
***
## TransactionRequestCallbackDestination
| Parameter | Type | Description |
| ----------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| amountNative | number | Deprecated. The amount transferred to this destination as a number. Use the amountNativeStr parameter for accurate precision. |
| amountNativeStr | string | The amount transferred to this destination represented as a string. |
| amountUSD | number | The USD value of the transfer to this destination. |
| dstAddressType | WHITELISTED or ONE\_TIME | `WHITELISTED` or `ONE_TIME` |
| dstId | string | The ID of the destination. |
| dstName | string | The name of the destination. |
| dstSubType | string | The specific exchange, fiat account, or unmanaged wallet. For exchange accounts: `BINANCE`, `BINANCEUS`, `BITFINEX`, `BITHUMB`, `BITMEX`, `BITSO`, `BITSTAMP`, `BITTREX`, `BYBIT`, `CIRCLE`, `COINBASEEXCHANGE`, `COINBASEPRO`, `COINMETRO`, `COINSPRO`, `CRYPTOCOM`, `DERIBIT`, `GEMINI`, `HITBTC`, `HUOBI`, `INDEPENDENTRESERVE`, `KORBIT`, `KRAKEN`, `KRAKENINTL`, `KUCOIN`, `LIQUID`, `OKCOIN`, `OKEX`, `PAXOS`, `POLONIEX` For fiat accounts: `BLINC` For unmanaged wallets: `INTERNAL`, `EXTERNAL`, or `CONTRACT` |
| dstType | string | The destination of the transaction: `VAULT`, `EXCHANGE_ACCOUNT`, `FIAT_ACCOUNT`, or `UNMANAGED`. |
| displayDstAddress | string | The address of this specific destination |
| action | string | Includes information about the Transaction Authorization Policy rule that matched this transaction. |
***
## RawTX
| Parameter | Type | Description |
| ----------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| rawTx | string | Hex-encoded details of a transaction sent to the blockchain |
| keyDerivationPath | string | Location of the encryption key within the customer’s [HD Wallet URL](https://support.fireblocks.io/hc/en-us/articles/360014330819-Fireblocks-Vault-HD-Derivation-Paths) used to sign this transaction. |
***
# Audit Log Events
Source: https://developers.fireblocks.com/reference/audit-log-events
# Overview
This page includes all Audit Log events and associated parameters. Sections are organized by Category.
# Administration
| Event ID | Subject | Event | Notification Subject |
| ---------------------------------------------------------- | ----------------------- | ---------------------------- | -------------------------------------------------------------------- |
| `EventId.ApiIpWhitelisting_ListUpdated` | Whitelisted IP | List updated | API IP Whitelisting List Updated |
| `EventId.AdminQuorum_ApprovedByAdmin` | Quorum | Approved | Admin Quorum Approved by admin |
| `EventId.AdminQuorum_Cancelled` | Quorum | Canceled | Admin Quorum Cancelled |
| `EventId.AdminQuorum_Rejected` | Quorum | Rejected | Admin Quorum Rejected |
| `EventId.AdminQuorum_RequestSubmitted` | Quorum | Submitted request | Admin Quorum Request Submitted |
| `EventId.AdminQuorum_ThresholdChanged` | Quorum | Changed threshold | Admin Quorum Threshold Changed |
| `EventId.Authentication_LoginFailed` | Sign in | Failed | Authentication Login Failed |
| `EventId.Authentication_PasswordChangeRequested` | Sign in | Requested password change | Authentication Password Change Requested |
| `EventId.Authentication_PasswordChanged` | Sign in | Changed password | Authentication Password Changed |
| `EventId.Authentication_2faReset` | Sign in | Reset 2FA | Authentication 2FA reset |
| `EventId.DeviceRecover_Completed` | Device recovery | Completed | Device Recover Completed |
| `EventId.DeviceReset_ApprovedByAdmin` | Device reset | Approved | Device Reset Approved by admin |
| `EventId.DeviceReset_DeviceRecover` | Device reset | Recovered | Device Reset Device Recover |
| `EventId.DeviceReset_DeviceReset` | Device reset | Completed | Device Reset Device Reset |
| `EventId.DeviceReset_Rejected` | Device reset | Rejected | Device Reset Rejected |
| `EventId.DeviceReset_RequestSubmitted` | Device reset | Submitted request | Device Reset Request submitted |
| `EventId.EditUser_ApprovedByAdmin` | Edit user | Approved | Edit User Approved by admin |
| `EventId.EditUser_Cancelled` | Edit user | Canceled | Edit User Cancelled |
| `EventId.EditUser_EditRequestSubmitted` | Edit user | Submitted request | Edit User Edit request submitted |
| `EventId.EditUser_EditRequestImplemented` | Edit user | Edit request implemented | |
| `EventId.EditUser_Rejected` | Edit user | Rejected | Edit User Rejected |
| `EventId.NewUserApproval_ApprovedByAdmin` | New user | Approved | New User Approval Approved by admin |
| `EventId.NewUserApproval_Cancelled` | New user | Canceled | New User Approval Cancelled |
| `EventId.NewUserApproval_Rejected` | New user | Rejected | New User Approval Rejected |
| `EventId.NewUserApproval_RequestSubmitted` | New user | Submitted request | New User Approval Request submitted |
| `EventId.OneTimeAddress_ApprovedByAdmin` | One-time address | Approved | One-time Address Approved by admin |
| `EventId.OneTimeAddress_Cancelled` | One-time address | Canceled | One-time Address Cancelled |
| `EventId.OneTimeAddress_Rejected` | One-time address | Rejected | One-time Address Rejected |
| `EventId.OneTimeAddress_RequestSubmitted` | One-time address | Submitted request | One-time Address Request Submitted |
| `EventId.OneTimeAddress_ToggledOff` | One-time address | Turned off | One-time Address Toggled off |
| `EventId.OneTimeAddress_ToggledOn` | One-time address | Turned on | One-time Address Toggled on |
| `EventId.ReEnrollDevice_ApprovedByAdmin` | Re-enroll mobile device | Approved | Re-enroll Device Approved by admin |
| `EventId.ReEnrollDevice_Cancelled` | Re-enroll mobile device | Canceled | Re-enroll Device Cancelled |
| `EventId.ReEnrollDevice_Completed` | Re-enroll mobile device | Completed | Re-enroll Device Completed |
| `EventId.ReEnrollDevice_DeviceReEnrollmentCompleted` | Re-enroll mobile device | Completed | Re-enroll Device Device Re-enrollment Completed |
| `EventId.ReEnrollDevice_DeviceRecover` | Re-enroll mobile device | Recovered | Re-enroll Device Device Recover |
| `EventId.ReEnrollDevice_Rejected` | Re-enroll mobile device | Rejected | Re-enroll Device Rejected |
| `EventId.ReEnrollDevice_RequestSubmitted` | Re-enroll mobile device | Submitted request | Re-enroll Device Request Submitted |
| `EventId.User_Deleted` | User | Deleted | User Deleted |
| `EventId.User_LoggedIn` | User | Signed in | User Logged In |
| `EventId.User_AccessDenied` | User | Access denied | User Access denied |
| `EventId.UserGroups_ChangesApprovedByAdmin` | User group | Changes approved | User Groups Active group changes request was approved by admin |
| `EventId.UserGroups_ChangesRequestRejected` | User group | Changes rejected | User Groups Active group changes request was rejected |
| `EventId.UserGroups_ChangesWentIntoAffect` | User group | Changes in effect | User Groups Active group changes went into affect |
| `EventId.UserGroups_EditRequestImplemented` | User group | Edited | User Groups Edit request implemented |
| `EventId.UserGroups_NewGroupApprovedAndCreated` | User group | Approved and created | User Groups New group approved and created |
| `EventId.UserGroups_NewGroupRequestWasApprovedByAdmin` | User group | Approved | User Groups New group request was approved by admin |
| `EventId.UserGroups_NewGroupRequestWasRejected` | User group | Rejected | User Groups New group request was rejected |
| `EventId.UserGroups_UserCanceledActiveGroupChangesRequest` | User group | Canceled change request | User Groups User canceled active group changes request |
| `EventId.UserGroups_UserDeletedAGroup` | User group | Deleted | User Groups User deleted a group |
| `EventId.UserGroups_UserDiscardedActiveGroupEditing` | User group | Discarded edits (DEPRECATED) | User Groups User discarded active group editing |
| `EventId.UserGroups_UserStartedEditingActiveGroup` | User group | Edited (DEPRECATED) | User Groups User started editing active group |
| `EventId.UserGroups_SubmittedApprovalRequestGroupChanges` | User group | Requested change approval | User Groups User submitted approval request for active group changes |
| `EventId.UserGroups_UserSubmittedNewGroupForApproval` | User group | Created | User Groups User submitted new group for approval |
| `EventId.UserManagement_DeviceRecover` | User | Recovered mobile device | User Management Device Recover |
| `EventId.UserManagement_DeviceReset` | User | Reset mobile device | User Management Device Reset |
| `EventId.UserManagement_Disabled` | User | Deactivated | User Management Disabled |
| `EventId.UserManagement_RoleChanged` | User | Changed role | User Management Role Changed |
| `EventId.LinkedUserMigration_InitiatedByUser` | Linked user migration | Initiated by user | Linked user migration Initiated by user |
| `EventId.LinkedUserMigration_UserPairedSuccessfully` | Linked user migration | User paired successfully | Linked user migration User paired successfully |
| `EventId.LinkedUserMigration_Activated` | Linked user migration | Activated | Linked user migration Activated |
| `EventId.LinkedUserMigration_Deactivated` | Linked user migration | Deactivated | Linked user migration Deactivated |
| `EventId.Notifications_EmailCreated` | Email Notification | Created | |
| `EventId.Notifications_EmailEnabled` | Email Notification | Enabled | |
| `EventId.Notifications_EmailDisabled` | Email Notification | Disabled | |
| `EventId.Notifications_EmailEdited` | Email Notification | Edited | |
| `EventId.Notifications_SlackCreated` | Slack Notification | Created | |
| `EventId.Notifications_SlackEnabled` | Slack Notification | Enabled | |
| `EventId.Notifications_SlackDisabled` | Slack Notification | Disabled | |
| `EventId.Notifications_SlackEdited` | Slack Notification | Edited | |
| `EventId.Notifications_WebhooksCreated` | Webhooks Notification | Created | |
| `EventId.Notifications_WebhooksEnabled` | Webhooks Notification | Enabled | |
| `EventId.Notifications_WebhooksDisabled` | Webhooks Notification | Disabled | |
| `EventId.Notifications_WebhooksEdited` | Webhooks Notification | Edited | |
| `EventId.Notifications_WebhooksDeleted` | Webhooks Notification | Deleted | |
# Assets
| Event ID | Subject | Event | Notification Subject |
| ------------------------ | ------- | --------- | -------------------- |
| `EventId.Asset_Listed` | Asset | Listed | Asset Listed |
| `EventId.Asset_SetPrice` | Asset | Set price | Asset Set price |
# Automation
| Event ID | Event | Subject | Notification Subject |
| ------------------------------------- | ------------- | --------------- | ----------------------------- |
| `EventId.AutomationRule_RuleCreated` | Rule Created | Automation Rule | Automation Rule Rule Created |
| `EventId.AutomationRule_RuleEdited` | Rule Edited | Automation Rule | Automation Rule Rule Edited |
| `EventId.AutomationRule_RuleEnabled` | Rule Enabled | Automation Rule | Automation Rule Rule Enabled |
| `EventId.AutomationRule_RuleDisabled` | Rule Disabled | Automation Rule | Automation Rule Rule Disabled |
| `EventId.AutomationRule_RuleDeleted` | Rule Deleted | Automation Rule | Automation Rule Rule Deleted |
# Compliance
| Event ID | Subject | Event Description | Notification Subject |
| -------------------------------------------------------- | ---------- | -------------------------------------- | -------------------------------------------------------------------------- |
| `EventId.Transaction_AmlRegistrationComplated` | Compliance | AML registration completed | Transaction AML Registration complated |
| `EventId.Transaction_AmlRegistrationStarted` | Compliance | AML registration initiated | Transaction AML Registration started |
| `EventId.Transaction_AmlScreeningCompleted` | Compliance | AML screening completed | Transaction AML screening completed |
| `EventId.Transaction_AmlScreeningFailed` | Compliance | AML screening failed | Transaction AML screening failed |
| `EventId.Transaction_AmlScreeningInBackground` | Compliance | AML screening in background | Transaction AML screening in background |
| `EventId.Transaction_AmlScreeningStarted` | Compliance | AML screening initiated | Transaction AML screening started |
| `EventId.Transaction_ScreeningCompleted` | Compliance | Screening completed | Transaction Screening completed |
| `EventId.Transaction_ScreeningStarted` | Compliance | Screening initiated | Transaction Screening Started |
| `EventId.Transaction_ScreeningUpdateCompleted` | Compliance | Screening update completed | Transaction Screening update completed |
| `EventId.Transaction_TravelRuleScreeningCompleted` | Compliance | Travel rule screening completed | Transaction Travel Rule screening completed |
| `EventId.Transaction_TravelRuleScreeningFailed` | Compliance | Travel rule screening failed | Transaction Travel Rule screening failed' |
| `EventId.Transaction_TravelRuleScreeningStarted` | Compliance | Travel rule screening initiated | Transaction Travel Rule screening started', 'Travel Rule screening started |
| `EventId.Transaction_TravelRuleScreeningUpdateCompleted` | Compliance | Travel rule screening update completed | Transaction Travel Rule screening update completed |
| `EventId.Transaction_TravelRuleScreeningUpdateStarted` | Compliance | Travel rule screening update initiated | Transaction Travel Rule screening update started |
# Developers
| Event ID | Subject | Event | Notification Subject |
| --------------------------- | ---------------- | -------------------- | ------------------------- |
| `WebhookUrls_ListUpdated` | Webhooks | Updated URLs | Webhook URLs List Updated |
| `Webhook_Added` | Webhook endpoint | Added | |
| `Webhook_Deleted` | Webhook endpoint | Deleted | |
| `Webhook_Activated` | Webhook endpoint | Activated | |
| `Webhook_Deactivated` | Webhook endpoint | Deactivated | |
| `Webhook_Updated` | Webhook endpoint | Updated | |
| `Webhook_Suspended` | Webhook endpoint | Suspended | |
| `Webhook_Suspended_Warning` | Webhook endpoint | Suspend warning sent | |
# Exchanges
| Event ID | Subject | Event | Notification Subject |
| --------------------------------------------------- | ---------------- | --------- | --------------------------------------------- |
| `EventId.ExchangeConnection_Added` | Exchange account | Linked | Exchange Connection Added |
| `EventId.ExchangeConnection_Removed` | Exchange account | Unlinked | Exchange Connection Removed |
| `EventId.ExchangeConnectionRequest_ApprovedByAdmin` | Exchange account | Approved | Exchange Connection Request Approved by admin |
| `EventId.ExchangeConnectionRequest_Cancelled` | Exchange account | Canceled | Exchange Connection Request Cancelled |
| `EventId.ExchangeConnectionRequest_Rejected` | Exchange account | Rejected | Exchange Connection Request Rejected |
| `EventId.ExchangeConnectionRequest_Submitted` | Exchange account | Submitted | Exchange Connection Request Submitted |
| `EventId.FiatConnectionRequest_ApprovedByAdmin` | Fiat account | Approved | FIAT Connection Request Approved by admin |
| `EventId.FiatConnectionRequest_Rejected` | Fiat account | Rejected | FIAT Connection Request Rejected |
| `EventId.FiatConnectionRequest_Submitted` | Fiat account | Submitted | FIAT Connection Request Submitted |
| `EventId.FiatConnectionRequest_Cancelled` | Fiat account | Canceled | FIAT Connection Request Cancelled |
| `EventId.FiatConnection_Added` | Fiat account | Linked | FIAT connection Added |
| `EventId.FiatConnection_Removed` | Fiat account | Unlinked | FIAT connection Removed |
# Keys
| Event ID | Subject | Event | Notification Subject |
| ---------------------------------- | -------------- | ------------------------- | ------------------------------------- |
| ValidationKey\_SubmittedRequest | Validation key | Submitted request | Validation key Submitted request |
| ValidationKey\_Approved | Validation key | Approved | Validation key Approved |
| ValidationKey\_Rejected | Validation key | Rejected | Validation key Rejected |
| ValidationKey\_Activated | Validation key | Activated | Validation key Activated |
| ValidationKey\_Deactivated | Validation key | Deactivated | Validation key Deactivated |
| SigningKey\_SubmittedRequest | Signing key | Submitted request | Signing key Submitted request |
| SigningKey\_LinkedToUser | Signing key | Linked to user | Signing key Linked to user |
| SigningKey\_Enabled | Signing key | Enabled | Signing key Enabled |
| SigningKey\_AssignedToVaultAccount | Signing key | Assigned to vault account | Signing key Assigned to vault account |
| SigningKey\_Deleted | Signing key | Deleted | Signing key Deleted |
| MPCKeySet\_Created | MPC key set | Created | |
| MPCKeySet\_Enabled | MPC key set | Enabled | |
| MPCKeySet\_Activated | MPC key set | Activated | |
# Policies
| Event ID | Subject | Event | Notification Subject |
| ------------------------------------------------------------------------------------- | --------------------------------- | --------------------------------- | --------------------------------------------------------------------------------------- |
| `EventId.Policy_PolicyReviewRejected` | TAP | Rejected policy | Policy Policy Review Rejected |
| `EventId.PolicyEditor_ASignerApprovedThePendingDraftPolicy` | TAP | Signed policy | Policy editor A signer approved the pending draft policy |
| `EventId.PolicyEditor_Deleted` | TAP | Deleted policy | Policy editor Deleted |
| `EventId.PolicyEditor_PolicyPublished` | TAP | Published policy | Policy editor Policy published |
| `EventId.PolicyEditor_TheDraftPolicyWasDiscarded` | TAP | Discarded policy draft | Policy editor The draft policy was discarded |
| `EventId.PolicyEditor_TheDraftPolicyWasReverted` | TAP | Reverted policy draft' | Policy editor The draft policy was reverted |
| `EventId.PolicyEditor_ThePendingPolicyWasRejected` | TAP | Rejected policy | Policy editor The pending policy was rejected |
| `EventId.PolicyEditor_ThePendingPolicyWasRejectedAndThePublishProcessHasBeenCanceled` | TAP | Rejected policy | Policy editor The pending policy was rejected and the publish process has been canceled |
| `EventId.PolicyEditor_ThePendingPolicyWentIntoEffect` | TAP | Put policy into effect | Policy editor The pending policy went into effect |
| `EventId.PolicyEditor_UserMarkedTheDraftPolicyAsReadyToPublish` | TAP | Draft marked as ready to publish | Policy editor User marked the draft policy as ready to publish |
| `EventId.PolicyEditor_UserRequestedToPublishTheDraftPolicy` | TAP | Requested policy draft publishing | Policy editor User requested to publish the draft policy |
| `EventId.PolicyEditor_UserStartedEditingTheDraftPolicy` | TAP | Edited draft | Policy editor User started editing the draft policy |
| `EventId.PolicyEditor_PolicyReviewRejected` | TAP | Rejected policy | Policy editor Policy Review Rejected |
| `EventId.IpAllowList_AllowListActivationRequestSubmitted` | IP address allowlist activation | Submitted | Activation request submitted |
| `EventId.IpAllowList_AllowListActivationRequestApproved` | IP address allowlist activation | Approved by quorum | Activation request approved by quorum |
| `EventId.IpAllowList_AllowListActivationRequestSigned` | IP address allowlist activation | Approved by user | Activation request approved by user |
| `EventId.IpAllowList_AllowListActivationRequestRejected` | IP address allowlist activation | Rejected | Activation request rejected |
| `EventId.IpAllowList_AllowListActivationRequestCanceled` | IP address allowlist activation | Canceled | Activation request canceled |
| `EventId.IpAllowList_AllowListActivationRequestFailed` | IP address allowlist activation | Failed | Activation request failed |
| `EventId.IpAllowList_AllowListDeactivationRequestSubmitted` | IP address allowlist deactivation | Submitted | Deactivation request submitted |
| `EventId.IpAllowList_AllowListDeactivationRequestApproved` | IP address allowlist deactivation | Approved by quorum | Deactivation request approved by quorum |
| `EventId.IpAllowList_AllowListDeactivationRequestSigned` | IP address allowlist deactivation | Approved by user | Deactivation request approved by user |
| `EventId.IpAllowList_AllowListDeactivationRequestRejected` | IP address allowlist deactivation | Rejected | Deactivation request rejected |
| `EventId.IpAllowList_AllowListDeactivationRequestCanceled` | IP address allowlist deactivation | Canceled | Deactivation request canceled |
| `EventId.IpAllowList_AllowListDeactivationRequestFailed` | IP address allowlist deactivation | Failed | Deactivation request failed |
| `EventId.IpAllowList_AddIpRequestSubmitted` | IP address allowlist | Approval submitted | Add IP address request submitted |
| `EventId.IpAllowList_AddIpRequestApproved` | IP address allowlist | Approval approved by quorum | Add IP address request approved by quorum |
| `EventId.IpAllowList_AddIpRequestSigned` | IP address allowlist | Approval approved by user | Add IP address request approved by user |
| `EventId.IpAllowList_AddIpRequestCanceled` | IP address allowlist | Approval canceled | Add IP address request canceled |
| `EventId.IpAllowList_AddIpRequestRejected` | IP address allowlist | Approval Rejected | Add IP address request rejected |
| `EventId.IpAllowList_AddIpRequestFailed` | IP address allowlist | Approval Failed | Add IP address request failed |
| `EventId.IpAllowList_UpdateIpRequestSubmitted` | IP address allowlist | Changes submitted | Update IP address request submitted |
| `EventId.IpAllowList_UpdateIpRequestApproved` | IP address allowlist | Changes approved by quorum | Update IP address request approved by quorum |
| `EventId.IpAllowList_UpdateIpRequestSigned` | IP address allowlist | Changes approved by user | Update IP address request approved by user |
| `EventId.IpAllowList_UpdateIpRequestCanceled` | IP address allowlist | Changes canceled | Update IP address request canceled |
| `EventId.IpAllowList_UpdateIpRequestRejected` | IP address allowlist | Changes rejected | Update IP address request rejected |
| `EventId.IpAllowList_UpdateIpRequestFailed` | IP address allowlist | Changes failed | Update IP address request failed |
| `EventId.IpAllowList_DeleteIpRequestSubmitted` | IP address allowlist | Deletion submitted | Remove IP address request submitted |
| `EventId.IpAllowList_DeleteIpRequestSigned` | IP address allowlist | Deletion approved by user | Remove IP address request approved by user |
| `EventId.IpAllowList_DeleteIpRequestCanceled` | IP address allowlist | Deletion canceled | Remove IP address request canceled |
| `EventId.IpAllowList_DeleteIpRequestApproved` | IP address allowlist | Deletion approved by quorum | Remove IP address request approved by quorum |
| `EventId.IpAllowList_DeleteIpRequestRejected` | IP address allowlist | Deletion rejected | Remove IP address request rejected |
| `EventId.IpAllowList_DeleteIpRequestFailed` | IP address allowlist | Deletion failed | Remove IP address request failed |
# Security
| Event ID | Subject | Event |
| :---------------------------- | :------ | :--------------- |
| EventId.Fspm\_FindingCreated | FSPM | Finding created |
| EventId.Fspm\_FindingResolved | FSPM | Finding resolved |
| EventId.Fspm\_FindingAccepted | FSPM | Finding accepted |
| EventId.Fspm\_FindingReopened | FSPM | Finding reopened |
# Settlements
| Event ID | Subject | Event | Notification Subject |
| -------------------------------------------------------------- | ------------------ | --------------------------------- | -------------------------------------------------------- |
| `EventId.NetworkConnection_Added` | Fireblocks network | Added connection | Network Connection Added |
| `EventId.NetworkConnection_Created` | Fireblocks network | Made connection | Network Connection Created |
| `EventId.NetworkConnectionInvitation_ApprovedByAdmin` | Fireblocks network | Approved invitation | Network Connection Invitation Approved by admin |
| `EventId.NetworkConnectionInvitation_Cancelled` | Fireblocks network | Canceled invitation | Network Connection Invitation Cancelled |
| `EventId.NetworkConnectionInvitation_ReceivedFromCounterparty` | Fireblocks network | Received invitation | Network Connection Invitation Received from Counterparty |
| `EventId.NetworkConnectionRequest_ApprovedByAdmin` | Fireblocks network | Invitation approved by connection | Network Connection Request Approved by admin |
| `EventId.NetworkConnectionRequest_Cancelled` | Fireblocks network | Invitation canceled by connection | Network Connection Request Cancelled |
| `EventId.NetworkConnectionRequest_Rejected` | Fireblocks network | Invitation rejected by connection | Network Connection Request Rejected |
| `EventId.NetworkConnectionRoutingChange_Approved` | Fireblocks network | Approved routing change | Network Connection Routing Change Approved |
| `EventId.NetworkConnectionRoutingChange_ApprovedByAdmin` | Fireblocks network | Approved routing change (admin) | Network Connection Routing Change Approved By Admin |
| `EventId.NetworkConnectionRoutingChange_Rejected` | Fireblocks network | Rejected routing change | Network Connection Routing Change Rejected |
| `EventId.NetworkConnectionRoutingChange_RequestSubmitted` | Fireblocks network | Requested routing change | Network Connection Routing Change Request Submitted |
| `EventId.NetworkConnectionRoutingChange_RoutingChanged` | Fireblocks network | Changed routing | Network Connection Routing Change Routing Changed |
| `EventId.NetworkDiscoverability_TurnedOn` | Fireblocks network | Turned on discoverability' | Network Discoverability Turned On |
| `EventId.NetworkDiscoverability_TurnedOff` | Fireblocks network | Turned off discoverability' | Network Discoverability Turned Off |
| `EventId.NetworkProfile_Created` | Fireblocks network | Created profile' | Network Profile Created |
| `EventId.NetworkProfileNameChange_ProfileRenamed` | Fireblocks network | Approved profile name change | Network Profile Name Change Profile Renamed |
| `EventId.NetworkProfileNameChange_RequestSubmitted` | Fireblocks network | Requested profile name change | Network Profile Name Change Request Submitted |
| `EventId.NetworkProfileRemoved_ProfileRemoved` | Fireblocks network | Removed profile | Network Profile Removed Profile Removed |
| `EventId.NetworkProfileRoutingChange_Approved` | Fireblocks network | Approved default routing change | Network Profile Routing Change Approved |
| `EventId.NetworkProfileRoutingChange_ApprovedByAdmin` | Fireblocks network | Approved default routing change' | Network Profile Routing Change Approved By Admin |
| `EventId.NetworkProfileRoutingChange_Rejected` | Fireblocks network | Rejected default routing change | Network Profile Routing Change Rejected |
| `EventId.NetworkProfileRoutingChange_RequestSubmitted` | Fireblocks network | Requested default routing change | Network Profile Routing Change Request Submitted |
| `EventId.NetworkProfileRoutingChange_RoutingChanged` | Fireblocks network | Changed default routing | Network Profile Routing Change Routing Changed |
| `EventId.NetworkProfileRoutingChange_WaitingForApproval` | Fireblocks network | Pending approval | Network Profile Routing Change Waiting For Approval |
| `EventId.NetworkConnection_Removed` | Fireblocks network | Removed connection | Network Connection Removed |
| `EventId.NetworkConnection_RemovedByCounterparty` | Fireblocks network | Removed by connection | Network Connection Removed by counterparty |
| `EventId.NetworkConnectionInvitation_Rejected` | Fireblocks network | Rejected invitation | Network connection invitation Rejected |
| `EventId.NetworkConnectionRequest_Submitted` | Fireblocks network | Sent invitation | Network connection request Submitted |
# Transactions
| Event ID | Subject | Event | Notification Subject |
| --------------------------------------------------------------------- | -------------------- | --------------------------------------- | -------------------------------------------------------------- |
| `EventId.IncomingTransaction_AssociationFailed` | Incoming transaction | Failed | Incoming Transaction Association Failed |
| `EventId.IncomingTransaction_Completed` | Incoming transaction | Completed | Incoming Transaction Completed |
| `EventId.IncomingTransaction_Submitted` | Incoming transaction | Submitted | Incoming Transaction Submitted |
| `EventId.IncomingTxAssociationFailed_FailedToAssociateIncomingTxHash` | Incoming transaction | Failed to associate incoming TX hash | Incoming tx association failed FailedToAssociateIncomingTxHash |
| `EventId.InternalTransaction_Completed` | Internal transaction | Completed | Internal Transaction Completed |
| `EventId.InternalTransaction_Submitted` | Internal transaction | Submitted | Internal Transaction Submitted |
| `EventId.OutgoingTransaction_Completed` | Outgoing transaction | Completed | Outgoing Transaction Completed |
| `EventId.OutgoingTransaction_Submitted` | Outgoing transaction | Submitted | Outgoing Transaction Submitted |
| `EventId.Transaction_AlertedByAml` | Transaction | Flagged by AML | Transaction Alerted by AML |
| `EventId.Transaction_AmlFailed` | Transaction | AML failed | Transaction AML Failed |
| `EventId.Transaction_AmlScreeningBlockingPeriodTimedOut` | Transaction | AML screening blocking period timed out | Transaction AML screening blocking period timed out |
| `EventId.Transaction_AmlResultRescreened` | Transaction | AML result rescreened | Transaction AML Result Rescreened |
| `EventId.Transaction_ApprovedBy2ndTier` | Transaction | Approved by 2nd tier | Transaction Approved by 2nd Tier |
| `EventId.Transaction_AuthorizationRequestInitiated` | Transaction | Authorization request initiated | Transaction Authorization Request Initiated |
| `EventId.Transaction_BlockedByPolicy` | Transaction | Blocked by TAP | Transaction Blocked by Policy |
| `EventId.Transaction_BypassedAml` | Transaction | Bypassed AML | Transaction Bypassed AML |
| `EventId.Transaction_Cancelled` | Transaction | Canceled | Transaction Cancelled |
| `EventId.Transaction_Completed` | Transaction | Completed | Transaction Completed |
| `EventId.Transaction_ConfirmationThresholdOverridden` | Transaction | Confirmation threshold overridden | Transaction Confirmation Threshold Overridden |
| `EventId.Transaction_DeclinedBy2ndTier` | Transaction | Declined by 2nd tier | Transaction Declined by 2nd Tier |
| `EventId.Transaction_FundsUnfrozen` | Transaction | Funds unfrozen | Transaction Funds Unfrozen |
| `EventId.Transaction_NoteChanged` | Transaction | Note changed | Transaction Note Changed |
| `EventId.Transaction_Rejected` | Transaction | Rejected | Transaction Rejected |
| `EventId.Transaction_RejectedByAml` | Transaction | Rejected by AML | Transaction Rejected by AML |
| `EventId.Transaction_Signed` | Transaction | Signed | Transaction Signed |
| `EventId.Transaction_Submitted` | Transaction | Submitted | Transaction Submitted |
| `EventId.Transaction_TransactionRejected` | Transaction | Rejected | Transaction Transaction Rejected |
| `EventId.ExternalTransaction_Completed` | Transaction | Completed | External Transaction Completed |
| `EventId.ExternalTransaction_Submitted` | Transaction | Submitted | External Transaction Submitted |
| `EventId.Transaction_ScreeningIncomingStarted` | Transaction | Screening incoming started | Transaction Screening incoming started |
| `EventId.Transaction_AmlIncomingStarted` | Transaction | AML Incoming Started | Transaction AML Incoming Started |
| `EventId.Transaction_AmlIncomingCompleted` | Transaction | AML Incoming Completed | Transaction AML Incoming Completed |
| `EventId.Transaction_AmlIncomingFailed` | Transaction | AML Incoming Failed | Transaction AML Incoming Failed |
| `EventId.Transaction_AmlIncomingInBackground` | Transaction | AML Incoming in background | Transaction AML Incoming in background |
| `EventId.Transaction_TrIncomingStarted` | Transaction | TR Incoming started | Transaction TR Incoming started |
| `EventId.Transaction_TrIncomingCompleted` | Transaction | TR Incoming completed | Transaction TR Incoming completed |
| `EventId.Transaction_TrIncomingFailed` | Transaction | TR Incoming failed | Transaction TR Incoming failed |
| `EventId.Transaction_ScreeningIncomingCompleted` | Transaction | Screening incoming completed | Transaction Screening incoming completed |
# Wallets
| Event ID | Subject | Event | Notification Subject |
| ---------------------------------------------------------------------- | ----------------- | ----------------------------------- | ----------------------------------------------------------------------- |
| `EventId.ColdWallet_DeviceHasLessThan10_RemainingSignatures` | Cold wallet | Requires signatures | Cold Wallet Device has less than 10% remaining signatures |
| `EventId.VaultAccount_Added` | Vault | Created | Vault Account Added |
| `EventId.VaultAccount_AddedInBulk` | Vault | Bulk created | Vault Account Added in Bulk |
| `EventId.VaultAccount_Archived` | Vault | Archived | Vault Account Archived |
| `EventId.VaultAccount_DisabledAutoFueling` | Vault | Turned off auto-fueling | Vault Account Disabled Auto Fueling |
| `EventId.VaultAccount_EnabledAutoFueling` | Vault | Turned on auto-fueling | Vault Account Enabled Auto Fueling |
| `EventId.VaultAccount_Renamed` | Vault | Renamed | Vault Account Renamed |
| `EventId.VaultAccount_SetHiddenOnUi` | Vault | Hidden | Vault Account Set Hidden On UI |
| `EventId.VaultAccount_SetVisibleOnUi` | Vault | Made visible | Vault Account Set Visible On UI |
| `EventId.VaultAccount_Unarchived` | Vault | Unarchived | Vault Account Unarchived |
| `EventId.VaultDepositAddress_ChangedDescription` | Wallet | Changed deposit address description | Vault deposit address Changed description |
| `EventId.VaultWallet_Added` | Wallet | Added | Vault wallet Added |
| `EventId.VaultWallet_AddedInBulk` | Wallet | Bulk added | Vault wallet Added in Bulk |
| `EventId.VaultWallet_Archived` | Wallet | Archived | Vault wallet Archived |
| `EventId.VaultWallet_Unarchived` | Wallet | Unarchived | Vault wallet Unarchived |
| `EventId.BackupAndRecovery_SentVerifyPassphraseAlert` | Mobile passphrase | Sent verification alert | Backup And Recovery Sent Verify Passphrase Alert |
| `EventId.BackupAndRecovery_VerifiedPassphrase` | Mobile passphrase | Verified passphrase | Backup And Recovery Verified Passphrase |
| `EventId.HardKeyRecoveryProcess_RequestSubmitted` | Key backup | Requested | Hard Key Recovery Process Request Submitted |
| `EventId.MobileKey_BackedUp` | Mobile passphrase | Backed up | Mobile Key Backed Up |
| `EventId.WorkspaceKeyBackup_ApprovedByAdmin` | Key backup | Approved | Workspace key backup Approved by admin |
| `EventId.WorkspaceKeyBackup_ApprovedByAdminQuorum` | Key backup | Approved by quorum | Workspace key backup Approved by admin quorum |
| `EventId.WorkspaceKeyBackup_Cancelled` | Key backup | Canceled | Workspace key backup Cancelled |
| `EventId.WorkspaceKeyBackup_InternalErrorWhenGeneratingTheBackup` | Key backup | Error generating key backup | Workspace key backup Internal error when generating the backup |
| `EventId.WorkspaceKeyBackup_RequestSubmitted` | Key backup | Requested | Workspace key backup Request Submitted |
| `EventId.WorkspaceKeyBackup_TheProcessHasBeenRejectedByOnOfTheAdmins` | Key backup | Rejected | Workspace key backup The process has been rejected by on of the admins |
| `EventId.WorkspaceKeyBackup_TheProcessHasBeenRejectedByOneOfTheAdmins` | Key backup | Rejected | Workspace key backup The process has been rejected by one of the admins |
| `EventId.WorkspaceKeyBackup_TheWorkspaceOwnerHasInitiatedTheProcess` | Key backup | Initiated | Workspace key backup The workspace owner has initiated the process |
| `EventId.WorkspaceKeyBackup_MarkedAsIncomplete` | Key backup | Marked as incomplete | Workspace key backup Marked as incomplete |
| `EventId.WorkspaceKeyBackup_MarkedAsCompleted` | Key backup | Marked as completed | Workspace key backup Marked as completed |
| `EventId.WorkspaceKeyBackup_PendingApproval` | Key backup | Pending approval | Workspace key backup Pending approval |
| `EventId.WorkspaceKeyBackup_BackupSent` | Key backup | Backup sent | Workspace key backup Backup sent |
| `EventId.GasStation_LowFunds` | Gas station | Low funds | Gas Station Low funds |
| `EventId.GasStation_VaultChanged` | Gas station | Changed vault | Gas Station Vault changed |
| `EventId.GasStation_SweepTransactionInitiated` | Gas station | Initiated sweep | Gas Station Sweep transaction initiated |
| `EventId.GasStation_FundsDeposited` | Gas station | Deposited funds | Gas Station Funds deposited |
| `EventId.ExternalWallet_Added` | Wallet | Added | External wallet Added |
| `EventId.ExternalWallet_Removed` | Wallet | Removed | External wallet Removed |
| `EventId.MyWallet_Added` | My wallet | Added | My wallet Added |
| `EventId.MyWallet_Removed` | My wallet | Removed | My wallet Removed |
# Web3
| Event ID | Subject | Event | Notification Subject |
| --------------------------------------------------------------- | ---------------------------- | ------------------ | -------------------------------------------------------- |
| `EventId.Allowance_AmountModified` | Allowance | Changed | Allowance Amount Modified |
| `EventId.Contract_Added` | Contract | Added | Contract Added |
| `EventId.Contract_Removed` | Contract | Removed | Contract Removed |
| `EventId.FireblocksExtensionConnected_ExtensionConnected` | Fireblocks browser extension | Connected | Fireblocks extension connected Extension Connected |
| `EventId.FireblocksExtensionUpdated_ExtensionUpdated` | Fireblocks browser extension | Updated | Fireblocks extension updated Extension Updated |
| `EventId.FireblocksExtensionDisconnected_ExtensionDisconnected` | Fireblocks browser extension | Disconnected | Fireblocks extension disconnected Extension Disconnected |
| `EventId.Nft_MarkedAsSpam` | NFT | Marked as spam | NFT Marked as spam |
| `EventId.Nft_MarkedAsNotSpam` | NFT | Marked as not spam | NFT Marked as not spam |
# Whitelist
| Event ID | Subject | Event | Notification Subject |
| ---------------------------------------------- | ------------------- | --------- | -------------------------------------- |
| `EventId.Address_Removed` | Whitelisted address | Removed | Address Removed |
| `EventId.Address_Whitelisted` | Whitelisted address | Added | Address Whitelisted |
| `EventId.AddressWhitelisting_ApprovedByAdmin` | Whitelisted address | Approved | Address Whitelisting Approved by admin |
| `EventId.AddressWhitelisting_Cancelled` | Whitelisted address | Canceled | Address Whitelisting Cancelled |
| `EventId.AddressWhitelisting_Rejected` | Whitelisted address | Rejected | Address Whitelisting Rejected |
| `EventId.AddressWhitelisting_RequestSubmitted` | Whitelisted address | Requested | Address Whitelisting Request Submitted |
# Authenticating the Callback Handler Request
Source: https://developers.fireblocks.com/reference/authenticate
> **Learn more about the API Co-Signer Callback Handler here**
## Overview
When your API Co-signer is configured with a Callback Handler, it sends a POST request to the Callback Handler. The POST request contains a JSON Web Token (JWT) encoded message signed with the API Co-Signer's private key. The Callback Handler uses the API Co-signer's public key to verify that every incoming JWT is signed correctly by the API Co-signer.
The Callback Handler's response is a JWT-encoded message signed with the Callback Handler's private key. This private key must be paired with the public key provided to the API Co-signer during the Callback Handler's setup.
***
## Keys Generation
* Generate a private key using the following command:
`openssl genrsa -out callback_private.pem 2048`
> **Important**
>
> Fireblocks only supports RSA key 2048 bit for public key Callback Handler authentication.
* Export the public key from the previously generated private key using the following command:
`openssl rsa -in callback_private.pem -outform PEM -pubout -out callback_public.pem`
* Write your callback logic, which should include checking that the message can be decoded using the API Co-signer public key. The API Co-signer public key can be obtained by running the command:
`./cosigner print-public-key`
Save the cosigner public key in a file on your Callback Handler server - `cosigner_public.pem`
* Set up an HTTPS server with a certificate signed by a trusted CA. Make sure the route has a "/v2" prefix. Your callback handler endpoints should respond to requests that include a “/v2” prefix: [https://your\_callback\_base\_url/v2/tx\_sign\_request](https://your_callback_base_url/v2/tx_sign_request) or [https://your\_callback\_base\_url/v2/config\_change\_sign\_request](https://your_callback_base_url/v2/config_change_sign_request)
> **Note:**
>
> When adding the Callback Handler URL to the Co-signer, you should pass only the base URL + custom relative path.
> The `` or `` relative paths will be automatically added upon each request made by the Co-signer.
>
> For example if you exposed the Callback Handler URL in the following path:
> [https://subdomain.example.com/fireblocks/callback\_handler/v2/tx\_sign\_request](https://subdomain.example.com/fireblocks/callback_handler/v2/tx_sign_request)
>
> You should configure the following URL in the Co-signer:
> [https://subdomain.example.com/fireblocks/callback\_handler](https://subdomain.example.com/fireblocks/callback_handler)
# Automation Webhooks
Source: https://developers.fireblocks.com/reference/automation-webhooks
> **Deprecation notice**
>
> Webhooks v1 will be deprecated on **June 15th, 2026**. Please use the Developer Center in the Fireblocks Console to upgrade to Webhooks V2, which offers improved reliability, performance, and observability.
This page describes all events relating to Fireblocks Automations that produce Webhook notifications, and their associated data objects.
The `type` parameter is automatically set to the description name for the data objects below.
## Automation Run
An AUTOMATION\_EXECUTION\_WEBHOOK\_UPDATE webhook is sent when an automation rule runs.
| Parameter | Type | Description |
| ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| ruleId | string | Unique ID for the Automation rule as a ratio to executions (1/N) |
| executionId | string | Number of times this rule has been executed |
| state | enum | Current status of the rule. Available values: `CREATED`; `TRIGGERED`; `CONDITION_MET`; `CONDITION_NOT_MET`; `EXECUTED`; `FAILED` |
| trigger | enum | Available values: `TIME`; `TRANSACTION` |
| condition | enum | Available values: `BALANCE`; `TRANSACTION_AMOUNT`; `UNCONDITIONAL` |
| actions | enum | Available values: `TRANSFER`; `TOP_UP`; `REBALANCE`; `START_WORKFLOW`; `CONVERT`; `SWEEP` |
| createdAt | number | The time the rule was created, in milliseconds (epoch) |
| createdBy | string | ID of the user who created the rule |
| rule | string | Name of the Automation Rule |
| failure | enum | Available values: `CONDITION_CHECK_FAILED`, `ACTION_FAILED`, `EXECUTION_FAILED` |
# Introduction
Source: https://developers.fireblocks.com/reference/background-retail-demo-application
The Fireblocks Retail Demo application is designed to support Fireblocks clients by serving as a reference model for their integration processes. It embodies the best practices Fireblocks advocates for building secure, retail-facing solutions.
This demo aims to accelerate and simplify the integration of Fireblocks into your projects, ensuring that you adhere to the recommended best practices when building on the Fireblocks platform.
This article provides the necessary background on the considerations we had in mind when planning the demo application and developing its business logic.
**Vault Structure**
First, it's essential to understand how to best structure your Fireblocks workspace, vault accounts, and asset wallets to serve the requirements of a retail crypto application.
There are generally [two main approaches for vault structuring](https://support.fireblocks.io/hc/en-us/articles/5253421857564-Fireblocks-Vault-structure-best-practices): Omnibus and Segregated. The [Omnibus](https://support.fireblocks.io/hc/en-us/articles/6986895761948-Account-and-wallet-structure) vault structure is usually the more fitting selection when planning a retail-facing product, as it offers a more efficient way to handle end-user deposits, balance management, and withdrawals in fewer transactions with better fee management than using a segregated structure.
In our implementation, we have used a central Omnibus vault account to hold end-user funds. UTXO-based assets (e.g., BTC) are deposited by the end-users directly into the Omnibus vault using a dedicated deposit address for each user deposit, while account-based assets (e.g., ETH) are deposited to intermediate deposit vault accounts and later swept to the Omnibus vault.
Additionally, we are using three designated withdrawal vaults to allow high withdrawal throughput. Using multiple withdrawal vaults allows for more robust withdrawal handling, as withdrawal requests might queue up into a long backlog due to an unconfirmed transaction of a specific asset from a withdrawal wallet. Such backlog scenarios should be handled with dedicated business logic, but generally speaking, having several withdrawal vaults ensures your application can maintain a steady and robust withdrawal throughput.
The configuration of the Fireblocks workspace vaults and wallets is done by the application's [setup script](/reference/setup#setup-script) upon running the app for the first time.
**End-user wallets**
A retail application, potentially serving millions of end-users, must be able to create and operate millions of crypto deposit addresses, assign them to the correct end-user accounts in our internal ledger, and manage their balances correctly. When planning the application, we must consider which types of assets we will support (UTXO-based / Account-based / Tag or Memo-based), as different types require different wallet creation and management approaches.
When an end-user logs in for the first time, we need to generate an account or wallet entity for that user that will hold all of their deposit addresses for the assets we support. Depending on the asset type, different business logic will occur in the backend when the user asks for a new deposit address.
For UTXO or Tag/Memo-based assets (such as BTC, ADA, etc.), we will create a new dedicated **deposit address** inside the Omnibus vault account and assign it to the user account in our database (our internal ledger).
For Account-based assets (such as ETH, SOL, etc.), we will create a new intermediate **vault account** and then create a deposit address inside this dedicated intermediate vault account whenever a user requests a new deposit address. One can improve this process by first checking if the user already has an unused vault account that doesn't yet have the requested asset's wallet. If such an account exists, we can use it to create the new deposit address instead of creating a new vault account each time the user requests a new address.
Additionally, as the process of generating a deposit address for account-based assets will usually require two API calls to Fireblocks (one for creating the new vault account and one for generating the deposit address), it will be beneficial to add a job-like service that will pre-create vault accounts in batches. Once an end-user requests a new deposit address, the backend process will use a ready vault account when creating the deposit address and assign it to the relevant end-user (rename the vault account with a user reference ID and update the internal ledger accordingly).
In our implementation, this business logic is mainly handled by the [VaultAccount service](https://github.com/fireblocks/retail-demo/blob/main/backend/src/service/fireblocks/vaultAccount.service.ts).
**Deposit Management - Sweeping and UTXO Consolidation**
Another aspect we must consider when planning a retail crypto application is the [sweeping](/reference/sweep-to-omnibus-1#sweeping) of account-based assets to the Omnibus vault account. For UTXO asset deposits, we must have a mechanism that will [consolidate](/reference/consolidate-utxos) our Omnibus wallet inputs (coming from end-user deposits) into larger UTXOs that allow more efficient processes down the line, such as internal rebalancing transactions and end-user withdrawals.
**Sweeping**
When designing the sweeping mechanism, we should take into account several considerations, such as:
* Triggering (when should we sweep the intermediate vaults?)
* Sorting (which vaults should be swept now?)
* Gas balances (gas top-ups for token sweeping)
* Asset sweeping order (sweep tokens before base assets)
In our implementation, we trigger the sweeping mechanism based on a simple [time interval](https://github.com/fireblocks/retail-demo/blob/6f3dabed7cf7cab0435462fb17d409d62839cfad/backend/src/service/sweeping.service.ts#L13), but other possible and more complex approaches might be based on a set threshold of incoming deposits of account-based assets or based on monitoring gas rates in a given network to trigger the sweeping mechanism only when gas rates are relatively low, as a more cost-effective approach. As for sorting, we are querying the database for all user wallets that have a balance higher than a set threshold of a "sweepable" asset (account-based) and mapping the balances to the relevant Fireblocks vault account IDs so we can iterate through them and trigger the sweeping transactions accordingly. Based on your logic for triggering the sweeping process, you can also change the flow for sorting and selecting which intermediate vaults to sweep.
The business logic of account-based asset sweeping is handled by the Sweeping service .
**UTXO Consolidation**
In Fireblocks, a UTXO-based asset transaction can consist of up to 250 inputs, and the default input selection mechanism selects inputs from the lowest to the highest value. These presets can lead to a situation where, in a high-volume crypto retail application that may receive numerous deposits of small amounts of tokens from end-users, the ever-growing list of small UTXOs will have the sufficient balance to support a transaction request from the Omnibus wallet with a large amount. Having a UTXO consolidation solution implemented correctly will help prevent such a situation and ensure the application's high throughput operation at all times.
In our implementation, we've created two UTXO consolidation jobs, one of which is a backup process for the first routine job.
We maintain a deposit counter for every UTXO asset the application supports in our database. Once the counter reaches 249 deposits, the routine consolidation job is triggered and will perform a consolidation transaction and reset the counter. The backup process runs every day and checks if any of the UTXO assets in the Omnibus wallet have 250 unspent inputs or more. This check is done with the [Fireblocks API](/reference/getunspentinputs) directly on the Omnibus vault account and adds another safeguard to the consolidation process. If 250 inputs or more are found, consolidation transactions will be triggered until that condition is no longer met.
A consolidation transaction will have the Omnibus vault account as both the source and the destination. This will ensure that the Omnibus wallet will have inputs with high value available for future transactions.
The business logic of UTXO consolidation is handled by the [consolidation service](https://github.com/fireblocks/retail-demo/blob/main/backend/src/service/consolidation.service.ts).
**Internal Rebalancing**
As mentioned above, a scalable retail crypto application must have several dedicated withdrawal vault accounts to support a high throughput of withdrawals. To function effectively, these vaults must maintain a sufficient balance of all supported assets at any given time. To achieve this, we need an internal rebalancing mechanism that ensures all withdrawal vaults are always funded. This mechanism can be developed programmatically using Fireblocks APIs, but in our implementation, we chose to leverage the new [automation](https://support.fireblocks.io/hc/en-us/articles/14873112741660-Automation) feature. This feature allows us to set up automatic triggers within Fireblocks if the asset's balance is lower than a set threshold after a withdrawal transaction is processed and completed.
Below is an example of such an automation we've configured in our testnet workspace.
This rebalancing approach will require you to set a minimum and a maximum threshold per asset you support. The minimum threshold will be the triggering amount of a rebalancing transaction, and the maximum threshold will be the amount the withdrawal vault will be topped up to after the rebalancing transaction is completed.
**End User Withdrawals**
End-user withdrawals are a crucial phase in the lifecycle of a retail crypto application, deeply affecting the platform's reputation. To handle a high volume of withdrawal requests efficiently, utilizing multiple dedicated withdrawal vault accounts is recommended. Besides this strategy, there are key considerations for robust withdrawal logic.
A solid withdrawal system should:
* Validate User Balances: Check that the user's available balance is sufficient to cover the withdrawal amount and any associated fees.
* Rotate Withdrawal Vaults: Incorporate a method, such as a random selection process, to alternate between different withdrawal vault accounts as transaction sources.
In our approach, we've implemented a straightforward randomization logic. The application randomly picks a number corresponding to one of the available withdrawal vault accounts (e.g., selecting between 1 and 3). This determines the vault account ID used for the transaction source. [See our code example here](https://github.com/fireblocks/retail-demo/blob/6f3dabed7cf7cab0435462fb17d409d62839cfad/backend/src/utils/vaultConfig.ts#L37).
The withdrawal flow is handled by the [transaction controller](https://github.com/fireblocks/retail-demo/blob/6f3dabed7cf7cab0435462fb17d409d62839cfad/backend/src/controller/transaction.controller.ts#L55) and the [transaction service](https://github.com/fireblocks/retail-demo/blob/6f3dabed7cf7cab0435462fb17d409d62839cfad/backend/src/service/fireblocks/transaction.service.ts).
# Balance validation
Source: https://developers.fireblocks.com/reference/balance-validation
## Method 3: Balance Validation
Balance validation verifies webhook transaction data against the Fireblocks API, protecting against stale or inconsistent data.
For our Validate Balances article, see [here](/docs/validate-balances).
# Basic Callback Handler example
Source: https://developers.fireblocks.com/reference/basic-code-example
## Request payload example
This example demonstrates the raw and decoded JWT payload sent by the Co-Signer to the Callback Handler.
Additionally, it includes a test private key that signed the payload and the corresponding public key that should be used for signature validation:
> **The provided Private Key is for example purposes only and should not be used in your production system.**
> **The provided example may contain properties that are not sent by default. Customers should ensure they DO NOT expect to receive values that are not documented in the Approve Transactions and Approve Configuration Changes sections.**
```text theme={"system"}
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eElkIjoiOWM3OTRjZWUtN2UyNy00NmM5LTllOWEtZWQ2ODI5NWZmMDZiIiwib3BlcmF0aW9uIjoiVFJBTlNGRVIiLCJzb3VyY2VUeXBlIjoiVkFVTFQiLCJzb3VyY2VJZCI6IjAiLCJkZXN0VHlwZSI6IlZBVUxUIiwiZGVzdElkIjoiMSIsImFzc2V0IjoiRVRIIiwiYW1vdW50IjowLjAxLCJhbW91bnRTdHIiOiIwLjAxMDAwMDAwMDAwMDAwMDAwMCIsInJlcXVlc3RlZEFtb3VudCI6MC4wMSwicmVxdWVzdGVkQW1vdW50U3RyIjoiMC4wMSIsImZlZSI6IjAuMDAwNTk3ODAzNzYyMjQxMDAwIiwiZGVzdEFkZHJlc3NUeXBlIjoiV0hJVEVMSVNURUQiLCJkZXN0QWRkcmVzcyI6IjB4NWRDNjlCMUZiYjEzQmFmZDA5YWY4OGE3ODJGMEYyODU3NzJBZDVmOCIsImRlc3RpbmF0aW9ucyI6W3siYW1vdW50TmF0aXZlIjowLjAxLCJhbW91bnROYXRpdmVTdHIiOiIwLjAxIiwiYW1vdW50VVNEIjoxOC43NDI5MjkzNywiZHN0QWRkcmVzc1R5cGUiOiJXSElURUxJU1RFRCIsImRzdElkIjoiMSIsImRzdFdhbGxldElkIjoiIiwiZHN0TmFtZSI6Ik5ldHdvcmsgRGVwb3NpdHMiLCJkc3RTdWJUeXBlIjoiIiwiZHN0VHlwZSI6IlZBVUxUIiwiZGlzcGxheURzdEFkZHJlc3MiOiIweDVkQzY5QjFGYmIxM0JhZmQwOWFmODhhNzgyRjBGMjg1NzcyQWQ1ZjgiLCJhY3Rpb24iOiJBTExPVyIsImFjdGlvbkluZm8iOnsiY2FwdHVyZWRSdWxlTnVtIjo1LCJydWxlc1NuYXBzaG90SWQiOjgxNjQsImJ5R2xvYmFsUG9saWN5IjpmYWxzZSwiYnlSdWxlIjp0cnVlLCJjYXB0dXJlZFJ1bGUiOiJ7XCJ0eXBlXCI6XCJUUkFOU0ZFUlwiLFwidHJhbnNhY3Rpb25UeXBlXCI6XCJUUkFOU0ZFUlwiLFwiYXNzZXRcIjpcIipcIixcImFtb3VudFwiOjAsXCJvcGVyYXRvcnNcIjp7XCJ3aWxkY2FyZFwiOlwiKlwifSxcImFwcGx5Rm9yQXBwcm92ZVwiOnRydWUsXCJhY3Rpb25cIjpcIkFMTE9XXCIsXCJzcmNcIjp7XCJpZHNcIjpbW1wiKlwiXV19LFwiZHN0XCI6e1wiaWRzXCI6W1tcIipcIl1dfSxcImRzdEFkZHJlc3NUeXBlXCI6XCIqXCIsXCJhbW91bnRDdXJyZW5jeVwiOlwiVVNEXCIsXCJhbW91bnRTY29wZVwiOlwiU0lOR0xFX1RYXCIsXCJwZXJpb2RTZWNcIjowfSJ9fV0sInJhd1R4IjpbeyJrZXlEZXJpdmF0aW9uUGF0aCI6IlsgNDQsIDYwLCAwLCAwLCAwIF0iLCJyYXdUeCI6IjAyZWYwMTA0ODQzYjlhY2EwMDg1MDZhMGMxOTg3ZDgyNTIwODk0NWRjNjliMWZiYjEzYmFmZDA5YWY4OGE3ODJmMGYyODU3NzJhZDVmODg3MjM4NmYyNmZjMTAwMDA4MGMwIiwicGF5bG9hZCI6Ijc3YjRlNzQwOTljZTkwYzA4NTAzYzBlMGJiNmU2NzJkYmUxYzVlM2UxMjdjZTMzM2JmMjJlYjU4MWNkM2Y2Y2UifV0sInBsYXllcnMiOlsiMjE5MjZlY2MtNGE4YS00NjE0LWJiYWMtN2M1OTFhYTdlZmRkIiwiMjc5MDA3MzctNDZmNi00MDk3LWExNjktZDBmZjQ1NjQ5ZWQ1IiwiZjg5Y2FjNTAtYzY1Ni00ZTc0LTg3OWYtMDQxYWZmOGQwMWI1Il0sInJlcXVlc3RJZCI6IjljNzk0Y2VlLTdlMjctNDZjOS05ZTlhLWVkNjgyOTVmZjA2YiJ9.aE1ZOSQreBU23q3e-Dx6Z76tFgURfDU8Szj1XESN1-LczwFpCXJeexOLJ4L5IoAHpp8FV8f1vg1yu_-iV1ZiPsCR8K9fcLQmTGF21Y43w18s1nvY8rqSKX64sHDWoBTUN1oJFhjzzi1ovpmcASBj3_yWJIv6-RfW20l30_f6ggMXZDE0QImCSYtRL2m5YIBr8wVe2rMleFLCQLUQTLVXyE-oxxbCfy-R_FqWv-dn7CaQSFkztm8fCn2_jnxlHs0phuOxSucwrOM7UkVr7qM8uTWhvdeTkYPjVBcj5lpgYwb8Fo2F0fnIvgcvRaz8r4LjVrj6hVwRHH809jt0ouzVeg
```
```json theme={"system"}
{
"txId": "9c794cee-7e27-46c9-9e9a-ed68295ff06b",
"operation": "TRANSFER",
"sourceType": "VAULT",
"sourceId": "0",
"destType": "VAULT",
"destId": "1",
"asset": "ETH",
"amount": 0.01,
"amountStr": "0.010000000000000000",
"requestedAmount": 0.01,
"requestedAmountStr": "0.01",
"fee": "0.000597803762241000",
"destAddressType": "WHITELISTED",
"destAddress": "0x5dC69B1Fbb13Bafd09af88a782F0F285772Ad5f8",
"destinations": [
{
"amountNative": 0.01,
"amountNativeStr": "0.01",
"amountUSD": 18.74292937,
"dstAddressType": "WHITELISTED",
"dstId": "1",
"dstWalletId": "",
"dstName": "Network Deposits",
"dstSubType": "",
"dstType": "VAULT",
"displayDstAddress": "0x5dC69B1Fbb13Bafd09af88a782F0F285772Ad5f8",
"action": "ALLOW",
"actionInfo": {
"capturedRuleNum": 5,
"rulesSnapshotId": 8164,
"byGlobalPolicy": false,
"byRule": true,
"capturedRule": "{\"type\":\"TRANSFER\",\"transactionType\":\"TRANSFER\",\"asset\":\"*\",\"amount\":0,\"operators\":{\"wildcard\":\"*\"},\"applyForApprove\":true,\"action\":\"ALLOW\",\"src\":{\"ids\":[[\"*\"]]},\"dst\":{\"ids\":[[\"*\"]]},\"dstAddressType\":\"*\",\"amountCurrency\":\"USD\",\"amountScope\":\"SINGLE_TX\",\"periodSec\":0}"
}
}
],
"rawTx": [
{
"keyDerivationPath": "[ 44, 60, 0, 0, 0 ]",
"rawTx": "02ef0104843b9aca008506a0c1987d825208945dc69b1fbb13bafd09af88a782f0f285772ad5f8872386f26fc1000080c0",
"payload": "77b4e74099ce90c08503c0e0bb6e672dbe1c5e3e127ce333bf22eb581cd3f6ce"
}
],
"players": [
"21926ecc-4a8a-4614-bbac-7c591aa7efdd",
"27900737-46f6-4097-a169-d0ff45649ed5",
"f89cac50-c656-4e74-879f-041aff8d01b5"
],
"requestId": "9c794cee-7e27-46c9-9e9a-ed68295ff06b"
}
```
```yaml theme={"system"}
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJtgGHPlbV5KB1
yzPslxYnFiYeogUX0w6rd9Ee+zAljQ2msEP45NCaHwPX6fsukQnw+w7hlvr52aVR
vKJKFmXnNMTSEd9v358053gJCzyVd9hKFnVO/04uwFTIwXX11VPd8XWZy6ue8meE
qztGfJJvvDtHnbmJUFgf48DBv04hUzDm7yS2CJsO0UR91WQRwlTDkMUs4b2jJ4AN
oLFaHlw+HAkKQH+O4g+WEfq+GQWnxq57L5U90TH4/+vELy54gOicojww6t/rTrjz
WRjzJxfE6Ue3Tbpf7tfVMrlCsD+q3958q+m5a6O/KmwyfMo6P/yUt66W1KhK4Wmg
v6YGY8J7AgMBAAECggEAG/rcvxNlJ+S/uLHta8n7dIQ3LnRKtjwnIp7gtGZN4++V
2gOaXNSfS7m1+/CE0Lf6w+GMy2XOPkk0DEtZIbjLUuU4Jhb87P+n4xv2mR6PaAEI
piJJDHe6sx59GZ9IYHJCi3IP3ju+fIe4gf00oDmYddpg82AMGWGP5Ss1FPXB/eTV
QT+5qwnZz2qqkzpk8QDcNjK/fsuuIaJg6RDC5NbXFuMr4NXKkXzDPkmzCgFowHAR
J5Jqf4y2YArKV7kwEgW+naUAESPLWFUCaoLmCJxw7fbqHkUHYKHfWk9M9t9C0boL
b0G9zbsAI/ip9YxuKzXi0E8lTkFH8q7Fssa5m/Gp/QKBgQD057qo2hq2zWXRXZ7W
Q9nta3uNdsxhRPeC/z9ejUIy4kC7/ZbQ04+i+Tefwz4kjSVxSobb4Y7Bh8e4/tpw
alyvTIyEys25G6vkFJh8MXojxQEgU1ImMnsFEqZVKsUilz/+aDG3POvihF4jwKbF
GJCUhFG8mFzsFQLtYKmmp5NOXQKBgQDS2VWyS3d7arZyAdCjI3pw+SV/iF/bJ7wT
NK2N6RHpfVwnnDk/AyFxQy2k53VwXASwYVsDkEZiPz1lqlV5xltcx3GDR5xhRdol
M4i0H+Qc+bYXjy+O99LYgRODzTsq8PQmUADL9xAF+Df3CW4sTZ5Izi46Hq9uMFa6
bA0IH5nWtwKBgGkuuUFZ4w1N7APelKBrpcZNWlQoiKDiEPenDp1aR+s4txrGUCbC
JjeVl6k7Ho5uPH2Kx57aIgjGeyXd9w0+8S2sz9EclPyCgPHFUrRMP6vrKY+rmWWk
WqeUGfIMG3y+vxJRx8BuHtU7in8Kd9XAth/DMKOyQH54i7hNwq87241VAoGAQax6
Oc+xxppFe5s/HiFF2Pxxhpi2qq9ksGK/EC2ha6WlV50cY5kZCItRI0UI2ld/CmU4
kRKWKbHi8NCuUQDMokho/egHOHEmcmHr2Zb5WWEaK5poyNI+NTt3FZ2OKWDl2y0e
Immw7vsSi3q/e0Mt4yV9VpMKN3sM+IIBSR92rl8CgYEAlfUVoSXRVOxh29dI65Qi
5IfJmg1mQnHWE2RfuZqtTcYisvbQejygsoyh1ZydEUSsX5rUbkc3/qqW5N4pEYVt
ZHCn7MJHot44SA3XDn2dGRQAL5UQJJK5nHRVeBuoJtnNyzhxbZH3M56sT4o5i6UC
TFalBSOqnaPpYIxV2fgCdyE=
-----END PRIVATE KEY-----
```
```yaml theme={"system"}
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAybYBhz5W1eSgdcsz7JcW
JxYmHqIFF9MOq3fRHvswJY0NprBD+OTQmh8D1+n7LpEJ8PsO4Zb6+dmlUbyiShZl
5zTE0hHfb9+fNOd4CQs8lXfYShZ1Tv9OLsBUyMF19dVT3fF1mcurnvJnhKs7RnyS
b7w7R525iVBYH+PAwb9OIVMw5u8ktgibDtFEfdVkEcJUw5DFLOG9oyeADaCxWh5c
PhwJCkB/juIPlhH6vhkFp8auey+VPdEx+P/rxC8ueIDonKI8MOrf606481kY8ycX
xOlHt026X+7X1TK5QrA/qt/efKvpuWujvypsMnzKOj/8lLeultSoSuFpoL+mBmPC
ewIDAQAB
-----END PUBLIC KEY-----
```
***
## Response payload example
This example demonstrates the raw and decoded JWT response returned from the Callback Handler to the Co-signer. The response is signed using the Callback Handler's private key. The Co-signer then verifies the signature using the predefined public key configured during the Co-signer installation phase.
For simplicity, the examples use the same private/public key pair as in the **Request Example** section:
> **Please note that the iat value is not required in the actual response and will be ignored by the Co-Signer. It is included here because the JWT signature library automatically adds this field.**
```text theme={"system"}
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY3Rpb24iOiJSRUpFQ1QiLCJyZXF1ZXN0SWQiOiI5Yzc5NGNlZS03ZTI3LTQ2YzktOWU5YS1lZDY4Mjk1ZmYwNmIiLCJyZWplY3Rpb25SZWFzb24iOiJMb2dpYyByZXR1cm5lZCBmYWxzZSIsImlhdCI6MTcyMDQ3MjU5NH0.CGJ7D0KHb2K0F0ibStAAy8MyvXIZR-sQsFRiHRebXPEVMOdjEooaDac9PZYTgmuMJANDtsDAy9bbIggaTraeGxLtHPS4TvQdOA1GX74gWlkBHktJxtGxngsSwbZ-clvCSrwQ0AQcwqCv1OozXRmt_SGberuJpVIUbNc1HWlKAbti4dIcN_irTp2Xwq9WmGRwF16rkK97JdtMbhPBF9t56kdYrHccKU9q69_4Q7zG8I9yXgYKTQ1XctJiGjg06dPR3fDEVeN_ibUXSU5h1sXnd3gvpbUNmEOYAREDKZAk_FMSdMmiC9Prp0t9g-xDtoSear6vN-ovxk_64AwMLxqsEg
```
```json theme={"system"}
{
"action": "REJECT",
"requestId": "9c794cee-7e27-46c9-9e9a-ed68295ff06b",
"rejectionReason": "Logic returned false",
"iat": 1720472594
}
```
***
## API Co-Signer basic Callback Handler server example
Here is a code example for a basic Callback Handler application. The application is designed to handle POST requests from the Co-signer at the endpoint /v2/tx\_sign\_request.
* It validates that the received payload is signed with the correct private key.
* If the verification is successful, it responds with a 200 status code, the `REJECT` action, and the `rejectionReason` in the response body.
* If the verification fails, it responds with a 401 status code.
```javascript theme={"system"}
const express = require("express");
const bodyParser = require("body-parser");
const fs = require("fs");
const jwt = require("jsonwebtoken");
const privateKey = fs.readFileSync("callback_private.pem");
const cosignerPubKey = fs.readFileSync("cosigner_public.pem");
const app = express();
app.use(
express.urlencoded({
extended: true
})
);
app.use(express.json());
app.use(function (req) {
req.rawBody = "";
req.setEncoding("utf8");
req.on("data", function(chunk) {
req.rawBody += chunk;
});
req.on("end", function () {
req.next();
});
});
app.post("/v2/tx_sign_request", async (req, res) => {
let verified;
try {
const tx = jwt.decode(req.rawBody);
const { requestId } = tx;
verified = jwt.verify(req.rawBody, cosignerPubKey);
if (verified) {
let action = "REJECT";
let rejectionReason = "Logic returned false";
const signedRes = jwt.sign(
{
action,
requestId,
rejectionReason
},
privateKey,
{ algorithm: "RS256" }
);
res.send(signedRes);
}
} catch (e) {
res.sendStatus(401);
}
});
app.listen(3000);
```
```python theme={"system"}
from pathlib import Path
from wsgiref.simple_server import make_server
import falcon
import jwt
callback_handler_prikey = None
cosigner_pubkey = None
# Load keys.
f1 = Path("callback_private.pem")
if f1.is_file(): callback_handler_prikey = f1.read_bytes()
f2 = Path("cosigner_public.pem")
if f2.is_file(): cosigner_pubkey = f2.read_bytes()
class JWTTransferRequest(object):
def on_post(self, req, resp):
raw_req = req.bounded_stream.read()
req = jwt.decode(raw_req, cosigner_pubkey, algorithms=["RS256"])
resp.body = jwt.encode({'action': 'APPROVE', 'requestId': req['requestId']}, callback_handler_prikey, algorithm="RS256")
resp.status = falcon.HTTP_200
# Create falcon app
app = falcon.App()
app.add_route('/v2/tx_sign_request', JWTTransferRequest())
app.add_route('/v2/config_change_sign_request', JWTTransferRequest())
if __name__ == '__main__':
with make_server('', 80, app) as httpd:
print('Serving on port 80...')
# Serve until process is killed
httpd.serve_forever()
JWTTransferRequest()
```
# Bring your own screening check developer guide
Source: https://developers.fireblocks.com/reference/bring-your-own-screening-check-developer-guide
Bring Your Own Screening Check lets you add a manual review step to Fireblocks transaction screening. After automatic AML screening completes, eligible transactions pause for your verdict before Travel Rule processing begins. For a conceptual overview, see [Bring Your Own Screening Check](https://support.fireblocks.io/hc/en-us/articles/26230042914076-Bring-Your-Own-Screening-Check-Integration-Guide) (requires Help Center login).
## Quickstart
Follow these steps to set up and activate Bring Your Own Screening Check:
1. Contact your Customer Success Manager to enable the feature for your workspace.
2. Configure incoming and outgoing timeouts with `PUT /v1/screening/byork/config/timeouts`.
3. Open a support ticket to configure your pre-screening rules.
4. Set up your webhook listener for screening events.
5. Test your verdict API integration in the sandbox environment.
6. Activate the feature with `POST /v1/screening/byork/config/activate`.
7. Monitor verdict submission latency against your configured timeouts.
## Configuration
### Get current configuration
```http theme={"system"}
GET /v1/screening/byork/config
```
Returns your current configuration, including timeouts and active status.
#### Response example
```json theme={"system"}
{
"active": false,
"incomingTimeoutSeconds": 3600,
"outgoingTimeoutSeconds": 3600,
"provider": "BYORK_LITE",
"lastUpdate": "2026-03-01T00:00:00.000Z",
"timeoutRangeIncoming": { "minSeconds": 10, "maxSeconds": 604800 },
"timeoutRangeOutgoing": { "minSeconds": 10, "maxSeconds": 604800 }
}
```
| Field | Type | Description |
| ------------------------ | ------- | ---------------------------------------------------------------------------------------------------- |
| `active` | boolean | Whether the feature is currently active for your tenant |
| `incomingTimeoutSeconds` | number | Verdict timeout for incoming transactions (seconds) |
| `outgoingTimeoutSeconds` | number | Verdict timeout for outgoing transactions (seconds) |
| `preScreeningRules` | array | Configured pre-screening rules. See [Pre-screening rules reference](#pre-screening-rules-reference). |
| `provider` | string | Provider identifier (e.g., `BYORK_LITE`) |
| `lastUpdate` | string | ISO 8601 timestamp of the last configuration update |
| `timeoutRangeIncoming` | object | Valid min/max bounds for `incomingTimeoutSeconds` |
| `timeoutRangeOutgoing` | object | Valid min/max bounds for `outgoingTimeoutSeconds` |
### Set timeouts
Configure how long the system waits for your verdict before auto-rejecting a transaction. Timeouts are set separately for incoming and outgoing transactions.
Always submit your verdict before the timeout expires. Once the timeout is reached, Fireblocks automatically rejects the transaction and the rejection cannot be reversed.
#### Request
```http theme={"system"}
PUT /v1/screening/byork/config/timeouts
```
Include at least one of `incomingTimeoutSeconds` or `outgoingTimeoutSeconds` in the request body. The response returns the full updated configuration.
#### Response example
```json theme={"system"}
{
"incomingTimeoutSeconds": 7200,
"outgoingTimeoutSeconds": 3600
}
```
| Parameter | Default | Min | Max |
| ------------------------ | ------- | --- | -------------------- |
| `incomingTimeoutSeconds` | 3600 | 10 | 604800 (7 days) |
| `outgoingTimeoutSeconds` | 3600 | 10 | JWT lifetime − 1800s |
### Configure pre-screening rules
Pre-screening rules determine which transactions are held for review and which bypass the check. Rules are evaluated in order — the first match wins. Omitted fields match any value.
To configure or update your pre-screening rules, open a support ticket. See [Pre-screening rules reference](#pre-screening-rules-reference) for the full list of available rule fields.
### Activate and deactivate
Once your timeouts and rules are set, activate to start screening transactions:
```http theme={"system"}
POST /v1/screening/byork/config/activate
```
To pause screening without removing your configuration:
```http theme={"system"}
POST /v1/screening/byork/config/deactivate
```
Both endpoints return the full updated configuration. When deactivated, all transactions bypass the review step and continue to Travel Rule or completion.
## Submitting verdicts
### Submit a verdict
```http theme={"system"}
POST /v1/screening/byork/verdict
```
Use an [idempotency key](/reference/api-idempotency) on `POST verdict` to avoid duplicate submissions.
#### Request body
```json theme={"system"}
{
"txId": "3b9cc47a-f8c2-4b09-9b1f-e12a53d9f74c",
"verdict": "ACCEPT"
}
```
| Field | Type | Description |
| --------- | ------ | ------------------------- |
| `txId` | string | Fireblocks transaction ID |
| `verdict` | string | `ACCEPT` or `REJECT` |
#### Response example
```json theme={"system"}
{
"status": "COMPLETED",
"message": "Verdict ACCEPT applied"
}
```
### Get verdict status
```http theme={"system"}
GET /v1/screening/byork/verdict?txId={txId}
```
Returns the current verdict status for a transaction.
| Status | Description |
| -------------- | ------------------------------------------------------------------------- |
| `PRE_ACCEPTED` | Verdict submitted before the wait step was reached; applied automatically |
| `PENDING` | The transaction is waiting for a verdict |
| `RECEIVED` | Verdict received and being applied |
| `COMPLETED` | Verdict applied; transaction continues |
## Pre-acceptance
You can submit a verdict before a transaction reaches the review wait step — for example, while automatic AML screening is still running. Fireblocks stores the verdict and applies it automatically when the transaction reaches the waiting state.
This is useful when you have already completed your own review and want to avoid any delay.
### Request
```http theme={"system"}
POST /v1/screening/byork/verdict
```
### Response example
```json theme={"system"}
{
"txId": "3b9cc47a-f8c2-4b09-9b1f-e12a53d9f74c",
"verdict": "ACCEPT"
}
```
The response returns `"status": "PRE_ACCEPTED"` if the transaction has not reached the wait step yet.
## Error handling
| HTTP status | Meaning | Action |
| ----------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `400 Bad Request` | Bring Your Own Screening Check not enabled for tenant, or invalid payload | Check that the feature is enabled and the request body is correct |
| `404 Not Found` | No verdict found for this transaction (GET only) | Verify `txId` is correct and the transaction has reached the screening step |
| `409 Conflict` | Verdict already submitted, or transaction screening is complete | Do not retry; verdict is final |
| `425 Too Early` | Transaction not found yet; screening has not started | Retry after a short delay |
## Pre-screening rules reference
Rules are evaluated in order. The first matching rule determines whether the transaction is held for review (`SCREEN`) or bypasses it (`PASS`).
| Field | Type | Description |
| --------------------- | ------- | ------------------------------------------------------------------- |
| `sourceWorkspaceName` | string | Source workspace name. For incoming transactions. |
| `destWorkspaceName` | string | Destination workspace name. For outgoing transactions. |
| `sourceType` | string | Source address type (e.g., `VAULT_ACCOUNT`, `EXCHANGE`). |
| `sourceSubType` | string | Source address sub-type. |
| `sourceAddress` | string | Source on-chain address. |
| `sourceId` | string | ID of the source vault, exchange account, or unmanaged wallet. |
| `destType` | string | Destination address type. |
| `destSubType` | string | Destination address sub-type. |
| `destAddress` | string | Destination on-chain address. |
| `destId` | string | ID of the destination vault, exchange account, or unmanaged wallet. |
| `asset` | string | Asset ID (e.g., `BTC`, `ETH`). |
| `amount` | object | Amount range with currency. See [Amount object](#amount-object). |
| `operation` | string | Transaction operation type. |
| `direction` | string | `INBOUND` or `OUTBOUND`. Limits the rule to one direction. |
| `isDefault` | boolean | When `true`, applies when no other rule matches. |
| `action` | string | **Required.** `PASS` (skip review) or `SCREEN` (hold for verdict). |
### Amount object
```json theme={"system"}
{
"range": {
"min": "1000",
"max": "50000"
},
"currency": "USD"
}
```
`currency` is either `"USD"` (fiat-equivalent value) or `"NATIVE"` (on-chain amount). `min` and `max` are both optional.
# Caching Signatures
Source: https://developers.fireblocks.com/reference/caching-signatures
Some DeFi apps expect to receive the same signature for separate consecutive messages. Signature caching allows the most recent signature to be returned based on the content and the source, including the workspace ID, Vault account, and asset, or derivation path. This signature may be returned repeatedly, skipping additional approval and signing processes.
Signature caching is enabled for all users by default using [WalletConnect](https://support.fireblocks.io/hc/en-us/articles/5403817784732-Connecting-to-Web3-using-WalletConnect) or the [Fireblocks Chrome Extension](https://fireblocks.zendesk.com/hc/en-us/articles/5403962226332). However, you can opt out by [contacting Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new).
Signature caching also works with [Typed Messages](/docs/typed-message-signing-1) and [Raw Signing](/docs/raw-signing) via the Fireblocks API.
# Code Examples
Source: https://developers.fireblocks.com/reference/code-examples-1
> **Deprecation notice**
>
> Webhooks v1 will be deprecated on **June 15th, 2026**. Please use the Developer Center in the Fireblocks Console to upgrade to Webhooks V2, which offers improved reliability, performance, and observability.
Below are examples in Python and JavaScript demonstrating how to configure the webhook receiving endpoint on the customer's end, including the request validation mechanism:
> **Warning: For reference only**
>
> * These examples are **not production-ready** and are used only for reference.
> * These examples are configured to represent a production environment. Sandbox users should ensure they update the Public Key to the correct one, as mentioned [here](/reference/verify-requests).
```javascript theme={"system"}
const crypto = require("crypto");
const express = require("express");
const bodyParser = require('body-parser')
const port = 3000;
const publicKey = `-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0+6wd9OJQpK60ZI7qnZG
jjQ0wNFUHfRv85Tdyek8+ahlg1Ph8uhwl4N6DZw5LwLXhNjzAbQ8LGPxt36RUZl5
YlxTru0jZNKx5lslR+H4i936A4pKBjgiMmSkVwXD9HcfKHTp70GQ812+J0Fvti/v
4nrrUpc011Wo4F6omt1QcYsi4GTI5OsEbeKQ24BtUd6Z1Nm/EP7PfPxeb4CP8KOH
clM8K7OwBUfWrip8Ptljjz9BNOZUF94iyjJ/BIzGJjyCntho64ehpUYP8UJykLVd
CGcu7sVYWnknf1ZGLuqqZQt4qt7cUUhFGielssZP9N9x7wzaAIFcT3yQ+ELDu1SZ
dE4lZsf2uMyfj58V8GDOLLE233+LRsRbJ083x+e2mW5BdAGtGgQBusFfnmv5Bxqd
HgS55hsna5725/44tvxll261TgQvjGrTxwe7e5Ia3d2Syc+e89mXQaI/+cZnylNP
SwCCvx8mOM847T0XkVRX3ZrwXtHIA25uKsPJzUtksDnAowB91j7RJkjXxJcz3Vh1
4k182UFOTPRW9jzdWNSyWQGl/vpe9oQ4c2Ly15+/toBo4YXJeDdDnZ5c/O+KKadc
IMPBpnPrH/0O97uMPuED+nI6ISGOTMLZo35xJ96gPBwyG5s2QxIkKPXIrhgcgUnk
tSM7QYNhlftT4/yVvYnk0YcCAwEAAQ==
-----END PUBLIC KEY-----`.replace(/\\n/g, "\n");
const app = express();
app.use(bodyParser.json());
app.post("/webhook", (req, res) => {
const message = JSON.stringify(req.body);
const signature = req.headers["fireblocks-signature"];
const verifier = crypto.createVerify('RSA-SHA512');
verifier.write(message);
verifier.end();
const isVerified = verifier.verify(publicKey, signature, "base64");
console.log("Verified:", isVerified);
res.send("ok");
});
app.listen(port, () => {
console.log(`Webhook running at http://localhost:${port}`);
});
```
```python theme={"system"}
import falcon
import json
import rsa
import base64
FIREBLOCKS_PUBLIC_KEY = """
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0+6wd9OJQpK60ZI7qnZG
jjQ0wNFUHfRv85Tdyek8+ahlg1Ph8uhwl4N6DZw5LwLXhNjzAbQ8LGPxt36RUZl5
YlxTru0jZNKx5lslR+H4i936A4pKBjgiMmSkVwXD9HcfKHTp70GQ812+J0Fvti/v
4nrrUpc011Wo4F6omt1QcYsi4GTI5OsEbeKQ24BtUd6Z1Nm/EP7PfPxeb4CP8KOH
clM8K7OwBUfWrip8Ptljjz9BNOZUF94iyjJ/BIzGJjyCntho64ehpUYP8UJykLVd
CGcu7sVYWnknf1ZGLuqqZQt4qt7cUUhFGielssZP9N9x7wzaAIFcT3yQ+ELDu1SZ
dE4lZsf2uMyfj58V8GDOLLE233+LRsRbJ083x+e2mW5BdAGtGgQBusFfnmv5Bxqd
HgS55hsna5725/44tvxll261TgQvjGrTxwe7e5Ia3d2Syc+e89mXQaI/+cZnylNP
SwCCvx8mOM847T0XkVRX3ZrwXtHIA25uKsPJzUtksDnAowB91j7RJkjXxJcz3Vh1
4k182UFOTPRW9jzdWNSyWQGl/vpe9oQ4c2Ly15+/toBo4YXJeDdDnZ5c/O+KKadc
IMPBpnPrH/0O97uMPuED+nI6ISGOTMLZo35xJ96gPBwyG5s2QxIkKPXIrhgcgUnk
tSM7QYNhlftT4/yVvYnk0YcCAwEAAQ==
-----END PUBLIC KEY-----
"""
signature_pub_key = rsa.PublicKey.load_pkcs1_openssl_pem(FIREBLOCKS_PUBLIC_KEY)
class RequestBodyMiddleware(object):
def process_request(self, req, resp):
req.body = req.bounded_stream.read()
class AuthMiddleware(object):
def process_request(self, req, resp):
signature = req.get_header('Fireblocks-Signature')
if signature is None:
raise falcon.HTTPUnauthorized('Signature required')
if not self._signature_is_valid(req.body, signature):
raise falcon.HTTPUnauthorized('Invalid signature')
def _signature_is_valid(self, body, signature):
try:
hashing_alg = rsa.verify(body, base64.b64decode(signature), signature_pub_key)
return hashing_alg == "SHA-512"
except rsa.pkcs1.VerificationError:
return False
class DummyRequest(object):
def on_post(self, req, resp):
obj = json.loads(req.body.decode("utf-8"))
print(obj)
resp.status = falcon.HTTP_201
# Create falcon app
app = falcon.API(
middleware=[
RequestBodyMiddleware(),
AuthMiddleware()
]
)
app.add_route('/webhook', DummyRequest())
if __name__ == '__main__':
from wsgiref import simple_server # NOQA
httpd = simple_server.make_server('127.0.0.1', 8000, app)
httpd.serve_forever()
```
# Code Examples
Source: https://developers.fireblocks.com/reference/code-examples-2
# Bitcoin Arbitrary Message
> **BTC arbitrary message signing can be also performed by Typed Message signing and it is considered more secure. Check out our Typed Message guide**
The example below illustrates the use of the Raw Signing feature for Bitcoin arbitrary message signing:
```javascript theme={"system"}
import { readFileSync } from 'fs';
import {
Fireblocks,
BasePath,
TransactionOperation,
TransferPeerPathType,
TransactionRequest,
TransactionResponse,
FireblocksResponse,
TransactionStateEnum,
CreateTransactionResponse
} from "@fireblocks/ts-sdk";
import { createHash } from "crypto";
const FIREBLOCKS_API_SECRET_PATH = "";
const API_KEY = ""
// Initialize a Fireblocks API instance with local variables
const fireblocks = new Fireblocks({
apiKey: API_KEY,
basePath: BasePath.US, // Basepath.Sandbox for the sandbox env
secretKey: readFileSync(FIREBLOCKS_API_SECRET_PATH, "utf8"),
});
const transactionPayload: TransactionRequest = {
assetId: "BTC",
operation: TransactionOperation.Raw,
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
note: ``,
extraParameters: {
rawMessageData: {},
},
};
let txInfo: any;
const getTxStatus = async (txId: string): Promise => {
try {
let response: FireblocksResponse =
await fireblocks.transactions.getTransaction({ txId });
let tx: TransactionResponse = response.data;
let messageToConsole: string = `Transaction ${tx.id} is currently at status - ${tx.status}`;
console.log(messageToConsole);
while (tx.status !== TransactionStateEnum.Completed) {
await new Promise((resolve) => setTimeout(resolve, 3000));
response = await fireblocks.transactions.getTransaction({ txId });
tx = response.data;
switch (tx.status) {
case TransactionStateEnum.Blocked:
case TransactionStateEnum.Cancelled:
case TransactionStateEnum.Failed:
case TransactionStateEnum.Rejected:
throw new Error(
`Signing request failed/blocked/cancelled: Transaction: ${tx.id} status is ${tx.status}`,
);
default:
console.log(messageToConsole);
break;
}
}
while (tx.status !== TransactionStateEnum.Completed);
return tx;
} catch (error) {
throw error;
}
};
const rawSign = async (
message: string,
): Promise => {
const wrappedMessage =
"\x18Bitcoin Signed Message:\n" +
String.fromCharCode(message.length) +
message;
const hash = createHash("sha256").update(wrappedMessage, "utf8").digest();
const content = createHash("sha256").update(hash).digest("hex");
//@ts-ignore
transactionPayload.extraParameters.rawMessageData = {
messages: [
{
content,
bip44addressIndex: 0,
},
],
};
transactionPayload.note = `BTC Message: ${message}`;
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest: transactionPayload,
},
);
//@ts-ignore
console.log(transactionPayload.extraParameters.rawMessageData);
const txId = transactionResponse.data.id;
if (!txId) {
throw new Error("Transaction ID is undefined.");
}
txInfo = await getTxStatus(txId);
console.log(JSON.stringify(txInfo, null, 2));
const signature = txInfo.signedMessages[0].signature;
console.log(JSON.stringify(signature));
const encodedSig =
Buffer.from([Number.parseInt(signature.v, 16) + 31]).toString("hex") +
signature.fullSig;
console.log(
"Encoded Signature:",
Buffer.from(encodedSig, "hex").toString("base64"),);
return
} catch (error) {
console.error(error);
}
};
rawSign("My message23");
```
```javascript theme={"system"}
import { createHash } from "crypto";
import * as fs from "fs"
import * as path from "path"
import { FireblocksSDK, PeerType, TransactionOperation, TransactionStatus } from "fireblocks-sdk";
const apiKey = ""
const apiSecretPath = ""
const apiSecret = fs.readFileSync(path.resolve(__dirname, apiSecretPath), "utf8");
const fireblocks = new FireblocksSDK(apiSecret, apiKey);
async function signArbitraryMessage(fireblocks: FireblocksSDK, vaultAccountId: string, message: string, bip44addressIndex = 0) {
const wrappedMessage = "\x18Bitcoin Signed Message:\n" + String.fromCharCode(message.length) + message;
const hash = createHash('sha256').update(wrappedMessage, 'utf8').digest();
const content = createHash('sha256').update(hash).digest("hex");
const { status, id } = await fireblocks.createTransaction({
operation: TransactionOperation.RAW,
assetId: "BTC",
source: {
type: PeerType.VAULT_ACCOUNT,
id: vaultAccountId
},
note: `BTC Message: ${message}`,
extraParameters: {
rawMessageData: {
messages: [{
content,
bip44addressIndex
}]
}
}
});
let txInfo;
let currentStatus = status;
while(currentStatus != TransactionStatus.COMPLETED && currentStatus != TransactionStatus.FAILED) {
try {
console.log("keep polling for tx " + id + "; status: " + currentStatus);
txInfo = await fireblocks.getTransactionById(id);
currentStatus = txInfo.status;
} catch (err) {
console.log("err", err);
}
await new Promise(r => setTimeout(r, 1000));
};
const signature = txInfo.signedMessages[0].signature;
console.log(JSON.stringify(signature));
const encodedSig = Buffer.from([signature.v + 31]).toString("hex") + signature.fullSig;
console.log("Encoded Signature:", Buffer.from(encodedSig,"hex").toString("base64"));
}
signArbitraryMessage(fireblocks, "0", "INSERT TEXT HERE");
```
```python theme={"system"}
from fireblocks.client import Fireblocks
from fireblocks.client_configuration import ClientConfiguration
from fireblocks.base_path import BasePath
from fireblocks.models.transaction_request import TransactionRequest
from fireblocks.models.destination_transfer_peer_path import DestinationTransferPeerPath
from fireblocks.models.source_transfer_peer_path import SourceTransferPeerPath
from fireblocks.models.transfer_peer_path_type import TransferPeerPathType
from fireblocks.models.transaction_request_amount import TransactionRequestAmount
from pprint import pprint
# load the secret key content from a file
with open('your_secret_key_file_path', 'r') as file:
secret_key_value = file.read()
# build the configuration
configuration = ClientConfiguration(
api_key="your_api_key",
secret_key=secret_key_value,
base_path=BasePath.Sandbox, # or set it directly to a string "https://sandbox-api.fireblocks.io/v1"
)
# Enter a context with an instance of the API client
with Fireblocks(configuration) as fireblocks:
transaction_request: TransactionRequest = TransactionRequest(
asset_id="BTC",
amount=TransactionRequestAmount("0.1"),
source=SourceTransferPeerPath(
type=TransferPeerPathType.VAULT_ACCOUNT,
id="0"
),
destination=DestinationTransferPeerPath(
type=TransferPeerPathType.VAULT_ACCOUNT,
id="1"
),
note="Your first transaction!"
)
# or you can use JSON approach:
#
# transaction_request: TransactionRequest = TransactionRequest.from_json(
# '{"note": "Your first transaction!", '
# '"assetId": "BTC", '
# '"source": {"type": "VAULT_ACCOUNT", "id": "0"}, '
# '"destination": {"type": "VAULT_ACCOUNT", "id": "1"}, '
# '"amount": "0.1"}'
# )
try:
# Create a new transaction
future = fireblocks.transactions.create_transaction(transaction_request=transaction_request)
api_response = future.result() # Wait for the response
print("The response of TransactionsApi->create_transaction:\n")
pprint(api_response)
# to print just the data: pprint(api_response.data)
# to print just the data in json format: pprint(api_response.data.to_json())
except Exception as e:
print("Exception when calling TransactionsApi->create_transaction: %s\n" % e)
```
3. Start by creating a transaction of type **RAW**, shown under `operation` (JS) or by using `create_raw_transaction()` (PY).
4. Now, specify the source who is signing the message, which is the default vault (`Id 0`) in our case.
After sending the transaction for signing, wait for its completion so you can retrieve the signature.
The loop in the example above waits for the status of the transaction to be `COMPLETED`, or until an issue arises.
Once the transaction is complete, we print the full signature by accessing the transaction object `signedMessages`, then `signature`.
# Common errors
Source: https://developers.fireblocks.com/reference/common-errors
# Unexpected physicalDeviceId
When thrown by any SDK function, this error indicates that the `physicalDeviceId` associated with the `deviceId` in Fireblocks and the `physicalDeviceId` sent with the request are not identical.
The `physicalDeviceId` is an ID the SDK provisions when the SDK is initialized on a new web browser or mobile device. After the `generateMPCKeys` function generates key shares or an end user completes the recovery procedure, Fireblocks assigns the `deviceId` to the `physicalDeviceId`. This means that the same `deviceId` cannot issue requests (e.g., sign transactions) from any other SDK initialization.
**Reminder**
The SDK initialization occurs with a specific `deviceId`.
Below are some scenarios that may result in an **Unexpected physicalDeviceId** exception.
## Unexpected physicalDeviceId after recovery
As described [here](https://ncw-developers.fireblocks.com/docs/backup-recovery-1#additional-recovery-info), encrypted key share backups are associated with a corresponding `deviceId`. When an end-user recovers a key share from a new device (i.e., a different `physicalDeviceId` than their original device), the `deviceId` of the original device is no longer associated with the key share.
### Example
If Device A (`physicalDeviceId: pd1` and `deviceId: d1`) generates a key share, and Device B (`physicalDeviceId: pd2`) recovers Device A's key share, the NCW SDK will throw the **Unexpected physicalDeviceId** error message when Device A attempts to sign a transaction since `pd1` is no longer associated with `d1`.
## Unexpected physicalDeviceId after key generation abruptly stopped
During the key generation process, Fireblocks associates the `physicalDeviceId` with the `deviceId`. If the process is interrupted and then restarted with the same `deviceId` but a different `physicalDeviceId`, the NCW SDK will throw the **Unexpected physicalDeviceId** error message.
### Examples
* Reinstalling the app, clearing the storage, and then calling `generateMPCKeys` again
* Calling `generateMPCKeys` from another device
# Configure Policies
Source: https://developers.fireblocks.com/reference/configure-transaction-authorization-policy
# The Policy Rules structure
The Policy Rule object represents a single unit of logic that Policies enforce. Understanding the structure and constraints of this object is crucial to working with Policy Editor APIs. The same object is used when working with Policy Drafts. To publish a single rule or a set of rules, pass an array inside the request body that holds one or more Policy Rule objects. Each Policy Rule object in the array should have the following mandatory fields:
| Field | Type | Values | Description |
| -------------- | ------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Action | String | ALLOW, BLOCK, 2-TIER | Defines what occurs when a transaction meets the rule's criteria. |
| Asset | String | | Defines the type of asset being transacted. Use “\*” for all assets, or specify a specific `assetID` string that can be obtained using the [List all asset types supported by Fireblocks endpoint](/api-reference/blockchains-&-assets/list-assets-legacy) . |
| amountCurrency | String | USD, EURO, NATIVE | Limits the amount of any asset users can transfer based on their NATIVE value or based on their USD or EURO equivalents. |
| Src and dst | String | | Defines source and destination accounts the rule allows transfers to originate from and be sent to. |
| amountScope | String | SINGLE\_TX, TIMEFRAME | This limit applies to a single transaction or to all transactions within the defined time period. |
| Amount | String | | |
| periodSec | Number | | Time period in seconds which applies to the `amountScope` field to accumulate transferred amounts in transactions that match the rule, until the total exceeds the value you specify under Minimum. When the specified amount is reached within that period, whether by one or many transactions, further transactions in that period either fail or require more approvals. - *Note:*\* If `amountScope` = “SINGLE\_TX”, meaning that the rule should not cover a Time period, set `periodSec` = “0” |
| Type | String | TRANSFER (Default) | The default value of TRANSFER is fixed and the value cannot be changed. If you wish to change the rule to apply on any of the other possible transaction types, add the `transactionType` key. \*\*Note:\*\*Additional mandatory fields apply when changing the `transactionType`. |
# Objects within the Policy Rule
## externalDescriptor
Each Policy rule receives a unique string ID identifying it. A “rule” is an object managed separately in Fireblocks as part of the Policy. The `externalDescriptor` key is an object holding that string ID value. This value is used to reference the specific rule when you wish to overwrite an existing rule using the [Send publish request for a set of policy rules endpoint](/api-reference/policy-editor-beta/send-publish-request-for-a-set-of-policy-rules). It is also referenced after the Policy Validation process is executed, and its response is returned under the `checkResult` object.
## Operators
Pass one or more `userID` strings inside an array of strings as the value for the “users” key in order to represent the users that are allowed to sign the transactions which are relevant under the scope of this rule. Use the [List users endpoint](/api-reference/users/list-users) to obtain the user IDs.
```json theme={"system"}
"operators": {
"usersGroups": ["userId1", "userId2", "userId3"]
},
```
Alternatively, to configure a rule where all users are allowed, replace the “users” key with the "wildcard" key and pass `*`.
```json theme={"system"}
"operators": {
"wildcard": "*"
},
```
Passing an Array of “userGroups” instead of “users” is optional. Use the [List user groups endpoint](/reference/getusergroups) to obtain the `userGroups` IDs.
```json theme={"system"}
"operators": {
"userGroups": ["userGroupID1", "userGroupID2"]
},
```
Check the example section below for payloads that have rules defined with either option.
## transactionType
It is possible to pass the transactionType key with either of the below values to configure a rule for the following types:
* TRANSFER - Default. Transfers funds from one account to another.
* CONTRACT\_CALL - calls a smart contract.
* APPROVE - enables the approve function to be used for a smart contract to withdraw from a designated wallet. [Learn more](https://support.fireblocks.io/hc/en-us/articles/4404616097426-Approve-Transaction-Amount-Cap).
* MINT - performs a mint operation (increases supply) on a supported token.
* BURN - performs a burn operation (reduces supply) on a supported token.
* STAKE - allows you to allocate and lock assets supported for staking to accrue rewards. [Learn more](https://support.fireblocks.io/hc/en-us/articles/4417214701970-Staking-on-Fireblocks).
* RAW - an off-chain message used to sign any message with your private key.
* TYPED\_MESSAGE - an off-chain message type that follows a predefined format and used to sign specific ETH or BTC messages.
Each of the Policy rule types may have different mandatory fields that are seen inside the endpoint’s [API reference documentation](/api-reference/policy-editor-beta/send-publish-request-for-a-set-of-policy-rules). For example, for the TRANSFER type, you can use any of the following sources or destinations:
* `*`
* VAULT
* ONE\_TIME\_ADDRESS
* EXCHANGE
* UNMANAGED
* NETWORK\_CONNECTION
* FIAT\_ACCOUNT
> **Note**
>
> Using ONE\_TIME\_ADDRESS, UNMANAGED & NETWORK\_CONNECTION is only possible under DST.
## SRC & DST
Standard Transfer rules as well as Contract Call rules limit the activity for specific sources or destinations. Exceptions to these rules, where the rule should not include a destination limitation, are Typed Message, RAW and Burn rule types.
The SRC & DST object structures should be an array of arrays. Each array can hold an array of either:
* A single key - “wildcard”, as the type of address should not be indicated
* Two keys - ID and Type
* Three keys - ID, Type, and Subtype of the address
```json theme={"system"}
"dst": {
"ids": [
[
"*",
"UNMANAGED"
],
[
"*",
"EXCHANGE",
"*"
],
[
"*",
"NETWORK_CONNECTION",
"*"
]
]
},
"src": {
"ids": [
[
"*",
"VAULT",
"*"
],
[
"*",
"EXCHANGE",
"KRAKEN"
]
]
},
```
Check the example section below for full payloads that have rules defined with either option.
# Publishing, approving and validating Policy rules
A Policy should normally have more than a single rule to govern the operations of the workspace. Therefore, multiple Policy Rule objects are passed inside the “rules” object. The [Send publish request for a set of policy rules endpoint](/api-reference/policy-editor-beta/send-publish-request-for-a-set-of-policy-rules) should receive a payload of your entire Policy. Check the example section below for payloads that have multiple rules defined.
# Publish a Policy using an SDK
To publish your Policy, use the `publishPolicyRules` SDK method and include the Policy Rule object. In the following example, you can see the passed object named “rule”. As mentioned, a typical Policy includes rules which are sent under the same array as a separate object.
Here is a code sample for configuring a single rule allowing ETH transactions:
```javascript theme={"system"}
async function publishPolicyRules(){[
rule = [
{
"action": "ALLOW",
"asset": "ETH",
"amountCurrency": "USD",
"src": {
"ids": [
[
"*"
]
]
},
"dst": {
"ids": [
[
"*"
]
]
},
"amountScope": "SINGLE_TX",
"amount": "0",
"periodSec": 0,
"type": "TRANSFER",
"operators": {
"wildcard": "*"
}
}
]
]
console.log(typeof(rule));
const publishPolicyRules = await fireblocks.publishPolicyRules(rule);
console.log(JSON.stringify(publishPolicyRules, null, 2));
}
```
Check the example section below for payloads that have multiple rules defined.
## Edit an Existing Policy rule
Using the [Send publish request for a set of policy rules endpoint](/api-reference/policy-editor-beta/send-publish-request-for-a-set-of-policy-rules), you can edit existing rules by passing the Policy Rule object details and adding the externalDescriptor ID of an existing rule that you wish to overwrite. Get the externalDescriptor from the [Get the active policy and its validation endpoint](/api-reference/policy-editor-beta/get-the-active-policy-and-its-validation). To edit multiple rules, pass the Policy Rule object and add each rule’s unique externalDescriptor in every rule object.
# Approving the Policy change inside the Console
Once you execute the code as the example above shows, your workspace Owner will receive a **Review Policy changes** notification in their Console. They will have to login and review the changes prior to getting the approval request on their mobile device.
Below is the notification that the Owner should look for once logging into the Console and navigating to the **Settings** page:
On the top-right side of the screen, the following will appear:
# Customizing the Rules
## Time-Based Threshold
Passing the `amountAggregation` object, together with the amountScope key (set to “TIMEFRAME”) and the `periodSec` (representing the time period in seconds), will configure the rule to match the aggregated value of transactions, the source and destination inclusion pattern, and the time period.
### Note:
This is a mandatory ***number*** parameter that should be set to “0” if no Time Based Threshold is used in the rule.
**Example**: Block transfers when a \$15,000 accumulation is reached over a 12-hour period (12hx60mx60s=43200 seconds))
```json theme={"system"}
"action": "BLOCK",
"amount": "15000",
"amountCurrency": "USD",
"transactionType": "TRANSFER",
"allowedAssetTypes": "FUNGIBLE",
"amountAggregation": {
"operators": "ACROSS_ALL_MATCHES",
"dstTransferPeers": "ACROSS_ALL_MATCHES",
"srcTransferPeers": "ACROSS_ALL_MATCHES"
},
"amountScope": "TIMEFRAME",
"periodSec": 43200,
```
## applyForApprove
Passing this key with a True value, will configure a Contract\_Call rule to match for initial “Approve” transaction used in Web3 smart contracts.
```json theme={"system"}
"applyForApprove": true,
```
## applyForTypedMessage
Passing this key with a True value, when configuring a Contract\_Call rule, will match interactions with decentralized apps (dApps) that require signing EIP-712 or ETH personal messages. Alternatively, you can create a separate Typed\_Message type rule for that purpose only. Configuring this key is relevant for Contract\_Call rules when one-time address (OTA) and whitelisted destinations are used or for Off-chain messages that have no destination.
```json theme={"system"}
"applyForTypedMessage": true,
```
## rawMessageSigning
Passing this object, will configure the rule to match specific Raw Signing messages by either their derivation paths(s) or their signing algorithm.
```json theme={"system"}
"rawMessageSigning": {
"algorithm": "MPC_ECDSA_SECP256K1",
"derivationPath": {
"path": [
44,0,0,0,0
]
}
},
```
This is applicable when the rule is configured with the “All vaults” as the source. In the example below, the SRC object limits the source to the “Vault” type. Unlike the other types of sources allowed, vaults have a derivation path per each asset wallet. [See Policy Rules for RAW Signing](https://support.fireblocks.io/hc/en-us/articles/4413379762450-Raw-Signing).
```json theme={"system"}
"src": {
"ids": [
[
"*",
"VAULT",
"*"
]
]
},
```
Note that passing the “derivationPath” key is mandatory while passing “algorithm” is optional.
# Policy Validation
Fireblocks checks your rule submission for errors. Each rule receives a unique string ID identifying the rule. The rule ID is returned under the Policy response body inside the `externalDescriptor` parameter. Together with the details of the submitted rule(s), the Policy response object shows additional validation-related details under the status key and the `checkResult` object:
* `status`: the status of the Policy operation
* `checkResult`: an object showing the details of the check for each rule submitted
* `errors`(1): a number indicating the total amount of errors found
* `results`: an array holding the details of the validation per each rule submitted. Each validation result will have an index key that represents the position of the rule within the set of Policy rules. Each validation will contain an array of errors found within it.
* `errors` (2): an array of objects, each reflecting the specific error details identified.
Here is an example Response object showing the validation fields (the rule itself is redacted):
```json theme={"system"}
{
"status": "INVALID_CONFIGURATION",
"checkResult": {
"errors": 1,
"results": [
{
"index": 0,
"externalDescriptor": "{\"id\":\"1e9cf057-028d-4657-8da1-b604800ed198\"}",
"status": "failure",
"errors": [
{
"errorMessage": "INVALID_ASSET_TYPE",
"errorCode": 2,
"errorCodeName": "INVALID_PARAMETERS",
"errorField": "allowedAssetTypes"
}
]
}
]
}
}
```
# Metadata response object
Together with the details of the submitted rule(s), the status of the Policy submission, and the `checkResult` object, the Policy response object holds a few important metadata details:
* `editedAt`: the timestamp of receiving the Policy edit request
* `editedBy`: the user ID submitting the Policy
* `publishedAt`: the timestamp of publishing the Policy
* `publishedBy`: the user ID that published the Policy
Example Metadata object details that are a part of the Policy Response object:
```yaml theme={"system"}
"metadata": {
"editedAt": 1708865838000,
"editedBy": "a54eb4b7-6a90-2e26-50c1-94369aa00177",
"publishedAt": 1708865838314,
"publishedBy": "a54eb4b7-6a90-2e26-50c1-94369aa00177"
}
```
# Policy examples
* Transfer OTA
* Transfer accumulated
* Contract Call
The following JSON sequence shows a set of transfer rules demonstrating the usage of `designatedSigners`, `authorizationGroups`, and operators (initiators) in an individual/group/combined configuration. Also, notice that `dstAddressType` matches the specific destination type.
The flow in this example shows:
* A separate handling of One-time Address destinations, requiring special approvals and signature.
* Four consecutive rules that define permitted transfers to whitelisted destinations for:
* Overall accumulation which blocks deviating transfers.
* Requirement of special approvals for single transactions above a certain amount and between specific sets of venues.
* Definition of the most permitted transfer rule for transactions that do not match preceding rules.
```json theme={"system"}
{
"draftResponse": {
"draftId": "0f8f98d8-43d8-4b68-b167-9b1e35c99e2e",
"status": "UNVALIDATED",
"rules": [
{
"dst": {
"ids": [
[
"*"
]
]
},
"src": {
"ids": [
[
"*",
"VAULT",
"*"
]
]
},
"type": "TRANSFER",
"asset": "*",
"action": "2-TIER",
"amount": "0",
"operators": {
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
},
"periodSec": 0,
"amountScope": "SINGLE_TX",
"amountCurrency": "USD",
"dstAddressType": "ONE_TIME",
"applyForApprove": false,
"transactionType": "TRANSFER",
"allowedAssetTypes": "FUNGIBLE",
"designatedSigners": {
"users": [
"316c2789-e8f0-45a3-9d2f-16cfec340a10"
],
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
},
"externalDescriptor": "{\"id\":\"ca863088-718b-4516-820c-3d06e80c4aad\"}",
"authorizationGroups": {
"logic": "OR",
"groups": [
{
"th": 2,
"users": [
"9e165261-cffc-4a7f-9f7e-3ed515cfbf16"
],
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
}
],
"allowOperatorAsAuthorizer": false
}
},
{
"dst": {
"ids": [
[
"*"
]
]
},
"src": {
"ids": [
[
"*"
]
]
},
"type": "TRANSFER",
"asset": "*",
"action": "BLOCK",
"amount": "10000000",
"operators": {
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
},
"periodSec": 86400,
"amountScope": "TIMEFRAME",
"amountCurrency": "USD",
"dstAddressType": "WHITELISTED",
"applyForApprove": false,
"transactionType": "TRANSFER",
"allowedAssetTypes": "FUNGIBLE",
"amountAggregation": {
"operators": "ACROSS_ALL_MATCHES",
"dstTransferPeers": "ACROSS_ALL_MATCHES",
"srcTransferPeers": "ACROSS_ALL_MATCHES"
},
"externalDescriptor": "{\"id\":\"b4c22327-e0cb-4a8b-9d81-7e352ab4e213\"}"
},
{
"dst": {
"ids": [
[
"*",
"UNMANAGED"
],
[
"*",
"EXCHANGE",
"*"
],
[
"*",
"NETWORK_CONNECTION",
"*"
]
]
},
"src": {
"ids": [
[
"*",
"VAULT",
"*"
],
[
"*",
"EXCHANGE",
"KRAKEN"
]
]
},
"type": "TRANSFER",
"asset": "*",
"action": "2-TIER",
"amount": "100000",
"operators": {
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
},
"periodSec": 0,
"amountScope": "SINGLE_TX",
"amountCurrency": "USD",
"dstAddressType": "WHITELISTED",
"applyForApprove": false,
"transactionType": "TRANSFER",
"allowedAssetTypes": "FUNGIBLE",
"externalDescriptor": "{\"id\":\"ea2a03cc-05da-4bdc-a119-4ba23798ed22\"}",
"authorizationGroups": {
"logic": "OR",
"groups": [
{
"th": 1,
"users": [
"9e165261-cffc-4a7f-9f7e-3ed515cfbf16",
"316c2789-e8f0-45a3-9d2f-16cfec340a10"
],
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
}
],
"allowOperatorAsAuthorizer": false
}
},
{
"dst": {
"ids": [
[
"*"
]
]
},
"src": {
"ids": [
[
"*"
]
]
},
"type": "TRANSFER",
"asset": "*",
"action": "ALLOW",
"amount": "0",
"operators": {
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
},
"periodSec": 0,
"amountScope": "SINGLE_TX",
"amountCurrency": "USD",
"dstAddressType": "WHITELISTED",
"applyForApprove": false,
"transactionType": "TRANSFER",
"allowedAssetTypes": "FUNGIBLE",
"externalDescriptor": "{\"id\":\"3972a016-6903-4eb6-85f4-07192392f82f\"}"
}
],
"metadata": {
"editedBy": "316c2789-e8f0-45a3-9d2f-16cfec340a10",
"editedAt": "2024-02-18T16:19:51.000Z"
}
},
"validation": {
"status": "SUCCESS",
"checkResult": {
"errors": 0,
"results": [
{
"index": 0,
"externalDescriptor": "{\"id\":\"ca863088-718b-4516-820c-3d06e80c4aad\"}",
"status": "ok",
"errors": []
},
{
"index": 1,
"externalDescriptor": "{\"id\":\"b4c22327-e0cb-4a8b-9d81-7e352ab4e213\"}",
"status": "ok",
"errors": []
},
{
"index": 2,
"externalDescriptor": "{\"id\":\"ea2a03cc-05da-4bdc-a119-4ba23798ed22\"}",
"status": "ok",
"errors": []
},
{
"index": 3,
"externalDescriptor": "{\"id\":\"3972a016-6903-4eb6-85f4-07192392f82f\"}",
"status": "ok",
"errors": []
}
]
}
}
}
```
The next JSON example demonstrates similar sets of rules which can be placed within your Policy, according to the first-match principle, to allow web3 interactions.
The flow in this example shows:
* A permissive rule for Contract Calls performed from a specific vault designated to whitelisted contracts
* A Contract Call rule that allows other vaults to interact with whitelisted contracts upon approval
* A rule that allows users to interact with non-whitelisted contracts with more restrictive approvals
```json theme={"system"}
{
"policy": {
"rules": [
{
"dst": {
"ids": [
[
"*",
"UNMANAGED",
"CONTRACT"
]
]
},
"src": {
"ids": [
[
"0",
"VAULT",
"*"
]
]
},
"type": "TRANSFER",
"asset": "*",
"action": "ALLOW",
"amount": 0,
"operators": {
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
},
"periodSec": 0,
"amountScope": "SINGLE_TX",
"amountCurrency": "USD",
"dstAddressType": "WHITELISTED",
"applyForApprove": true,
"transactionType": "CONTRACT_CALL",
"allowedAssetTypes": "FUNGIBLE",
"applyForDeployment": false,
"externalDescriptor": "{\"id\":\"3972a016-6903-4eb6-85f4-07192392f82f\"}",
"applyForTypedMessage": true
},
{
"dst": {
"ids": [
[
"*",
"UNMANAGED",
"CONTRACT"
]
]
},
"src": {
"ids": [
[
"*",
"VAULT",
"*"
]
]
},
"type": "TRANSFER",
"asset": "*",
"action": "2-TIER",
"amount": 0,
"operators": {
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
},
"periodSec": 0,
"amountScope": "SINGLE_TX",
"amountCurrency": "USD",
"dstAddressType": "WHITELISTED",
"applyForApprove": true,
"transactionType": "CONTRACT_CALL",
"allowedAssetTypes": "FUNGIBLE",
"applyForDeployment": false,
"externalDescriptor": "{\"id\":\"059c0bb7-807a-4de2-a250-bc933e3c8969\"}",
"authorizationGroups": {
"logic": "OR",
"groups": [
{
"th": 1,
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
}
],
"allowOperatorAsAuthorizer": false
},
"applyForTypedMessage": true
},
{
"dst": {
"ids": [
[
"*"
]
]
},
"src": {
"ids": [
[
"*",
"VAULT",
"*"
]
]
},
"type": "TRANSFER",
"asset": "*",
"action": "2-TIER",
"amount": 0,
"operators": {
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
},
"periodSec": 0,
"amountScope": "SINGLE_TX",
"amountCurrency": "USD",
"dstAddressType": "ONE_TIME",
"applyForApprove": true,
"transactionType": "CONTRACT_CALL",
"allowedAssetTypes": "FUNGIBLE",
"applyForDeployment": false,
"externalDescriptor": "{\"id\":\"ee775834-e46c-4413-a713-de114c0193eb\"}",
"authorizationGroups": {
"logic": "OR",
"groups": [
{
"th": 2,
"usersGroups": [
"5a325451-d970-4dd0-87e4-ae2c54936f4f"
]
}
],
"allowOperatorAsAuthorizer": false
},
"applyForTypedMessage": true
}
],
"metadata": {
"publishedBy": "316c2789-e8f0-45a3-9d2f-16cfec340a10",
"publishedAt": 1710168706517
}
},
"validation": {
"status": "SUCCESS",
"checkResult": {
"errors": 0,
"results": [
{
"index": 0,
"externalDescriptor": "{\"id\":\"3972a016-6903-4eb6-85f4-07192392f82f\"}",
"status": "ok",
"errors": []
},
{
"index": 1,
"externalDescriptor": "{\"id\":\"059c0bb7-807a-4de2-a250-bc933e3c8969\"}",
"status": "ok",
"errors": []
},
{
"index": 2,
"externalDescriptor": "{\"id\":\"ee775834-e46c-4413-a713-de114c0193eb\"}",
"status": "ok",
"errors": []
}
]
}
}
}
```
# Configure Webhook URLs
Source: https://developers.fireblocks.com/reference/configure-webhook-urls
> **Deprecation notice**
>
> Webhooks v1 will be deprecated on **June 15th, 2026**. Please use the Developer Center in the Fireblocks Console to upgrade to Webhooks V2, which offers improved reliability, performance, and observability.
Follow these steps in the Fireblocks Console:
1. Navigate to **Settings** > **General**, then scroll down to the **Configure Webhook URL** heading and select **Manage URLs**.
2. In the **Configure Webhook URL** window, enter a URL to define the HTTPS endpoint, then press **Enter**.
3. Select **Save**
> **Webhook URL requirement**
>
> Each webhook URL must be a complete, globally available HTTPS address (e.g., `https://example.com`).
Once your Webhook is connected to your Fireblocks workspace, you will start receiving notifications on events in that workspace.
# Consolidate UTXOs
Source: https://developers.fireblocks.com/reference/consolidate-utxos
# Overview
If you regularly run operations on the Bitcoin blockchain, you will likely notice that the list of UTXOs in your wallets grows very quickly. This is especially common in situations where you have multiple addresses used to consolidate into an omnibus account or just as part of an ongoing operation. This can be a major problem for retail-facing operations.
A process utilized by most companies is "consolidating UTXOs", or creating a transaction that will take many small unspent UTXOs and turn them into a single bigger UTXO.
This is done by creating an "internal" transaction within your own vault account that takes the maximum amount of inputs (250) and turns them into a single output.
Although Bitcoin is the most popular UTXO blockchain, this limitation applies to Bitcoin Cash, Bitcoin SV, Dash, Litecoin, ZCash, and a maximum of 110 inputs for Cardano.
# Example
The logic to decide which unspent UTXOs to use can be as simple or complex as you wish, but in this example, we will use any small unspent UTXO that has received enough confirmations.
We have 3 steps in the process of consolidating UTXOs:
1. Retrieve the max spendable amount for a specific wallet.
2. This will result in an amount that considers up to 250 UTXOs within the wallet (by default, from smallest to biggest).
3. Create a transaction with the amount provided.
```javascript theme={"system"}
const getMaxSpendableAmount = async (
assetId: string,
vaultAccountId: string,
): Promise => {
try {
const maxSpendableAmount = await fireblocks.vaults.getMaxSpendableAmount({
vaultAccountId,
assetId,
});
console.log(
JSON.stringify(maxSpendableAmount.data.maxSpendableAmount, null, 2),
);
return maxSpendableAmount.data;
} catch (error) {
console.error(error);
}
};
let transactionPayload = {};
const consolidateWallet = async (
assetId: string,
vaultAccountId: string,
treasuryVault: string,
): Promise => {
const amount = await getMaxSpendableAmount(assetId, vaultAccountId);
transactionPayload = {
assetId,
amount: amount?.maxSpendableAmount,
source: {
type: TransferPeerPathType.VaultAccount,
id: vaultAccountId,
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: treasuryVault,
},
};
console.log(JSON.stringify(transactionPayload, null, 2));
try {
const result = await fireblocks.transactions.createTransaction({
transactionRequest: transactionPayload,
});
console.log(JSON.stringify(result.data, null, 2));
return result.data;
} catch (error) {
console.error(error);
}
};
getMaxSpendableAmount("BTC", "2");
consolidateWallet("BTC", "2", "0");
```
```javascript theme={"system"}
async function consolidate(vaultAccountId, assetId, treasuryVault){
let amountToConsolidate = await fireblocks.getMaxSpendableAmount(vaultAccountId, assetId).maxSpendableAmount
const payload = {
assetId,
amount: amountToConsolidate.maxSpendableAmount,
source: {
type: PeerType.VAULT_ACCOUNT,
id: vaultAccountId
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: treasuryVault
},
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
consolidate("0", "BTC", "1");
```
```python theme={"system"}
from fireblocks_sdk import TransferPeerPath, DestinationTransferPeerPath
def consolidate(vault_id: str, asset: str, treasury_id: str):
amountToConsolidate = fireblocks.get_max_spendable_amount(vault_id, asset)["maxSpendableAmount"]
fireblocks.create_transaction(
asset_id=asset,
amount=amountToConsolidate,
source=TransferPeerPath(VAULT_ACCOUNT, vault_id),
destination=DestinationTransferPeerPath(VAULT_ACCOUNT, treasury_id)
)
consolidate("0", "BTC", "1");
```
Retrieving the maximum spendable amount for consolidation is used through the getMaxSpendableAmount endpoint.
Do note you need the `vaultId` and `assetId`.
Once we create a transaction with the specified amount, Fireblocks automatically selects all of the inputs (smallest to biggest) to consolidate. You can [contact Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new) in order to change the default consolidation selection method and reverse it to a selection going from largest to smallest.
> **UTXO consolidation to source**
>
> You can send a transaction to yourself, thus just consolidating the UTXOs without sending them outwards.
# Webhooks v1
Source: https://developers.fireblocks.com/reference/consume-webhooks
> **Deprecation notice**
>
> Webhooks v1 will be deprecated on **June 15th, 2026**. Please use the Developer Center in the Fireblocks Console to upgrade to Webhooks V2, which offers improved reliability, performance, and observability.
## Overview
Webhooks provide real-time notifications for events happening within your Fireblocks workspace, such as incoming and outgoing transactions, transaction status updates, and the addition of new vault accounts, contract wallets, internal wallets, or external wallets. By configuring webhooks, you can 'listen' for these events at your chosen URL, ensuring that all relevant event types are broadcast to your designated endpoint.
Using webhooks offers several benefits, particularly for event-driven development. They enable immediate awareness of critical events, allowing your systems to respond quickly and automatically to changes in your workspace. This real-time monitoring enhances operational efficiency, as it can trigger automated workflows, updates, or alerts based on the specific events received. Webhooks also facilitate seamless integration with your existing applications, enabling more dynamic and responsive interactions between your Fireblocks workspace and other platforms.
When implementing webhooks, consider the reliability and scalability of the receiving endpoint. Ensure that your system can handle the volume of incoming events and process them efficiently.
If notifications are missed due to any issue, Fireblocks offers the following API endpoints for resending webhook notifications:
* [Resend failed webhooks](/reference/resendwebhooks) - Resends all failed webhook notifications
* [Resend webhooks for a transaction by ID](/reference/resendtransactionwebhooks) - Resends webhook notifications for a transaction by its unique identifier
**Key Features**:
* **Event Ordering** - Webhook events are sent in order with a 10-second delay.
* **Retry Logic** - Missed Webhooks are retried every 5, 15, 35, 75, 155, 315, 635, 1275, 2555 (in seconds).
## Payload Structure
We have a standard payload structure that we implement throughout, as shown below:
| Parameter | Type | Description |
| --------- | ------ | -------------------------------------------------- |
| type | string | The event type. For example: `VAULT_ACCOUNT_ADDED` |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | object | Object details |
Below is a sample of the payload response:
```json theme={"system"}
{
"type": "TRANSACTION_CREATED",
"tenantId”: ".........-.....-....-....-...........",
"timestamp": 1679651214621,
"data": {
"id": "........-....-....-....-............",
"createdAt": 1679651104380,
"lastUpdated": 1679651104380,
"assetId": "WETH_TEST3",
"source": {
"id": "0",
"type": "VAULT_ACCOUNT",
"name": "Main",
"subType": ""
},
"destination": {
"id": "12",
"type": "VAULT_ACCOUNT",
"name": "MintBurn",
"subType": ""
},
"amount": 0.001,
"sourceAddress": "",
"destinationAddress": "",
"destinationAddressDescription": "",
"destinationTag": "",
"status": "SUBMITTED",
"txHash": "",
"subStatus": "",
"signedBy": [],
"createdBy": ".........-.....-....-....-...........",
"rejectedBy": "",
"amountUSD": null,
"addressType": "",
"note": "",
"exchangeTxId": "",
"requestedAmount": 0.001,
"feeCurrency": "ETH_TEST3",
"operation": "TRANSFER",
"customerRefId": null,
"amountInfo": {
"amount": "0.001",
"requestedAmount": "0.001"
},
"feeInfo": {},
"destinations": [],
"externalTxId": null,
"blockInfo": {},
"signedMessages": [],
"assetType": "ERC20"
}
}
```
## Event Types
| Category | Event Type |
| ------------------------------------ | ------------------------------------------ |
| Transactions | TRANSACTION\_CREATED |
| Transactions | TRANSACTION\_STATUS\_UPDATED |
| Transactions | TRANSACTION\_APPROVAL\_STATUS\_UPDATED |
| Internal, External & Contract Wallet | EXTERNAL\_WALLET\_ASSET\_ADDED |
| Internal, External & Contract Wallet | EXTERNAL\_WALLET\_ASSET\_REMOVED |
| Internal, External & Contract Wallet | INTERNAL\_WALLET\_ASSET\_ADDED |
| Internal, External & Contract Wallet | INTERNAL\_WALLET\_ASSET\_REMOVED |
| Internal, External & Contract Wallet | CONTRACT\_WALLET\_ASSET\_ADDED |
| Internal, External & Contract Wallet | CONTRACT\_WALLET\_ASSET\_REMOVED |
| Vault | VAULT\_ACCOUNT\_ADDED |
| Vault | VAULT\_ACCOUNT\_ASSET\_ADDED |
| Vault | VAULT\_BALANCE\_UPDATE |
| NFT | NFT\_BALANCE\_CHANGED |
| Exchange & Fiat Account | EXCHANGE\_ACCOUNT\_ADDED |
| Exchange & Fiat Account | FIAT\_ACCOUNT\_ADDED |
| Network Connection | NETWORK\_CONNECTION\_ADDED |
| Smart Transfer | TICKET\_CREATED |
| Smart Transfer | TICKET\_SUBMITTED |
| Smart Transfer | TICKET\_EXPIRED |
| Smart Transfer | TICKET\_CANCELED |
| Smart Transfer | TICKET\_FULFILLED |
| Smart Transfer | TICKET\_COUNTERPARTY\_ADDED |
| Smart Transfer | TICKET\_COUNERPARTY\_EXTERNAL\_ID\_SET |
| Smart Transfer | TICKET\_NOTE\_ADDED |
| Smart Transfer | TICKET\_EXPIRES\_IN\_SET |
| Smart Transfer | TICKET\_EXPIRES\_AT\_SET |
| Smart Transfer | TICKET\_TERM\_ADDED |
| Smart Transfer | TICKET\_TERM\_UPDATED |
| Smart Transfer | TICKET\_TERM\_DELETED |
| Smart Transfer | TICKET\_TERM\_FUNDED |
| Smart Transfer | TICKET\_TERM\_MANUALLY\_FUNDED |
| Smart Transfer | TICKET\_TERM\_FUNDING\_CANCELED |
| Smart Transfer | TICKET\_TERM\_FUNDING\_COMPLETED |
| Smart Transfer | TICKET\_TERM\_TRANSACTION\_STATUS\_CHANGED |
| Off Exchange | SETTLEMENT\_CREATED |
| Off Exchange | COLLATERAL\_SIGNER\_READY\_EVENT |
## IP Whitelisting
Whitelisting Webhook IP addresses is optional but recommended. Webhooks are sent from the following IPs:
* **US environment:** 3.134.25.131
* **EU environment:** 3.72.125.45, 18.184.217.45, 18.198.71.192
# Contract Objects
Source: https://developers.fireblocks.com/reference/contract-objects
## ContractAsset
| Parameter | Type | Description |
| -------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| id | string | The ID of the contract wallet. |
| balance | string | The balance of the contract wallet. |
| lockedAmount | string | Locked amount in the contract wallet. |
| status | ConfigChangeRequestStatus | Status of the contract wallet. |
| activationTime | string | The time the contract wallet will be activated in case wallet activation is postponed according to the workspace definition. |
| address | string | The address of the contract wallet. |
| tag | string | Used as destination tag for XRP; `memo` for ATOM, EOS, HBAR, LUNA, LUNC, XDB, XEM; `memo_text` for XLM; `notes` for ALGO. |
***
## UnmanagedContract
| Parameter | Type | Description |
| --------- | ------------------------------------------------ | -------------------------------------------------------------- |
| id | string | The ID of the unmanaged contract wallet. |
| name | string | Name of the contract wallet container. |
| assets | Array of [ContractAsset](#contractasset) objects | An array of assets available in the unmanaged contract wallet. |
# Securing communication
Source: https://developers.fireblocks.com/reference/cosigner-callbackhandler-secure-communication-authentication
## Authenticating the Callback Handler Response Object
When setting up the Callback Handler server for an API user paired with the Co-signer, you can choose between five options to secure the communication between them.
This selection determines the payload structure of the POST request sent by the Co-signer to the Callback Handler server. It also defines how the request is authenticated by the Callback Handler. More details are provided below.
***
## Option 1: Public key authentication
In this option, the Co-signer and the Callback Handler exchange JSON Web Token (JWT) encoded messages, each signed with their respective private keys. The Co-signer's POST request to the Callback Handler server and the Callback Handler's response to the Co-signer are authenticated using their corresponding public keys.
### JWT-encoded signed request
* The Co-signer, acting as a client of the Callback Handler server, sends a POST request and uses its private key to sign the JWT-encoded message.
* The Callback Handler uses the Co-signer's public key to authenticate the message and ensure it originated from the Co-signer.
* You can retrieve the Co-signer's public key directly from the Co-signer ([see the guides](/reference/api-cosigner-maintenance)).
> **Note:** The same Co-signer private key is used to sign request messages sent to the Callback Handler server for all API users paired with this Co-signer.
### JWT-encoded signed response
* The Callback Handler responds with a JWT-encoded message signed with its private key.
* The Co-signer uses the Callback Handler's public key to authenticate the message and ensure it originated from it.
* You provide the API user's Callback Handler public key to the Co-signer during installation or while configuring the Callback Handler for that API user. This public key corresponds to the private key used by the Callback Handler to sign JWT-encoded response messages.
Follow these steps to generate a private-public key pair for signing JWT-encoded responses. This allows the Co-signer to authenticate your Callback Handler's responses using the corresponding public key:
1. Generate a private key using the following command:
```bash theme={"system"}
openssl genrsa -out callback_private.pem 2048
```
> **Note:** Only RSA 2048 bit keys are supported for public key Callback Handler response authentication.
2. Export the public key from the previously generated private key using the following command:
```bash theme={"system"}
openssl rsa -in callback_private.pem -outform PEM -pubout -out callback_public.pem
```
3. Use this public key to configure the Co-signer's Callback Handler for the specified API user.
4. Set up the Callback Handler as an HTTPS server using a certificate signed by a trusted Certificate Authority (CA). Configure the Callback Handler endpoints to **include** a `/v2` prefix in their URLs:
> `https://your_callback_base_url/v2/tx_sign_request`
> or
> `https://your_callback_base_url/v2/config_change_sign_request`
### Communication channel security
TLS communication between the Co-signer and the Callback Handler server requires the Callback Handler to operate as an HTTPS server with a certificate signed by a trusted Certificate Authority (CA).
***
## Option 2: Self-Signed Certificate-based communication (Certificate pinning)
In this option, a self-signed certificate or a certificate signed by a trusted Certificate Authority (CA) is used to establish certificate-pinning-based secure communication between the Co-signer and the Callback Handler. TLS certificate authentication occurs during SSL negotiation and is based on the certificate you provide to the Co-signer.
The certificate is provided to the Co-signer during installation or while configuring the Callback Handler for a specific API user. In this setup, both the Co-signer's POST request to the Callback Handler server and the server's response are in JSON format, instead of using signed JWTs.
Create a certificate and sign it yourself or have it signed by a trusted CA; set up an HTTPS server and configure your Callback Handler endpoints to respond to requests that **do not include** a `/v2` prefix:
> `https://your_callback_base_url/tx_sign_request`
> or
> `https://your_callback_base_url/config_change_sign_request`
***
## Option 3: Root-CA Certificate-based communication
> **Note:**
>
> This feature requires Co-signers version 2025.12.11 or newer.
In this option, a Root-CA certificate is used to establish certificate-based secure communication between the Co-signer and the Callback Handler. TLS certificate authentication occurs during SSL negotiation and is based on the Root-CA certificate you provide to the Co-signer.
The Root-CA certificate is provided to the Co-signer during installation or while configuring the Callback Handler for a specific API user. A certificate that was signed by the Root-CA needs to be provided to the Co-signer by the Callback Handler during the TLS certificate authentication.
In this setup, both the Co-signer's POST request to the Callback Handler server and the server's response are in JSON format, instead of using signed JWTs.
Create a certificate and have it signed by the Root-CA; set up an HTTPS server and configure your Callback Handler endpoints to respond to requests that **do not include** a `/v2` prefix:
> `https://your_callback_base_url/tx_sign_request`
> or
> `https://your_callback_base_url/config_change_sign_request`
***
## Option 4: Hybrid - Public key authentication with certificate pinning
> **Note:**
>
> This feature requires Co-signer version 2025.12.11 or newer and is currently supported only by the SGX cosigner.
This hybrid option combines the message-level security of Option 1(public key authentication) with the transport-level security of Option 2 (certificate pinning).
In this configuration:
* **TLS Layer**: The secure TLS connection is established using certificate pinning with a self-signed certificate or a certificate signed by a trusted Certificate Authority (CA), as described in Option 2.
* **Message Layer**: Communication messages are exchanged as JWT-encoded messages signed with private keys, exactly as described in Option 1.
This approach provides dual-layer security:
1. The TLS handshake authenticates the Callback Handler server using the pinned certificate
2. The JWT signatures authenticate individual messages using public key cryptography
### Configuration steps:
1. Create a certificate and sign it yourself or have it signed by a trusted CA
2. Provide the certificate to the Co-signer during installation or while configuring the Callback Handler for the specific API user
3. Generate and configure JWT signing keys as described in Option 1:
1. Generate a private-public key pair for the Callback Handler
2. Provide the public key to the Co-signer for JWT verification
4. Configure your Callback Handler endpoints to include a /v2 prefix (as in Option 1):
> `https://your_callback_base_url/v2/tx_sign_request`
> or
> `https://your_callback_base_url/v2/config_change_sign_request`
5. Implement your Callback Handler to:
1. Accept JWT-encoded requests from the Co-signer
2. Respond with JWT-encoded messages signed with your private key
***
## Option 5: Hybrid - Public key authentication with Root-CA certificate
> **Note:**
>
> This feature requires Co-signer version 2025.12.11 or newer and is currently supported only by the SGX cosigner.
This hybrid option combines the message-level security of Option 1(public key authentication) with the transport-level security of Option 3 (Root-CA certificate validation).
In this configuration:
* **TLS Layer**: The secure TLS connection is established using Root-CA certificate validation, as described in Option 3.
* **Message Layer**: Communication messages are exchanged as JWT-encoded messages signed with private keys, exactly as described in Option 1.
This approach provides dual-layer security:
1. The TLS handshake authenticates the Callback Handler server using Root-CA certificate validation
2. The JWT signatures authenticate individual messages using public key cryptography
### Configuration steps:
1. Create a certificate and have it signed by your Root-CA
2. Provide the Root-CA certificate to the Co-signer during installation or while configuring the Callback Handler for the specific API user
3. Generate and configure JWT signing keys as described in Option 1:
1. Generate a private-public key pair for the Callback Handler
2. Provide the public key to the Co-signer for JWT verification
4. Configure your Callback Handler endpoints to include a `/v2` prefix (as in Option 1):
> `https://your_callback_base_url/v2/tx_sign_request`
> or
> `https://your_callback_base_url/v2/config_change_sign_request`
5. Implement your Callback Handler to:
1. Accept JWT-encoded requests from the Co-signer
2. Respond with JWT-encoded messages signed with your private key
> **Note:**
>
> When adding the Callback Handler URL to the Co-signer, you should pass only the base URL + custom relative path.
> The `/v2/tx_sign_request` or `/v2/config_change_sign_request` relative paths will be automatically added upon each request made by the Co-signer.
>
> For example if you exposed the Callback Handler URL in the following path:
> `https://subdomain.example.com/fireblocks/callback_handler/v2/tx_sign_request`
>
> You should configure the following URL in the Co-signer:
> `https://subdomain.example.com/fireblocks/callback_handler`
# Create Omnibus Structure
Source: https://developers.fireblocks.com/reference/create-omnibus-structure
# Overview
For customers who have taken the omnibus account structure, it is important to make sure the vaults are structured accordingly, and there is no bottleneck of transactions within the withdrawal mechanism, for example.
> **Important:**
>
> * **Intermediate vault accounts**: This is the vault account assigned to an end client. Because you could have numerous end clients, you can use the Fireblocks API to automatically generate as many intermediate vault accounts as needed.
> * **Omnibus deposits**: This is the central vault omnibus account where end-client funds are swept and stored.
> * **Withdrawal pool**: These are the vault accounts containing funds allocated for end-client withdrawal requests. More than one withdrawal pool vault account is required due to blockchain limitations.
>
> Make sure you are following the right structure for you by reading the [Create Direct Custody Wallets](/docs/create-direct-custody-wallets) article.
# Understanding Asset Types
Handling your omnibus account correctly requires a clear understanding of the differences between different asset types - UTXO vs Account Based.
Due to the nature of UTXO-based blockchains, the transaction includes the source address for each end client, unlike account-based transactions which require an intermediary vault account.
We will explain the two methodologies separately in this article.
## UTXO Based
### Structure
* In the Omnibus Deposits vault account, you can assign each end client a deposit address (which is derived from the permanent wallet address of the UTXO asset).
* When adding an address for an end client in the Omnibus Deposits vault account, use the [Create a New Deposit Address of an Asset in a Vault Account API call](/reference/createvaultaccountassetaddress)
and use the `name` parameter to associate the end client's ID, as a prefix or suffix for the name of the vault account.
The `customerRefId` parameter is the ID for AML providers to associate the owner of funds with transactions and should now be used for other purposes. Both the name of the vault account and the AML customerRefID fields are propagated to every transaction to the end client in your system.
### Deposit
Funds are deposited using the following process:
* The retail platform shares the deposit address with the end client.
* The end client makes a deposit.
* The incoming deposit triggers a webhook notification.
* Your client-facing software automatically notifies the end client that the deposit was successfully received.
* The deposit appears on the Transaction History page.
### Example
```javascript theme={"system"}
const createUTXOWithdrawalVaultAccounts = async (
assetId: string,
name: string,
): Promise | undefined> => {
const result: Array<{}> = [];
try {
const vaultAccount = await fireblocks.vaults.createVaultAccount({
createVaultAccountRequest: {
name,
},
});
if (vaultAccount.data) {
const vaultWallet = await fireblocks.vaults.createVaultAccountAsset({
vaultAccountId: vaultAccount.data.id as string,
assetId,
});
result.push({
"Vault Account Name": vaultAccount.data.name,
"Vault Account ID": vaultAccount.data.id,
"Asset ID": assetId,
Address: vaultWallet.data.address,
});
console.log(JSON.stringify(result, null, 2));
}
return result;
} catch (error) {
console.error(error);
}
};
// Create an omnibus vault account for UTXO based assets
const createOmnibusUTXOAccount = async (
numOfAddresses: number,
assetId: string,
): Promise<{} | undefined> => {
try {
const myOmnibusVault = await fireblocks.vaults.createVaultAccount({
createVaultAccountRequest: {
name: "My Omnibus Vault",
},
});
if (myOmnibusVault.data) {
const vaultAccountId = myOmnibusVault.data.id as string;
let result = {};
await fireblocks.vaults.createVaultAccountAsset({
vaultAccountId,
assetId,
});
for (let i = 0; i < numOfAddresses; i++) {
// Generating additional addresses is possible for UTXO based assets only
await fireblocks.vaults.createVaultAccountAssetAddress({
assetId,
vaultAccountId,
createAddressRequest: {
description: `UserAddress${i + 1}`,
},
});
}
const addresses =
await fireblocks.vaults.getVaultAccountAssetAddressesPaginated({
vaultAccountId,
assetId,
});
result = {
"Vault Account Name": myOmnibusVault.data.name,
"VaultAccount ID": myOmnibusVault.data.id,
"Asset ID": assetId,
Addresses: addresses?.data.addresses,
};
console.log(JSON.stringify(result, null, 2));
return result;
}
} catch (error) {
console.error(error);
}
};
createUTXOWithdrawalVaultAccounts("BTC_TEST", "MyWithdrawalVault");
createOmnibusUTXOAccount(3, "BTC_TEST");
```
```javascript theme={"system"}
// Obtain a list of user identifiers associated with the vault accounts and pass them as a strings inside internalCustRefIds
// each of the internalCustRefIds is concatenated to the vault's name
const internalCustRefIds = ["a","b","c"];
const assetId = "BTC_TEST";
async function createUTXOWithdrawalVaultAccounts(assetId, name){
vault = await fireblocks.createVaultAccount(name);
vaultWallet = await fireblocks.createVaultAsset(Number(vault.id), assetId);
const result = [{"Vault Name": vault.name, "Vault ID": vault.id, "Asset ID": assetId, "Wallet Address": vaultWallet.address}];
console.log(JSON.stringify(result, null, 2));
return(result);
}
async function createUTXOOmnibusAccount(amountOfVaultAccounts, assetId, internalCustRefIds){
let vault;
let vaultWallet;
let address = [];
vault = await fireblocks.createVaultAccount("Omnibus");
vaultWallet = await fireblocks.createVaultAsset(Number(vault.id), assetId);
for (let i = 0; i < amountOfVaultAccounts; i++){
address[i] = await fireblocks.generateNewAddress(Number(vault.id), assetId, "CustomerID_"+internalCustRefIds[i]+"_vault");
}
console.log("Created vault account:"+JSON.stringify(vault, null, 2)+" with wallet addresses:"+JSON.stringify(address, null, 2));
return("Omnibus:", vault, "Addresses:", address);
}
createUTXOWithdrawalVaultAccounts(assetId, "Withdrawal");
createUTXOOmnibusAccount(2, assetId, internalCustRefIds);
```
```python theme={"system"}
# Obtain a list of user identifiers associated with the vault accounts and pass them as a strings inside internalCustRefIds
# each of the internalCustRefIds is concatenated to the vault's name
ASSET = "BTC_TEST"
CUSTOMER_IDS = ["a", "b", "c"]
def create_utxo_withdrawal_vault(asset: str, name: str):
vault_id = fireblocks.create_vault_account(name=name)["id"]
address = fireblocks.create_vault_asset(vault_account_id=vault_id, asset_id=asset)["address"]
return {name: vault_id}, address
def create_utxo_omnibus_vault(amount: int, asset: str, customer_ids: list, hidden_on_ui: bool = True):
deposit_address = {}
vault_id = fireblocks.create_vault_account(name="Omnibus")["id"]
fireblocks.create_vault_asset(vault_account_id=vault_id, asset_id=asset)
for i in range(amount):
address = fireblocks.generate_new_address(vault_account_id=vault_id, asset_id=asset, description=customer_ids[i], hidden_on_ui=hidden_on_ui)["address"]
deposit_address[customer_ids[i]] = address
return {"Omnibus": vault_id, "Addresses": deposit_address}
print(create_utxo_withdrawal_vault(ASSET, "Withdrawal"))
print(create_utxo_omnibus_vault(3, ASSET, CUSTOMER_IDS))
```
The above code creates the Omnibus vault and a withdrawal vault, from which we can later on move funds back to end users who would like to settle.
Afterwards, we create a deposit address per end user, while using an available, unique customer ID. The function then returns a dictionary of the newly created vaults and generated deposit addresses.
## Account Based
> **Note**
>
> Do note this section refers to account based assets without a tag / memo capability. You can refer to tag / memo based assets in the next section.
### Structure
* The workspace should contain one or more intermediate vault accounts per end client in addition to a single Omnibus Deposits vault account.
* When adding a vault account, we recommend using the [Create a New Vault Account API call](/reference/createvaultaccount) and use the `name` parameter to associate the end client's ID, as a prefix or suffix for the name of the vault account.
The `customerRefId` parameter is the ID for AML providers to associate the owner of funds with transactions and should now be used for other purposes. Both the name of the vault account and the AML customerRefID fields are propagated to every transaction to the end client in your system.
* Due to the nature of account-based blockchains, transactions with account-based assets can only be transferred from one account-based address to another account-based address (unlike UTXO, where multiple addresses are included in a single transaction).
### Deposit
Funds are deposited using the following process:
* The end client receives a deposit address.
* The end client makes a deposit.
* The incoming deposit triggers a webhook notification.
* Your client-facing software automatically notifies the end client that the deposit was successfully received.
* The deposit is swept to the Omnibus Deposits vault account. You can see further on the sweeping logic in the [Sweeping within an Omnibus Vault structure](/docs/sweep-funds) article.
### Example
> **Recommended: Set "Hidden Vaults" on**
>
> For the creation of end user vaults, we will usually choose to set **hiddenOnUi** as true, as part of the **createVaultAccount** endpoint.
>
> By default, it is set to false, hence all of the vaults created in this article will be visible in the UI which is not recommended for a very large amount of vaults.
>
> This also means transfers to these vaults won't be visible in the UI, but only programatically.
As the name suggests, the end-user vaults will be serving your end users. If you have followed the structure section, you might have noticed that account based assets require a one-to-one vault per end user.
The treasury vault is a single account where all of the swept assets will move to. You can see more in regarding to sweeping in the following [sweeping article](/docs/sweep-funds).
Lastly, we will also create a few withdrawal vaults in order to distribute our load in regards to settlements, making sure we don't have a bottleneck at the withdrawal part.
We will use the below code in order to perform the following:
1. Create 5 vaults for 5 end users.
2. Create 1 treasury vault.
3. Create 3 withdrawal vaults.
```javascript theme={"system"}
const createAccountBasedVaultAccounts = async (
vaultAccountNamePrefix: string,
numOfVaultAccounts: number,
assetId: string,
hiddenOnUI: boolean,
endUserReferences?: string[],
): Promise | undefined> => {
try {
let vaultAccount: FireblocksResponse;
let results: Array<{}> = [];
for (let i = 0; i < numOfVaultAccounts; i++) {
if (
endUserReferences &&
endUserReferences.length !== numOfVaultAccounts
) {
throw new Error(
"Number of Vault Accounts does not equal to the number of end user references",
);
}
vaultAccount = await fireblocks.vaults.createVaultAccount({
createVaultAccountRequest: {
name: endUserReferences
? vaultAccountNamePrefix + "_" + endUserReferences[i]
: vaultAccountNamePrefix + "_Vault" + String(i + 1),
hiddenOnUI,
},
});
const vaultAccountId = vaultAccount.data?.id as string;
const vaultWallet = await fireblocks.vaults.createVaultAccountAsset({
assetId,
vaultAccountId,
});
const singleVaultResult = {
"Vault Account": vaultAccount.data?.name,
"Vault Account ID": vaultAccountId,
"Asset ID": assetId,
Address: vaultWallet.data?.address,
};
results.push(singleVaultResult);
console.log(
`Created Vault Account:\n ${JSON.stringify(singleVaultResult, null, 2)}`,
);
}
return results;
} catch (error) {
console.error(error);
}
};
createAccountBasedVaultAccounts("Deposits", 5, "ETH_TEST5", true, [
"UserA",
"UserB",
"UserC",
"UserD",
"UserE",
]);
createAccountBasedVaultAccounts("Treasury", 1, "ETH_TEST5", false);
createAccountBasedVaultAccounts("Withdrawal_Pool", 3, "ETH_TEST5", false);
```
```javascript theme={"system"}
// Obtain a list of user identifiers associated with the vault accounts and pass them as a strings inside internalCustRefIds
// each of the internalCustRefIds is concatenated to the vault's name
const internalCustRefIds = ["a","b","c","d","e"];
const assetId = "ETH_TEST3";
async function createAccountBasedVaultAccounts(vaultAccountNamePrefix, amountOfVaultAccounts, assetId, hiddenOnUI, internalCustRefIds){
let createVaultRes;
let vault;
let vaultWallet;
for (let i = 0; i < amountOfVaultAccounts; i++){
if (internalCustRefIds){
createVaultRes = await fireblocks.createVaultAccount(vaultAccountNamePrefix.toString()+"_"+internalCustRefIds[i]+"_vault", hiddenOnUI);
}
else {
createVaultRes = await fireblocks.createVaultAccount(vaultAccountNamePrefix.toString()+"_"+i.toString()+"_vault", hiddenOnUI);
}
vault = {
vaultName: createVaultRes.name,
vaultID: createVaultRes.id
}
vaultWallet = await fireblocks.createVaultAsset(Number(vault.vaultID), assetId);
console.log("Created vault account", vault.vaultName,":", "with wallet address:", vaultWallet.address);
}
}
createAccountBasedVaultAccounts("Deposits_End_User", 5, assetId, false, internalCustRefIds);
createAccountBasedVaultAccounts("Treasury", 1, assetId, false, undefined);
createAccountBasedVaultAccounts("Withdrawal_pool", 3, assetId, false, undefined);
```
```python theme={"system"}
# Obtain a list of user identifiers associated with the vault accounts and pass them as a strings inside internalCustRefIds
# each of the internalCustRefIds is concatenated to the vault's name
CUSTOMER_IDS = ["a", "b", "c", "d", "e"]
ASSET = "ETH_TEST3"
def create_account_vault_accounts(prefix: str, amount: int, asset_id: str, customer_ids: list, is_hidden: bool = False) -> dict:
vault_dict = {}
for index in range(amount):
if customer_ids:
vault_name = f"{prefix}_{customer_ids[index]}_vault"
else:
vault_name = f"{prefix}_vault"
vault_id = fireblocks.create_vault_account(name=vault_name, hidden_on_ui=is_hidden)["id"]
fireblocks.create_vault_asset(vault_id, )
vault_dict[vault_name] = vault_id
return vault_dict
print(create_account_vault_accounts("End-User", 5, ASSET, CUSTOMER_IDS, True))
print(create_account_vault_accounts("Treasury", 1, ASSET))
print(create_account_vault_accounts("Withdrawal", 3, ASSET))
```
In the above code, we have created a function that takes a prefix for the vault name and a number of vaults that we would like to create and also uses the and the internalCustRefIds and `hiddenOnUI` params, if relevant, depending on vault accounts creation purpose.
We then run it three times.
1. For the end user vaults.
2. For the treasury vault.
3. For the withdrawal vault.
## Tag / Memo Based
> **Note**
>
> Although these are basically also account based, they have a special differentiating attribute: the **tag** / **memo**. This helps us identify different customers / accounts within our single wallet, crediting customers in our internal ledger.
### Structure
* In the Omnibus Deposits vault account, you can assign each end client a tag or memo (name varies based on the blockchain).
* When adding an address for an end client in the Omnibus Deposits vault account, use the [Create a New Deposit Address of an Asset in a Vault Account API call](/reference/createvaultaccountassetaddress)
and use the `name` parameter to associate the end client's ID, as a prefix or suffix for the name of the vault account.
The `customerRefId` parameter is the ID for AML providers to associate the owner of funds with transactions and should now be used for other purposes. Both the name of the vault account and the AML customerRefID fields are propagated to every transaction to the end client in your system.
### Deposit
Funds are deposited using the following process:
* The end client receives a deposit address and a **tag** or **memo**.
* The end client makes a deposit, using the address and the tag.
* The incoming deposit triggers a webhook notification.
* Your client-facing software automatically notifies the end client that the deposit was successfully received, assuming he passed a **tag** or **memo**.
* All of your funds will be located in the same account, while managing different customer balances in an internal ledger.
### Example
```javascript theme={"system"}
const createTagWithdrawalVaultAccounts = async (
assetId: string,
name: string,
): Promise | undefined> => {
const result: Array<{}> = [];
try {
const vaultAccount = await fireblocks.vaults.createVaultAccount({
createVaultAccountRequest: {
name,
},
});
if (vaultAccount.data) {
const vaultWallet = await fireblocks.vaults.createVaultAccountAsset({
vaultAccountId: vaultAccount.data.id as string,
assetId,
});
result.push({
"Vault Account Name": vaultAccount.data.name,
"Vault Account ID": vaultAccount.data.id,
"Asset ID": assetId,
Address: vaultWallet.data.address,
});
console.log(JSON.stringify(result, null, 2));
}
return result;
} catch (error) {
console.error(error);
}
};
// Create an omnibus vault account for Tag/Memo based assets
const createTagOmnibusAccount = async (
numOfAddresses: number,
assetId: string,
): Promise<{} | undefined> => {
try {
const myOmnibusVault = await fireblocks.vaults.createVaultAccount({
createVaultAccountRequest: {
name: "My Omnibus Vault",
},
});
if (myOmnibusVault.data) {
const vaultAccountId = myOmnibusVault.data.id as string;
let result = {};
await fireblocks.vaults.createVaultAccountAsset({
vaultAccountId,
assetId,
});
for (let i = 0; i < numOfAddresses; i++) {
// For Tag/Memo based assets, the address of the wallet is always the same but a new Memo/Tag is generated upon each user
await fireblocks.vaults.createVaultAccountAssetAddress({
assetId,
vaultAccountId,
createAddressRequest: {
description: `UserAddress${i + 1}`,
},
});
}
const addresses =
await fireblocks.vaults.getVaultAccountAssetAddressesPaginated({
vaultAccountId,
assetId,
});
result = {
"Vault Account Name": myOmnibusVault.data.name,
"VaultAccount ID": myOmnibusVault.data.id,
"Asset ID": assetId,
Addresses: addresses?.data.addresses,
};
console.log(JSON.stringify(result, null, 2));
return result;
}
} catch (error) {
console.error(error);
}
};
createTagWithdrawalVaultAccounts("XLM_TEST", "Withdrawal");
createTagOmnibusAccount(2, "XLM_TEST");
```
```javascript theme={"system"}
// Obtain a list of user identifiers associated with the vault accounts and pass them as a strings inside internalCustRefIds
// each of the internalCustRefIds is concatenated to the vault's name
const internalCustRefIds = ["a","b","c"];
const assetId = "XLM_TEST";
async function createTagWithdrawalVaultAccounts(assetId, name){
vault = await fireblocks.createVaultAccount(name);
vaultWallet = await fireblocks.createVaultAsset(Number(vault.id), assetId);
const result = [{"Vault Name": vault.name, "Vault ID": vault.id, "Asset ID": assetId, "Wallet Address": vaultWallet.address}];
console.log(JSON.stringify(result, null, 2));
return(result);
}
async function createTagOmnibusAccount(amountOfVaultAccounts, assetId, internalCustRefIds){
let vault;
let vaultWallet;
let tag = [];
vault = await fireblocks.createVaultAccount("Omnibus");
vaultWallet = await fireblocks.createVaultAsset(Number(vault.id), assetId);
for (let i = 0; i < amountOfVaultAccounts; i++){
tag[i] = await fireblocks.generateNewAddress(Number(vault.id), assetId, "CustomerID_"+internalCustRefIds[i]+"_vault");
}
console.log("Created vault account:"+JSON.stringify(vault, null, 2)+" with wallet tag:"+JSON.stringify(tag, null, 2));
return("Omnibus:", vault, "Tags:", tag);
}
createTagWithdrawalVaultAccounts(assetId, "Withdrawal");
createTagOmnibusAccount(2, assetId, internalCustRefIds);
```
```python theme={"system"}
ASSET = "XLM_TEST"
CUSTOMER_IDS = ["a", "b", "c"]
def create_tag_withdrawal_vault(asset: str, name: str):
vault_id = fireblocks.create_vault_account(name=name)["id"]
address = fireblocks.create_vault_asset(vault_account_id=vault_id, asset_id=asset)["address"]
return {name: vault_id}, address
def create_tag_omnibus_vault(amount: int, asset: str, customer_ids: list, hidden_on_ui: bool = True):
deposit_tags = {}
vault_id = fireblocks.create_vault_account(name="Omnibus")
address = fireblocks.create_vault_asset(vault_account_id=vault_id, asset_id=asset)["address"]
for i in range(amount):
tag = fireblocks.generate_new_address(vault_account_id=vault_id, asset_id=asset, description=customer_ids[i], hidden_on_ui=hidden_on_ui)["tag"]
deposit_tags[customer_ids[i]] = address
return {"Omnibus": vault_id, "Address": address, "Tags": deposit_tags}
print(create_tag_withdrawal_vault(ASSET, "Withdrawal"))
print(create_tag_omnibus_vault(3, ASSET, CUSTOMER_IDS))
```
The above code creates the Omnibus vault and a withdrawal vault, from which we can later on move funds back to end users who would like to settle.
Afterwards, we create a deposit tag per end user, while using an available, unique customer ID. The function then returns a dictionary of the newly created vaults and generated deposit tags.
# Create a Staking Position
Source: https://developers.fireblocks.com/reference/create-stake
1. [Approve the terms of service](/reference/approvetermsofservicebyproviderid) of your desired staking provider (Kiln or Figment):
```javascript theme={"system"}
const FireblocksSDK = require("fireblocks-sdk").FireblocksSDK;
const fireblocks = new FireblocksSDK(privateKey, apiKey);
const approveRequest = await fireblocks.approveStakingProviderTermsOfService("kiln");
```
2. [Create your staking position](/reference/stake) :
```javascript theme={"system"}
const stakeRequest = await fireblocks.executeStakingStake(
"SOL",{
vaultAccountId:"1",
providerId:"kiln",
stakeAmount:"100",
txNote:"stake 100 SOL from vaultId 1, 24 Jan 2024"
}
);
```
**Important:**
The response object from the staking action includes an ID that serves as the unique identifier for the staking position.
It's essential to save this ID for future reference. If you lose this ID, you can retrieve all the IDs from the staking position in your workspace by using the `fireblocks.getStakingPositions()` function.
## Monitor and sign the staking request
[Find the relevant transaction](/reference/getdelegationbyid) - After creating the staking position, find the new transaction ID using `getStakingPosition(id)`. The transaction ID can be found under `responseBody.relatedTransactions[0].txId`:
```javascript theme={"system"}
const positionId = stakeRequest.id
const position = await fireblocks.getStakingPosition(positionId);
// When creating a new staking position, there is only 1 transaction
const txId = position.relatedTransactions[0].txId
// ... sign it
```
To sign the transaction, please follow the necessary steps outlined. Learn more about the [transaction signing request and approval process](https://support.fireblocks.io/hc/en-us/articles/12006018592156-API-Co-Signer-Overview) .
Once the stake position is created, you can monitor the position status and available actions, such as unstaking or withdrawing, using `getPosition(positionId)`.
# Create Transactions
Source: https://developers.fireblocks.com/reference/create-transactions
# Overview
Every transaction on the Fireblocks platform is initiated using the [Create a new transaction](/reference/createtransaction) API endpoint. Its default operation type is `TRANSFER`. However, other important operations are available as valid values for the `operation` body parameter:
* **TRANSFER:** Transfers funds from one account to another. UTXO blockchains allow multi-input and multi-output transfers. All other blockchains allow transfers with one source address and one destination address.
* **CONTRACT\_CALL:** Calls a smart contract method for Web3 operations on any EVM blockchain.
* **PROGRAM\_CALL:** Calls programs for Web3 operations on the Solana blockchain. Learn more [here](/reference/interact-with-solana-programs#/).
* **TYPED\_MESSAGE:** An off-chain message in either [Ethereum Personal Message](https://geth.ethereum.org/docs/rpc/ns-personal#personal_sign) or EIP-712 format. Used to sign specific readable messages that are not actual transactions.
* **RAW:** An off-chain message with no predefined format. Used to sign any message with your private key, including protocols such as blockchains and custom transaction types not natively supported by Fireblocks.
* **MINT:** Perform a mint operation to increase the supply of a token. Supported for Stellar, Ripple, and EVM-based blockchains.
* **BURN:** Perform a burn operation to reduce the supply of a token. Supported for Stellar, Ripple, and EVM-based blockchains.
The API call serves all possible source and destination combinations, including a one-time address destination (OTA), vault account, pre-whitelisted internal wallet, external wallet & contract wallet, Fireblocks Network connections and any connected exchange account and fiat account.
> **Optional parameters for assets & operations**
>
> Although there are required parameters for the [Create a new transaction](/reference/createtransaction) API call, you can pass other optional body parameters depending on the asset or the required operation.
>
> The endpoint also accepts the addition of the `extraParameters` object, used to describe additional details required for raw message signing, contract calls, and specific UTXO selections.
>
> [Learn how the `extraParameters` object works in transaction responses.](/reference/transaction-objects)
# Your first transaction
## Vault account to vault account transaction
To start, initiate a transaction from one Fireblocks vault account to another. Account-based assets allow single-destination transfers, and UTXO assets allow multi-destination transfers.
### Single destination transfer (ETH)
The example transfers 0.001 amount of ETH from vault account ID `0` to vault account ID `1`.
```javascript theme={"system"}
const transactionPayload = {
assetId: "ETH",
amount: "0.001",
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
note: "Your first transaction!",
};
const createTransaction = async (
transactionPayload: TransactionRequest,
): Promise => {
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest: transactionPayload,
},
);
console.log(JSON.stringify(transactionResponse.data, null, 2));
return transactionResponse.data;
} catch (error) {
console.error(error);
}
};
createTransaction(transactionPayload);
```
```javascript theme={"system"}
async function createTransaction(assetId, amount, srcId, destId){
let payload = {
assetId,
amount,
source: {
type: PeerType.VAULT_ACCOUNT,
id: String(srcId)
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: String(destId)
},
note: "Your first transaction!"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "0", "1");
```
```python theme={"system"}
def create_transaction(asset_id, amount, src_id, dest_id):
tx_result = fireblocks.create_transaction(
asset_id=asset_id,
amount=amount,
source=TransferPeerPath(VAULT_ACCOUNT, src_id),
destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
note="Your first transaction!"
)
print(tx_result)
create_transaction("ETH", "0.001", "0", "1")
```
### Multiple-destination transfer
Transfer 0.001 BTC from the first vault account (`"1"`), by sending 0.0005 BTC to the second vault account (using `id: "2"`) and 0.0005 BTC to the third vault account (`id: "3"`) as destinations.
```javascript theme={"system"}
const transactionPayload = {
assetId: "BTC",
amount: "0.001",
source: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
destinations: [
{
amount: "0.0005",
destination: {
type: TransferPeerPathType.VaultAccount,
id: "2",
},
},
{
amount: "0.0005",
destination: {
type: TransferPeerPathType.VaultAccount,
id: "3",
},
},
],
note: "Your first multiple destination transaction!",
};
const createTransaction = async (
transactionPayload: TransactionRequest,
): Promise => {
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest: transactionPayload,
},
);
console.log(JSON.stringify(transactionResponse.data, null, 2));
return transactionResponse.data;
} catch (error) {
console.error(error);
}
};
createTransaction(transactionPayload);
```
```javascript theme={"system"}
async function createTransaction(assetId, amount, srcId){
let payload = {
assetId,
amount,
source: {
type: PeerType.VAULT_ACCOUNT,
id: String(srcId)
},
destinations: [
{amount: "0.0005", destination: {type: PeerType.VAULT_ACCOUNT, id: "2"}},
{amount: "0.0005", destination: {type: PeerType.VAULT_ACCOUNT, id: "3"}}
],
note: "Your first multiple destination transaction!"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("BTC", "0.001", "1");
```
```python theme={"system"}
def create_transaction(asset_id, amount, src_id):
tx_result = fireblocks.create_transaction(
asset_id=asset_id,
amount=amount,
source=TransferPeerPath(VAULT_ACCOUNT, src_id),
destinations=[
TransactionDestination("0.0005", DestinationTransferPeerPath(VAULT_ACCOUNT, "2")),
TransactionDestination("0.0005", DestinationTransferPeerPath(VAULT_ACCOUNT, "3"))
],
note="Your first multiple destination transaction!"
)
print(tx_result)
create_transaction("BTC", "0.001", "1")
```
## Vault account to one-time address transaction
Transfer 0.01 ETH between the vault account (`"1"`) to a specific one-time blockchain address.
```javascript theme={"system"}
const transactionPayload = {
assetId: "ETH",
amount: "0.001",
source: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
destination: {
type: TransferPeerPathType.OneTimeAddress,
oneTimeAddress: {
address: "0x13277a70e3F48EEAD9C8a8bab12EbEDbC3DB6446",
},
},
note: "Your first OTA transaction!",
};
const createTransaction = async (
transactionPayload: TransactionRequest,
): Promise => {
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest: transactionPayload,
},
);
console.log(JSON.stringify(transactionResponse.data, null, 2));
return transactionResponse.data;
} catch (error) {
console.error(error);
}
};
createTransaction(transactionPayload);
```
```javascript theme={"system"}
async function createTransaction(assetId, amount, srcId, address){
let payload = {
assetId,
amount,
source: {
type: PeerType.VAULT_ACCOUNT,
id: String(srcId)
},
destination: {
type: PeerType.ONE_TIME_ADDRESS,
oneTimeAddress: {
address: String(address)
}
},
note: "Your first OTA transaction!"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "1", "0x13277a70e3F48EEAD9C8a8bab12EbEDbC3DB6446");
```
```python theme={"system"}
def create_transaction(asset_id, amount, src_id, address):
tx_result = fireblocks.create_transaction(
asset_id=asset_id,
amount=amount,
source=TransferPeerPath(VAULT_ACCOUNT, src_id),
destination=DestinationTransferPeerPath(ONE_TIME_ADDRESS, None, {"address": address}),
note="Your first OTA transaction!"
)
print(tx_result)
create_transaction("ETH", "0.001", "1", "0x13277a70e3F48EEAD9C8a8bab12EbEDbC3DB6446")
```
> **API idempotency for transactions**
>
> The best practice for creating transactions is to use the `externalTxId` parameter as seen in the [Optional parameters section.](doc:creating-a-transaction#optional-parameters)
## Contract Call Transaction
```javascript theme={"system"}
import { readFileSync } from 'fs';
import {
Fireblocks,
BasePath,
TransactionOperation,
TransferPeerPathType
} from "@fireblocks/ts-sdk";
// Initialize a Fireblocks API instance with local variables
const FIREBLOCKS_API_SECRET_PATH = "";
const fireblocks = new Fireblocks({
apiKey: "",
basePath: BasePath.US,
secretKey: readFileSync(FIREBLOCKS_API_SECRET_PATH, "utf8"),
});
(async() => {
const contractAddress = "0x43506849D7C04F9138D1A2050bbF3A0c054402dd" // USDC contract address
const contractCallData = "0x095ea7b3000000000000000000000000d09971d8ed6c6a5e57581e90d593ee5b94e348d4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" // calling the approve function with some example params
try{
const contractCallTransaction = await fireblocks.transactions.createTransaction({
transactionRequest: {
operation: TransactionOperation.ContractCall,
assetId: "ETH",
source: {
type: TransferPeerPathType.VaultAccount,
id: "0"
},
destination: {
type: TransferPeerPathType.OneTimeAddress,
oneTimeAddress: {
address: contractAddress
}
},
amount: "0",
extraParameters: {
contractCallData
}
}
})
console.log(JSON.stringify(contractCallTransaction, null, 2))
} catch(e){
console.log(e)
}
})();
```
***
# Optional parameters
Some blockchains have different technicalities when building transactions, handled using optional parameters.
## externalTxId
A *critical* practice to avoid processing multiple identical POST transaction requests more than once is to use the `externalTxId` parameter in the [Create a new transaction](/reference/createtransaction) API call.
The `externalTxId` value is an internal identifier of the transaction that you create and manage on your end.
This value is securely stored in the Fireblocks system, and additional transaction requests with the same `externalTxId` value are not processed on our system. The `externalTxId` is limited to a maximum of 255 characters.
```javascript theme={"system"}
const transactionPayload = {
assetId: "ETH",
amount: "0.001",
externalTxId: "UniqueIdentifier", // the unique identifier of the transaction outside of Fireblocks
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
note: "Your first transaction!",
};
const createTransaction = async (
transactionPayload: TransactionRequest,
): Promise => {
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest: transactionPayload,
},
);
console.log(JSON.stringify(transactionResponse.data, null, 2));
return transactionResponse.data;
} catch (error) {
console.error(error);
}
};
createTransaction(transactionPayload);
```
```javascript theme={"system"}
async function createTransaction(assetId, amount, srcId, destId, externalTxId){
let payload = {
assetId,
amount,
externalTxId, // the unique identifier of the transaction outside of Fireblocks
source: {
type: PeerType.VAULT_ACCOUNT,
id: String(srcId)
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: String(destId)
},
note: "Your first transaction identified by an external ID"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "0", "1", "uniqueTXid");
```
```python theme={"system"}
def create_transaction(asset_id, amount, src_id, dest_id, external_tx_id):
tx_result = fireblocks.create_transaction(
asset_id=asset_id,
amount=amount,
external_tx_id=external_tx_id, # the unique identifier of the transaction outside of Fireblocks
source=TransferPeerPath(VAULT_ACCOUNT, src_id),
destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
note="Your first transaction identified by an external ID"
)
print(tx_result)
create_transaction("ETH", "0.001", "0", "1", "uniqueTXid")
```
## treatAsGrossAmount
The value is`false` by default. If it is set to `true`, the network fee is deducted from the requested amount.
> **Note**
>
> If you send the entire vault account balance without the treatAsGrossAmount field, then the transaction amount will be treated as a gross amount.
```javascript theme={"system"}
const transactionPayload = {
assetId: "ETH",
amount: "0.001",
treatAsGrossAmount: true, // true or false (by default - false)
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
note: "Your first treat as gross transaction!"
}
const createTransaction = async (
transactionPayload:TransactionRequest
):Promise => {
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest:transactionPayload
}
);
console.log(JSON.stringify(transactionResponse.data, null, 2));
return transactionResponse.data;
}
catch(error){
console.error(error);
}
}
createTransaction(transactionPayload);
```
```javascript theme={"system"}
async function createTransaction(assetId, amount, srcId, destId){
let payload = {
assetId,
amount,
treatAsGrossAmount: true, // true / false (by default)
source: {
type: PeerType.VAULT_ACCOUNT,
id: String(srcId)
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: String(destId)
},
note: "Your first treat as gross transaction!"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "0", "1");
```
```python theme={"system"}
def create_transaction(asset_id, amount, src_id, dest_id):
tx_result = fireblocks.create_transaction(
asset_id=asset_id,
amount=amount,
treat_as_gross_amount=True, # true / false (by default)
source=TransferPeerPath(VAULT_ACCOUNT, src_id),
destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
note: "Your first treat as gross transaction!"
)
print(tx_result)
create_transaction("ETH", "0.001", "0", "1")
```
## fee
For UTXO-based assets, `fee` refers to the fee per byte in the asset's smallest unit (Satoshi, Latoshi, etc).
```javascript theme={"system"}
const transactionPayload = {
assetId: "BTC",
amount: "0.001",
fee: "15", // Satoshi per Byte
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
note: "Your first high fee transaction!"
}
const createTransaction = async (
transactionPayload:TransactionRequest
):Promise => {
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest:transactionPayload
}
);
console.log(JSON.stringify(transactionResponse.data, null, 2));
return transactionResponse.data;
}
catch(error){
console.error(error);
}
}
createTransaction(transactionPayload);
```
```javascript theme={"system"}
async function createTransaction(assetId, amount, srcId, destId, fee){
let payload = {
assetId,
amount,
fee, //Satoshi per Byte
source: {
type: PeerType.VAULT_ACCOUNT,
id: String(srcId)
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: String(destId)
},
note: "Your first high fee transaction!"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("BTC", "0.001", "0", "1", "15");
```
```python theme={"system"}
def create_transaction(asset_id, amount, src_id, dest_id, fee):
tx_result = fireblocks.create_transaction(
asset_id=asset_id,
amount=amount,
fee=fee, #Satoshi per Byte
source=TransferPeerPath(VAULT_ACCOUNT, src_id),
destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
note="Your first high fee transaction!"
)
print(tx_result)
create_transaction("BTC", "0.001", "0", "1", "15")
```
## feeLevel
Defines the blockchain fee level that will be paid for the transaction (only for Ethereum, Solana, and UTXO-based blockchains). Set to `MEDIUM` by default. Valid values are `LOW` `MEDIUM` & `HIGH`.
```javascript theme={"system"}
const transactionPayload = {
assetId: "ETH",
amount: "0.001",
feeLevel: TransactionRequestFeeLevelEnum.High, // Low / Medium / High
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
note: "Your first high fee level transaction!",
};
const createTransaction = async (
transactionPayload: TransactionRequest,
): Promise => {
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest: transactionPayload,
},
);
console.log(JSON.stringify(transactionResponse.data, null, 2));
return transactionResponse.data;
} catch (error) {
console.error(error);
}
};
createTransaction(transactionPayload);
```
```javascript theme={"system"}
async function createTransaction(assetId, amount, srcId, destId, feeLevel){
let payload = {
assetId,
amount,
feeLevel, // LOW / MEDIUM / HIGH
source: {
type: PeerType.VAULT_ACCOUNT,
id: String(srcId)
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: String(destId)
},
note: "Your first high fee level transaction!"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("BTC", "0.001", "0", "1", "HIGH");
```
```python theme={"system"}
def create_transaction(asset_id, amount, src_id, dest_id, fee_level):
tx_result = fireblocks.create_transaction(
asset_id=asset_id,
amount=amount,
fee_level=fee_level, # LOW / MEDIUM / HIGH
source=TransferPeerPath(VAULT_ACCOUNT, src_id),
destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
note="Your first high fee level transaction!"
)
print(tx_result)
create_transaction("BTC", "0.001", "0", "1", "HIGH")
```
## failOnLowFee
Set to`false` by default. If set to `true`, and the `feeLevel` (value: `MEDIUM`) is higher than the acceptable amount specified in the transaction, the transaction will fail, to avoid getting stuck with 0 confirmations.
```javascript theme={"system"}
const transactionPayload = {
assetId: "ETH",
amount: "0.001",
failOnLowFee: true, // true / false (default - false)
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
note: "Your first failOnLowFee transaction",
};
const createTransaction = async (
transactionPayload: TransactionRequest,
): Promise => {
try {
const transactionResponse = await fireblocks.transactions.createTransaction(
{
transactionRequest: transactionPayload,
},
);
console.log(JSON.stringify(transactionResponse.data, null, 2));
return transactionResponse.data;
} catch (error) {
console.error(error);
}
};
createTransaction(transactionPayload);
```
```javascript theme={"system"}
async function createTransaction(assetId, amount, srcId, destId, failOnLowFee){
let payload = {
assetId,
amount,
failOnLowFee, // true / false (default)
source: {
type: PeerType.VAULT_ACCOUNT,
id: String(srcId)
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: String(destId)
},
note: "Your first failOnLowFee transaction"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("BTC", "0.001", "0", "1", true);
```
```python theme={"system"}
def create_transaction(asset_id, amount, src_id, dest_id, fail_on_low_fee):
tx_result = fireblocks.create_transaction(
asset_id=asset_id,
amount=amount,
fail_on_low_fee=fail_on_low_fee, # True / False (by default)
source=TransferPeerPath(VAULT_ACCOUNT, src_id),
destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
note="Your first failOnLowFee transaction"
)
print(tx_result)
create_transaction("BTC", "0.001", "0", "1", True)
```
# Create Vault Accounts
Source: https://developers.fireblocks.com/reference/create-vault-account
Your Fireblocks workspace utilizes a hierarchy of vault accounts as part of its [Object Model](doc:object-model). This hierarchy allows you to segregate funds belonging to different business units or deposited by different users.
A Vault account can hold multiple assets. To transfer to or from vault accounts, your source or destination targets must be provided with both their vault ID and asset ID.
Use the [Create a new vault account](/reference/createvaultaccount) API call to create a new vault account that will hold your UTXO or account-based wallets.
### Important:
Vault account names should consist of ASCII characters only.
### Code Example
```javascript theme={"system"}
(async() => {
const vaultAccount = await fireblocks.vaults.createVaultAccount({
createVaultAccountRequest: {
name: "MyVaultAccount",
autoFuel: true,
hiddenOnUI: false
}
})
console.log(JSON.stringify(vaultAccount.data, null, 2))
})();
```
```python theme={"system"}
vault_account = fireblocks.create_vault_account(
name="MyVaultAccount",
hiddenOnUI=False,
autoFuel=True
)
```
### Response Example
```json theme={"system"}
{
"id": "148",
"name": "MyVaultAccount",
"hiddenOnUI": false,
"assets": [],
"autoFuel": true
}
```
***
# Optional parameters
### hiddenOnUI
Set to `true` by default, hides this vault account from appearing in the Fireblocks Console.
This is the best practice when creating intermediate deposit vault accounts for your users as it helps reduce visual clutter and improves UI loading time.
The best practice is configuring this setting so that only your omnibus account and another operational vault account (or multiple) are visible in the Fireblocks Console.
### autoFuel
If the Gas Station service is enabled on your workspace, this flag needs to be set to `true` if you wish to monitor and fuel this account's Ethereum address upon detected balance refresh events, such as when deposits of ERC20 tokens occur.
# Create Vault Wallets
Source: https://developers.fireblocks.com/reference/create-vault-wallet
Fireblocks vault accounts contain vault wallets. For each vault wallet, there are one or more deposit addresses.
# Address generation
## Account-based wallets
For account-based assets, there are two address-generation options:
1. Account-based assets *without* tag/memo/note support, such as ETH, can only generate one deposit address, making each vault account unique per vault wallet. This allows you to manage one deposit address per asset, per vault account. This requires you to create additional vault accounts when more than one deposit address of the same asset is required.
2. Account-based assets *with* tag/memo/note support, such as XRP, can generate one or more deposit addresses. Each deposit address has the same on-chain address. However, they are differentiated by their tag/memo.
## UTXO wallets
UTXO-based assets, such as Bitcoin, can hold multiple wallet addresses. This allows you to manage deposits in a single vault account.
### Create Vault Wallet code example:
```javascript theme={"system"}
(async() => {
try {
const vaultWallet = await fireblocks.vaults.createVaultAccountAsset({
vaultAccountId: "148",
assetId: "BTC"
})
console.log(JSON.stringify(vaultWallet, null, 2))
} catch(e){
console.log(e)
}
})();
```
```python theme={"system"}
vault_wallet = fireblocks.create_vault_asset(
vault_account_id="148",
asset_id="BTC"
)
pprint.pprint(vault_wallet)
```
### Response example
```json theme={"system"}
{
'address': 'bc1q8q87uy8h2mru0q5gc7u680w76dz350s6sx5u8a',
'id': '148',
'legacyAddress': '167RvaKttzN2wRrJwmYEwjKG7kvdjwhKfq',
'tag': ''
}
```
### Create Deposit Address for UTXO and Tag/Memo based assets:
```javascript theme={"system"}
(async() => {
try {
const depositAddress = await fireblocks.vaults.createVaultAccountAssetAddress({
assetId: "BTC",
vaultAccountId: "148",
createAddressRequest: {
description: "EndUserA"
}
})
console.log(JSON.stringify(depositAddress, null, 2))
} catch(e){
console.log(e)
}
})();
```
```python theme={"system"}
deposit_address= fireblocks.generate_new_address(
vault_account_id='148',
asset_id='BTC',
description='EndUserA'
)
pprint.pprint(deposit_address)
```
### Response Example:
```json theme={"system"}
{
'address': 'bc1qkwxyzs68a3nsulhe4eavfm5dzuucf25jjnefex',
'bip44AddressIndex': 1,
'legacyAddress': '1HNMyRRzt4beCDnYLRwQKEbPAwTgmKjwrJ',
'tag': ''
}
```
> **Check the Create Vault Wallet and Create a Deposit Address API Reference**
# Create Workflow Configuration
Source: https://developers.fireblocks.com/reference/create-workflow-configuration
Call the [POST /payments/workflow\_config](/reference/createflowconfiguration) endpoint.
After a configuration is created, the operation type for the WC can’t be changed. However, other WC parameters can be defined and edited later when creating the WE.
## Example
```json theme={"system"}
{
configName: 'some-name',
preScreening: {
enabled: true
},
failureHandling: {
enabled: true,
type: 'REVERSE'
},
configOperations: {
type: 'TRANSFER',
params: {
source: {
accountId: 'xyz',
accountType: 'EXCHANGE_ACCOUNT',
},
assetId: 'USDC_POLYGON',
destination: {
accountType: 'VAULT_ACCOUNT',
accountId: '0',
},
},
},
{
type: 'TRANSFER',
params: {
destination: {
accountType: 'EXCHANGE_ACCOUNT',
accountId: 'abc',
},
source: {
accountType: 'VAULT_ACCOUNT',
accountId: '0',
},
assetId: 'USDC_POLYGON',
},
},
}
```
This route returns the configuration ID which will be used to create the WE.
A configuration proceeds through the following statuses during its creation. These statuses will be applied to each WCO and the WC as a whole.
1. **PENDING:** The configuration is about to start the validation process.
2. **VALIDATION\_IN\_PROGRESS:** The validation process has started, ensuring the configuration is valid.
3. **VALIDATION\_FAILED** or **READY\_FOR\_EXECUTION:** The validation failed or the configuration can be executed. These statuses are finite states.
All the operation validation processes must succeed for the configuration validation to succeed.
If one or more operation validations fail, the entire configuration validation fails. Failed WCOs may show VALIDATION\_FAILED while others may show VALIDATION\_COMPLETED. However, the WC status will show VALIDATION\_FAILED. The failure details will be included under the failed operation in the validationFailure field. In this scenario, you should call the API endpoint again with the corrected configuration.
# Create Workflow Execution
Source: https://developers.fireblocks.com/reference/create-workflow-execution
Once the WC is in **READY\_FOR\_EXECUTION** status, call the [POST /payments/workflow\_execution](/reference/createflowexecution) endpoint.
When creating a WE, mandatory parameters, such as amounts and addresses, that weren’t provided during the configuration phase must be provided. Parameters provided when creating the WC can be overridden when creating the WE. Some parameters are only provided when creating the WE.
The `amount` parameter can only be provided during the WE since it’s required for the preview and launch but not for the WC, which is just a template. This parameter is usually provided to the first operation and then carried from one operation to another down the flow.
## Example
```json theme={"system"}
{
"configId": "string",
"preScreening":{
"enabled": false
},
failureHandling: {
enabled: true,
type: 'REVERSE'
},
"params": [
{
"configOperationId": "string",
"configOverrideParams": {
"accountId": "string",
"srcAssetId": "string",
"destAssetId": "string",
"slippageBasisPoints": 10000
},
"executionParams": {
"amount": "string"
}
},
{
"configOperationId": "string",
"configOverrideParams": {
"paymentAccount": {
"accountId": "string",
"accountType": "EXCHANGE_ACCOUNT"
},
"instructionSet": [
{
"payeeAccount": {
"accountId": "string",
"accountType": "EXCHANGE_ACCOUNT"
},
"assetId": "string",
"amount": "string"
},
{
"payeeAccount": {
"accountId": "string",
"accountType": "EXCHANGE_ACCOUNT"
},
"assetId": "string",
"percentage": "string"
}
]
},
"executionParams": {
"amount": "string"
}
}
]
}
```
The request body `configId` field must include the id for a WC in READY\_FOR\_EXECUTION status.
The request body `params` field holds an array. Each item of the array has a `configOperationId`, which points to a specific operation from the WC. This is necessary when overriding or setting an operation.
An execution proceeds through the following statuses during its creation:
1. **PENDING:** The execution is about to start the validation process.
2. **VALIDATION\_IN\_PROGRESS:** The validation process has started, ensuring the execution is valid.
3. **VALIDATION\_FAILED** or **VALIDATION\_COMPLETED:** The validation failed or completed. If completed, the preview process starts automatically.
4. **PREVIEW\_IN\_PROGRESS:** The preview process has started.
5. **PREVIEW\_FAILED** or **READY\_FOR\_LAUNCH:** The preview failed or the execution can be launched. These statuses are finite states.
If an execution is in VALIDATION\_FAILED status or a PREVIEW\_FAILED, it can't be launched or used again. To get another corrected preview, create a new WE to trigger the validation and preview processes.
# Data Objects
Source: https://developers.fireblocks.com/reference/data-objects
On the following pages, you can find descriptions of all the data objects expected and returned by the Fireblocks API's endpoints.
# Deploy an NFT Collection
Source: https://developers.fireblocks.com/reference/deploy-an-nft-collection
# Overview
You can deploy smart contracts using [The Fireblocks Hardhat plugin integration](https://hardhat.org/hardhat-runner/docs/guides/deploying)
# Create your ERC-721 collection
You can create your own NFT collection using the common ERC-721 standard.
For this example, we’ll name our collection “Space Bunnies”.
There are some great tools to help you do this pretty easily. This example was pre-generated using the [Contracts Wizard by OpenZeppelin](https://docs.openzeppelin.com/contracts/4.x/wizard).
```solidity theme={"system"}
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract SpaceBunnies is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("Space Bunnies", "SPCB") {}
function safeMint(address to, string memory uri) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
}
```
> **OpenZeppelin required**
>
> To run the generated code, you also need to install the OpenZeppelin contracts package from NPM.
>
> In your project directory, run: `npm install @openzeppelin/contracts`.
You are ready to go!
Check out the [Fireblocks Hardhat Plugin Documenation](/reference/hardhat-plugin), [Fireblocks Local JSON RPC](/reference/evm-local-json-rpc) and [Fireblocks Web3 provider](/reference/evm-web3-provider) .
Make sure you go through these and deploy the above contract as explained there, using your choice of available options.
> **Hardhat Deployment**
>
> Hardhat is the go-to market solution for easily deploying contracts. We highly recommend that you choose this option if you feel comfortable with going through the configuration process.
# Estimate Transaction Fee
Source: https://developers.fireblocks.com/reference/estimate-transaction-fee
> **Learn more about Fee Management in Fireblocks in [the following guide](/docs/verify-fee-effeciency)**
# Overview
Ethereum (ETH) fees, also referred to as "gas price" or "gas fees," are calculated based on the amount of network activity and the network resources required. Fireblocks allows you to set the fee when creating a new transaction. You can either use a **custom fee** to set the amount used manually, or you can have Fireblocks estimate the fee by default.
You can estimate network gas fees using the Fireblocks API:
* Estimate a tentative fee for low, medium, or high rates by making a request to [Estimate the required fee for an asset.](/reference/estimatenetworkfee)
* Estimate a specific fee based on your transaction's parameters by making a request to [Estimate the transaction fee.](/reference/estimatetransactionfee)
> **Fee levels determine transaction speed**
>
> The fee rate dictates the speed at which your transaction will be picked up and confirmed by the blockchain. When setting a tentative fee rate, the fee amount is an estimate only. Gas fee calculation is not finalized until your transaction is signed.
> **Using custom fee**
>
> Using the custom fee option can be complex as it offers different parameters, similar to stock trading, that allow you to set options like:
>
> * **Maximum priority fee** - Transaction time takes priority over gas fee price.
> * **Max fee** - The gas fee max price is preset and takes priority over transaction time.
>
> [Learn more about the current Ethereum Network EIP-1559 standard for fee estimation.](https://support.fireblocks.io/hc/en-us/articles/4403728014994-London-Fork-and-EIP-1559)
***
# Estimated network fee
> **Response Caching:**
>
> The network fee response is cached for 30 seconds on the Fireblocks side. Customers should consider this interval when using this endpoint, as querying it more frequently than every 30 seconds will not provide additional value.
You'll see the tentative fee estimation in your fee values before creating your transaction data. This example shows how the estimated network fee is returned by the `getFeeForAsset` SDK function for the ETH asset. A high `priorityFee` estimation is used here to create a transaction sending 0.001 from vault ID `0` to vault ID `1`.
The fee level can be either `LOW` / `MEDIUM` / `HIGH`. It will be `MEDIUM` by default.
* **Note**: You are required to specify the `maxFee`when using `priorityFee`.
```javascript theme={"system"}
const createTxWithNetworkFee = async (
payload: TransactionRequest,
): Promise => {
try {
const fee = await fireblocks.transactions.estimateNetworkFee({
assetId: payload.assetId as string,
});
console.log(
JSON.stringify(
`Priority fee for the Tx is: ${fee.data.high.priorityFee}`,
),
);
payload.priorityFee = fee.data.high.priorityFee;
payload.maxFee = "120";
const result = await fireblocks.transactions.createTransaction({
transactionRequest: payload,
});
console.log(JSON.stringify(result.data, null, 2));
return result.data;
} catch (error: any) {
console.error(error);
}
};
createTxWithNetworkFee({
assetId: "ETH",
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
amount: 0.01,
});
```
```javascript theme={"system"}
async function createTransactionWithNetworkFee(assetId, amount, sourceId, destId){
const fee = await getFee(assetId)
console.log(JSON.stringify("Priority Fee for Transaction is: " + fee.high.priorityFee, null, 2));
const payload = {
assetId,
source: {
type: PeerType.VAULT_ACCOUNT,
id: sourceId
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: destId
},
amount,
priorityFee: fee.high.priorityFee,
maxFee: "120"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransactionWithNetworkFee("ETH", "0.001", "0", "1");
```
```python theme={"system"}
def create_transaction_with_network_fee(asset_id: str, amount: str, source_id: str, dest_id: str):
fee = fireblocks.get_fee_for_asset(asset_id=asset_id)
print("Priority Fee for Transaction is:", fee["high"]["priorityFee"])
result = fireblocks.create_transaction(
asset_id=asset_id,
source=TransferPeerPath(
peer_type=VAULT_ACCOUNT,
peer_id=source_id
),
destination=DestinationTransferPeerPath(
peer_type=VAULT_ACCOUNT,
peer_id=dest_id
),
amount=amount,
priority_fee=fee["high"]["priorityFee"],
max_fee="120"
)
print(result)
create_transaction_with_network_fee("ETH", "0.001", "0", "1")
```
***
# Estimate transaction fee
You'll see the `feeLevel` parameter value inside your transaction data based on the fee level selection from the `estimateFeeForTransaction` SDK function.
This example shows how the estimated network fee is returned by the `getFeeForAsset` SDK function for the ETH asset. A high `priorityFee` estimation is used here to create a transaction sending 0.001 from vault ID `0` to vault ID `1`:
```javascript theme={"system"}
const getTxFee = async (
payload: TransactionRequest,
): Promise => {
try {
const txFee = await fireblocks.transactions.estimateTransactionFee({
transactionRequest: payload,
});
return txFee.data;
} catch (error: any) {
console.error(error);
}
};
// The function should include the logic that will determine the fee level used
// it should be based on the threshold relevant for your use-case
// The logic options are HIGH/LOW as MEDIUM is the default when feeLevel is null
const getFeeLevelToUse = (
feeEstimation: EstimatedTransactionFeeResponse,
): TransactionRequestFeeLevelEnum | undefined => {
let feeLevelToUse: TransactionRequestFeeLevelEnum | undefined;
if ("") {
feeLevelToUse = TransactionRequestFeeLevelEnum.High;
} else if ("") {
feeLevelToUse = TransactionRequestFeeLevelEnum.Low;
}
return feeLevelToUse;
};
const createTxWithFeeEstimation = async (
payload: TransactionRequest,
): Promise => {
try {
const txFee = (await getTxFee(payload)) as EstimatedTransactionFeeResponse;
const feeLevel = getFeeLevelToUse(txFee);
payload.feeLevel = feeLevel as TransactionRequestFeeLevelEnum;
const result = await fireblocks.transactions.createTransaction({
transactionRequest: payload,
});
console.log(JSON.stringify(result.data, null, 2));
return result.data;
} catch (error: any) {
console.error(error);
}
};
createTxWithFeeEstimation({
assetId: "ETH",
source: {
type: TransferPeerPathType.VaultAccount,
id: "0",
},
destination: {
type: TransferPeerPathType.VaultAccount,
id: "1",
},
amount: 0.01,
});
```
```javascript theme={"system"}
async function getTxFee(payload){
const getTxFee = await fireblocks.estimateFeeForTransaction(payload);
return getTxFee;
}
// the function should include the logic that will determine the fee level used
// it should be based on the threshold relevant for your use-case
// The logic options are HIGH/LOW as MEDIUM is the default when feeLevel is null
function logicForWhatFeeLevelToUse(feeEstimation){
if(... <= myThreshold){
feeLevelToUse = FeeLevel.HIGH
}
else if(.....){
feeLevelToUse = FeeLevel.LOW
}
return feeLevelToUse;
}
async function createTransaction(assetId, amount, sourceId, destId){
var feeLevel;
const payload = {
assetId,
amount,
source: {
type: PeerType.VAULT_ACCOUNT,
id: sourceId
},
destination: {
type: PeerType.VAULT_ACCOUNT,
id: destId
},
feeLevel
};
payload.feeLevel = logicForWhatFeeLevelToUse(getTxFee(payload));
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "0", "1");
```
```python theme={"system"}
def create_transaction(asset_id: str, amount: str, source_id: str, dest_id: str):
fee_level = ""
payload = {
"asset_id": asset_id,
"amount": amount,
"source": TransferPeerPath(
peer_type=VAULT_ACCOUNT,
peer_id=source_id
),
"destination": DestinationTransferPeerPath(
peer_type=VAULT_ACCOUNT,
peer_id=dest_id
),
"fee_level": fee_level
}
try:
payload["fee_level"] = logic_for_what_fee_level_to_use(fireblocks.estimate_fee_for_transaction(**payload))
result = fireblocks.create_transaction(**payload)
print(result)
except Exception as e:
print("Error:", e)
```
# EVM Local JSON RPC
Source: https://developers.fireblocks.com/reference/evm-local-json-rpc
# Overview
The Fireblocks JSON-RPC is a command-line server that utilizes the Fireblocks API to facilitate interactions with Ethereum Virtual Machine (EVM) chains. It enables users to perform blockchain operations through a JSON-RPC interface, and it was developed to simplify the integration of Fireblocks' secure wallet infrastructure with blockchain applications.
In this article, you will find installation instructions, code examples, and guidance on how to utilize Fireblocks JSON RPC and other frameworks (e.g. Brownie, Foundry) for smart contract development and interactions.
# Getting Started
## web3.py integration
[Fireblocks JSON-RPC](https://github.com/fireblocks/fireblocks-json-rpc) helps seamlessly integrate Fireblocks into your web3.py development stack.
You can use it to deploy contracts, sign messages, and send transactions.
### Installation
```bash theme={"system"}
npm install -g @fireblocks/fireblocks-json-rpc
pip install web3
```
### Setup
Set the [environment variables](https://github.com/fireblocks/fireblocks-json-rpc/blob/main/.env.example).
Create `example.py`:
```python theme={"system"}
import json
import os
from datetime import datetime
from web3 import Web3
web3 = Web3(Web3.IPCProvider(os.environ['FIREBLOCKS_JSON_RPC_ADDRESS'], 60000*180))
web3.eth.defaultAccount = web3.eth.accounts[0]
CONTRACT_ADDRESS = Web3.toChecksumAddress("0x8A470A36a1BDE8B18949599a061892f6B2c4fFAb")
GREETER_ABI = json.loads('[{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"greet","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_greeting","type":"string"}],"name":"setGreeting","outputs":[],"stateMutability":"nonpayable","type":"function"}]')
GREETING = "Hello web3! By " + web3.eth.defaultAccount + " at " + str(datetime.now())
if __name__ == '__main__':
print('last block number: ', web3.eth.blockNumber)
for account in web3.eth.accounts:
print('account: ', account)
print('account balance: ', web3.fromWei(web3.eth.getBalance(account), "ether"), ' ETH\n')
print('Greeter contract: https://sepolia.etherscan.io/address/' + CONTRACT_ADDRESS)
contract = web3.eth.contract(address=CONTRACT_ADDRESS, abi=GREETER_ABI)
print('Current greeting:', contract.functions.greet().call())
print('Setting greeting to:', GREETING)
tx_hash = contract.functions.setGreeting(GREETING).transact({'from':web3.eth.defaultAccount})
print('Transaction signed and broadcasted: https://sepolia.etherscan.io/tx/' + tx_hash.hex())
print('Waiting for transaction to be mined...')
web3.eth.wait_for_transaction_receipt(tx_hash)
print('Current greeting:', contract.functions.greet().call())
```
### Usage
```bash theme={"system"}
fireblocks-json-rpc -- python example.py
```
You can now use the `web3` object exactly as you normally would!
# Ethereum Smart Contract Development
## Using Brownie
Use the [Fireblocks JSON-RPC](https://github.com/fireblocks/fireblocks-json-rpc) to seamlessly work with Brownie on top of Fireblocks.
## Installation
### Step 1 - Brownie installation:
Please follow the Brownie official [documentation](https://eth-brownie.readthedocs.io/en/stable/install.html) for installation
### Step 2 - Install Fireblocks JSON RPC server:
```bash theme={"system"}
npm install -g @fireblocks/fireblocks-json-rpc
```
## Setup
### Step 1 - Create a new example Brownie project:
```bash theme={"system"}
brownie bake token
cd token
```
### Step 2 - set environment variables:
Set the [environment variables](https://github.com/fireblocks/fireblocks-json-rpc/blob/main/.env.example)
### Step 3 - Add Fireblocks Sepolia network to Brownie:
```bash theme={"system"}
brownie networks add Fireblocks fireblocks-sepolia name="Sepolia (Fireblocks)" chainid=11155111 host='http://127.0.0.1:8545/${FIREBLOCKS_API_KEY}' timeout=600
```
### Step 4 - Configure brownie-config.yaml file:
Add ***dotenv: .env*** parameter to the config yaml file.
Example:
```yaml theme={"system"}
# exclude SafeMath when calculating test coverage
# https://eth-brownie.readthedocs.io/en/v1.10.3/config.html#exclude_paths
reports:
exclude_contracts:
- SafeMath
dotenv: .env
```
## Usage:
```bash theme={"system"}
fireblocks-json-rpc -- brownie run --network fireblocks-sepolia scripts/token.py
```
## Using Foundry
## Installing Foundry
You can skip this section if you already have Foundry installed or follow that [Foundry Installation guide](https://book.getfoundry.sh/getting-started/installation) , [Foundry New Project guide](https://book.getfoundry.sh/projects/creating-a-new-project) on the Foundry website for all details.
We provide you with a very basic process here for convenience:
```bash theme={"system"}
curl -L https://foundry.paradigm.xyz | bash
foundryup
forge init hello_foundry
cd hello_foundry
forge build
forge test
```
After you complete these steps, you'll have a new Foundry project.
## Foundry integration
The [Fireblocks Local JSON-RPC](https://github.com/fireblocks/fireblocks-json-rpc) helps seamlessly integrate Fireblocks into your [Foundry](https://book.getfoundry.sh/) development stack.
You can use it to deploy contracts, sign messages, and send transactions.
### Installation
```bash theme={"system"}
npm install -g @fireblocks/fireblocks-json-rpc
```
### Configuration
Configuration can be set via command line flags or environment variables.
Command line flags:
* Ignore apiBaseUrl if you are not using a sandbox environment
```bash theme={"system"}
fireblocks-json-rpc --apiKey --privateKey --chainId --apiBaseUrl https://sandbox-api.fireblocks.io
```
Environment variables:
* Ignore FIREBLOCKS\_API\_BASE\_URL if you are not using a sandbox environment
```bash theme={"system"}
FIREBLOCKS_API_KEY= \
FIREBLOCKS_API_PRIVATE_KEY_PATH= \
FIREBLOCKS_CHAIN_ID= \
FIREBLOCKS_API_BASE_URL=https://sandbox-api.fireblocks.io
fireblocks-json-rpc
```
Delete the files that came with your Foundry boilerplate template:
```bash theme={"system"}
rm test/Counter.t.sol script/Counter.s.sol src/Counter.sol
```
## Deploy Contract - Using 'forge script'
Now that you have a Foundry project set up, create your smart contract `src/Hello.sol` in the project folder and then deploy it to the Sepolia Ethereum Testnet.
### Step 1: Create and compile the Solidity file
```solidity theme={"system"}
pragma solidity ^0.8.17;
contract HelloWorld {
string public greet = "Hello World!";
}
```
Run the following command to compile it:
```bash theme={"system"}
forge build
```
### Step 2: Create the deployment script
Create a deployment script `script/Hello.s.sol` :
```solidity theme={"system"}
pragma solidity ^0.8.17;
import "forge-std/Script.sol";
import "../src/Hello.sol";
contract MyScript is Script {
function run() external {
vm.startBroadcast();
HelloWorld hello = new HelloWorld();
vm.stopBroadcast();
}
}
```
### Step 3: Deploy smart contract
Deploy your contract to the Ethereum Sepolia Testnet (It is recommended to use the `--slow` parameter in your forge script command, specifically when the script is processing few transactions sequentially):
```bash theme={"system"}
FIREBLOCKS_API_KEY=12345678-1234-1234-1234-123456789abc \
FIREBLOCKS_API_PRIVATE_KEY_PATH=/path/to/secret.key \
FIREBLOCKS_CHAIN_ID=11155111 \
fireblocks-json-rpc --http -- \
forge script script/Hello.s.sol:MyScript \
--sender --slow --broadcast --unlocked --rpc-url {}
```
* `sender_address` can be found in your Fireblocks workspace, through Fireblocks API, or using the JSON RPC directly.
Get address of vault account 0:
```bash theme={"system"}
FIREBLOCKS_API_KEY=12345678-1234-1234-1234-123456789abc \
FIREBLOCKS_API_PRIVATE_KEY_PATH=/path/to/secret.key \
FIREBLOCKS_CHAIN_ID=11155111 \
fireblocks-json-rpc --http --vaultAccountIds 0 -- curl {} \
-X POST \
-H "Content-Type: application/json" \
--data '{"method":"eth_accounts","id":1,"jsonrpc":"2.0"}'
```
This should take a couple of minutes to run if everything was configured correctly.
# EVM Web3 Provider
Source: https://developers.fireblocks.com/reference/evm-web3-provider
# Overview
Popular blockchain choices for building Web3 capabilities are based typically on the Ethereum Virtual Machine (EVM), and therefore share the development tech stack.
Some examples of EVM blockchains:
* Ethereum
* BNB Chain (BSC)
* Polygon
* Avalanche
* Arbitrum
# Convenience libraries
Most commonly, developers interact with EVM-based blockchains using "convenience libraries" such as [web3.js](https://web3js.readthedocs.io/) and [ethers.js](https://docs.ethers.io).
To streamline your JavaScript development experience, we created the [Fireblocks Web3 Provider](https://github.com/fireblocks/fireblocks-web3-provider), to easily connect `ethers.js` and `web3.js` to your Fireblocks workspace.
# web3.js integration
The [Fireblocks Web3 Provider](https://github.com/fireblocks/fireblocks-web3-provider) helps seamlessly integrate Fireblocks into your [`web3.js`](https://web3js.readthedocs.io/) development stack. Use it to deploy contracts, sign messages, and send transactions.
### Installation
```bash theme={"system"}
npm install @fireblocks/fireblocks-web3-provider web3
```
### Setup
```javascript theme={"system"}
import { FireblocksWeb3Provider, ChainId, ApiBaseUrl } from "@fireblocks/fireblocks-web3-provider";
const eip1193Provider = new FireblocksWeb3Provider({
apiBaseUrl: ApiBaseUrl.Sandbox, // If using a sandbox workspace
privateKey: process.env.FIREBLOCKS_API_PRIVATE_KEY_PATH,
apiKey: process.env.FIREBLOCKS_API_KEY,
vaultAccountIds: process.env.FIREBLOCKS_VAULT_ACCOUNT_IDS,
chainId: ChainId.SEPOLIA,
})
```
If you are not using a Sandbox environment, but rather a regular one, just comment the apiBaseUrl line.
### Usage
```javascript theme={"system"}
import Web3 from "web3";
const web3 = new Web3(eip1193Provider);
```
Now you can use the `web3` object exactly as you normally would!
### Example
In this example we are executing the 'approve' method of [USDC](https://goerli.etherscan.io/address/0x07865c6E87B9F70255377e024ace6630C1Eaa37F#writeProxyContract) (ERC20) token on Sepolia by using web3.js and Fireblocks web3 provider.
```javascript theme={"system"}
const { FireblocksWeb3Provider, ChainId, ApiBaseUrl } = require("@fireblocks/fireblocks-web3-provider")
const Web3 = require("web3");
// Import the Sepolia USDC ABI
const ABI = require("./USDC_SEPOLIA_ABI.json");
// Sepolia USDC Contract Address
const CONTRACT_ADDRESS = "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8"
const eip1193Provider = new FireblocksWeb3Provider({
privateKey: process.env.FIREBLOCKS_API_PRIVATE_KEY_PATH,
apiKey: process.env.FIREBLOCKS_API_KEY,
vaultAccountIds: process.env.FIREBLOCKS_VAULT_ACCOUNT_IDS,
chainId: ChainId.SEPOLIA,
// apiBaseUrl: ApiBaseUrl.Sandbox // If using a sandbox workspace
});
(async() => {
const web3 = new Web3(eip1193Provider);
const myAddr = await web3.eth.getAccounts()
const contract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS);
const spenderAddr = ""
// 1 USDC to approve
const amount = 1e6
// Invoke approve method
console.log(
await contract.methods.approve(spenderAddr, amount).send({
from: myAddr[0]
})
)
})().catch(error => {
console.log(error)
});
```
# ethers.js integration
The [Fireblocks Web3 Provider](https://github.com/fireblocks/fireblocks-web3-provider) helps seamlessly integrate Fireblocks into your [`ethers.js`](https://docs.ethers.io/) development stack.
You can use it to deploy contracts, sign messages, and send transactions.
### Installation
```bash theme={"system"}
npm install @fireblocks/fireblocks-web3-provider ethers@5
```
### Setup
```javascript theme={"system"}
import { FireblocksWeb3Provider, ChainId, ApiBaseUrl } from "@fireblocks/fireblocks-web3-provider";
const eip1193Provider = new FireblocksWeb3Provider({
apiBaseUrl: ApiBaseUrl.Sandbox, // If using a sandbox workspace
privateKey: process.env.FIREBLOCKS_API_PRIVATE_KEY_PATH,
apiKey: process.env.FIREBLOCKS_API_KEY,
vaultAccountIds: process.env.FIREBLOCKS_VAULT_ACCOUNT_IDS,
chainId: ChainId.SEPOLIA,
})
```
If you are not using a Sandbox environment, but rather a regular one, just comment the apiBaseUrl line.
### Usage
```javascript theme={"system"}
import * as ethers from "ethers"
const provider = new ethers.providers.Web3Provider(eip1193Provider);
```
Now you can use the `provider` object exactly as you normally would!
### Example
In this example we are executing the 'approve' method of [USDC](https://goerli.etherscan.io/address/0x07865c6E87B9F70255377e024ace6630C1Eaa37F#writeProxyContract) (ERC20) token on Sepolia by using ethers.js and Fireblocks web3 provider.
```javascript theme={"system"}
const { FireblocksWeb3Provider, ChainId, ApiBaseUrl } = require("@fireblocks/fireblocks-web3-provider")
const ethers = require("ethers")
// Import the Sepolia USDC ABI
const ABI = require("./USDC_SEPOLIA_ABI.json");
// Sepolia USDC Contract Address
const CONTRACT_ADDRESS = "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8"
const eip1193Provider = new FireblocksWeb3Provider({
privateKey: process.env.FIREBLOCKS_API_PRIVATE_KEY_PATH,
apiKey: process.env.FIREBLOCKS_API_KEY,
vaultAccountIds: process.env.FIREBLOCKS_VAULT_ACCOUNT_IDS,
chainId: ChainId.SEPOLIA,
// apiBaseUrl: ApiBaseUrl.Sandbox // If using a sandbox workspace
});
(async() => {
const provider = new ethers.providers.Web3Provider(eip1193Provider);
const myContract = new ethers.Contract(CONTRACT_ADDRESS, ABI, provider.getSigner());
const spenderAddr = ""
// 1 USDC to approve
const amount = 1e6
// Invoke approve method
const tx = await myContract.approve(
spenderAddr,
amount
)
console.log(JSON.stringify(tx, null, 2))
})().catch(error => {
console.log(error)
});
```
# Viem integration
The [Fireblocks Web3 Provider](https://github.com/fireblocks/fireblocks-web3-provider) helps seamlessly integrate Fireblocks into your [viem](https://viem.sh/) development stack.
You can use it to deploy contracts, sign messages, and send transactions.
### Installation
```bash theme={"system"}
npm install @fireblocks/fireblocks-web3-provider viem
```
### Setup
```javascript theme={"system"}
import { FireblocksWeb3Provider, ChainId, ApiBaseUrl } from "@fireblocks/fireblocks-web3-provider";
const eip1193Provider = new FireblocksWeb3Provider({
apiBaseUrl: ApiBaseUrl.Sandbox, // If using a sandbox workspace
privateKey: process.env.FIREBLOCKS_API_PRIVATE_KEY_PATH,
apiKey: process.env.FIREBLOCKS_API_KEY,
vaultAccountIds: process.env.FIREBLOCKS_VAULT_ACCOUNT_IDS,
chainId: ChainId.SEPOLIA,
})
```
If you are not using a Sandbox environment, but rather a regular one, just comment the apiBaseUrl line.
### Usage
```javascript theme={"system"}
const { createWalletClient, custom } = require("viem")
const { sepolia } = require("viem/chains")
const walletClient = createWalletClient({
chain: sepolia,
transport: custom(eip1193Provider),
});
```
Now you can use the `walletClient` object exactly as you normally would!
### Example
In this example we are executing the 'approve' method of [USDC](https://goerli.etherscan.io/address/0x07865c6E87B9F70255377e024ace6630C1Eaa37F#writeProxyContract) (ERC20) token on Sepolia by using *viem* and Fireblocks web3 provider.
```javascript theme={"system"}
const { sepolia } = require("viem/chains")
const {
ChainId,
FireblocksWeb3Provider,
ApiBaseUrl
} = require("@fireblocks/fireblocks-web3-provider")
const {
createWalletClient,
custom,
createPublicClient,
http
} = require("viem")
// Import the Sepolia USDC ABI
const ABI = require("./USDC_SEPOLIA_ABI.json");
// Sepolia USDC Contract Address
const CONTRACT_ADDRESS = '0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8'
(async () => {
const spenderAddr = "";
// 1 USDC to approve
const amount = 1e6;
const eip1193Provider = new FireblocksWeb3Provider({
// apiBaseUrl: ApiBaseUrl.Sandbox, // If using a sandbox workspace
privateKey: process.env.FIREBLOCKS_API_PRIVATE_KEY_PATH,
apiKey: process.env.FIREBLOCKS_API_KEY,
vaultAccountIds: process.env.FIREBLOCKS_VAULT_ACCOUNT_IDS,
chainId: ChainId.SEPOLIA
});
// Create wallet client instance
const walletClient = createWalletClient({
chain: sepolia,
transport: custom(eip1193Provider),
});
// Create public client instance
const publicClient = createPublicClient({
chain: sepolia,
transport: http()
})
// Get my account's address
const [ account ] = await walletClient.getAddresses();
// Simulate the 'approve' call
const { request } = await publicClient.simulateContract({
address: CONTRACT_ADDRESS,
abi: ABI,
functionName: 'approve',
args: [spenderAddr, amount],
account
})
// Execute approve call via Fireblocks
await walletClient.writeContract(request)
})();
```
# Ethereum Smart Contract Development
Smart contract development frameworks make it easy to develop, test, and deploy smart contracts on EVM-based blockchains.
# Using Truffle
Use the [Fireblocks Web3 Provider](https://github.com/fireblocks/fireblocks-web3-provider) to seamlessly work with Truffle on top of Fireblocks.
### Installation
```bash theme={"system"}
npm install -g truffle
npm install @fireblocks/fireblocks-web3-provider
```
## Configuration
### Step 1:
Set the [environment variables](https://github.com/fireblocks/fireblocks-json-rpc/blob/main/.env.example)
### Step 2:
Initialize an example Truffle NFT project:
```bash theme={"system"}
truffle unbox nft-box
```
### Step 3:
Edit the **truffle-config.js** file:
```javascript theme={"system"}
require('dotenv').config();
const { FireblocksWeb3Provider, ChainId } = require("@fireblocks/fireblocks-web3-provider");
module.exports = {
networks: {
sepolia: {
provider: () => new FireblocksWeb3Provider({
privateKey: process.env.FIREBLOCKS_API_PRIVATE_KEY_PATH,
apiKey: process.env.FIREBLOCKS_API_KEY,
vaultAccountIds: process.env.FIREBLOCKS_VAULT_ACCOUNT_IDS,
chainId: ChainId.SEPOLIA,
}),
network_id: ChainId.SEPOLIA,
},
},
compilers: {
solc: {
version: "0.8.13"
}
},
};
```
### Usage:
```bash theme={"system"}
truffle migrate --network sepolia
```
# EW API errors
Source: https://developers.fireblocks.com/reference/ew-api-errors
# Overview
This page covers API errors associated with the Fireblocks Embedded Wallet. Every error is accompanied by the correct HTTP error code and a message structured as follows:
```javascript theme={"system"}
{
error: 'HTTP Error description',
message: 'Error message'
}
```
# 4XX errors
## 400 - Bad Request
| Error Name | Error Message |
| :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
| No active webhook subscriptions | The workspace was not configured with a Webhook endpoint that is required for NCW async communication. |
| Unsupported algorithm | The provided algorithm for MPC key generation is not supported. Learn more [here](https://ncw-developers.fireblocks.com/docs/mpc-key-generation). |
| Pagination limit too large | The provided pagination limit parameter is higher than 50. |
| Validation failed (numeric string is expected) | The API call was made with an invalid NCW wallet identifier or account ID. |
## 403 - Forbidden
| Error Name | Error Message |
| :-------------- | :---------------------------------------------------------------------------- |
| Wallet disabled | The requested NCW is disabled. Learn more [here](/reference/enablewallet). |
| Device disabled | The requested device is disabled. Learn more [here](/reference/enabledevice). |
| Tenant disabled | The entire Fireblocks workspace is disabled. |
## 404 - Not Found
| Error Name | Error Message |
| :--------------- | :------------------------------------ |
| Wallet not found | The provided wallet ID was not found. |
| Device not found | The provided device ID was not found. |
| Tenant not found | The provided tenant ID was not found. |
## 409 - Conflict
| Error Name | Error Message |
| :------------------------------ | :----------------------------------------- |
| Incomplete MPC Setup | The MPC Key generation was not completed. |
| Ongoing setup already in motion | MPC Key generation ceremony is in process. |
***
# 1XXX errors
## 1000 - Incomplete Wallet
| Error Name | Error Message |
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------- |
| Incomplete Wallet | None of the devices in the Wallet have a COMPLETE status. Learn more [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms). |
## 1001 - Incomplete Device
| Error Name | Error Message |
| :---------------- | :-------------------------------------------------------------------------------------------------------------------------------- |
| Incomplete Device | The device key status is in status INCOMPLETE. Learn more [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms). |
## 1002 - Incomplete Backup
| Error Name | Error Message |
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Incomplete Backup | The device key was not backed up. Learn more about backups [here](https://ncw-developers.fireblocks.com/docs/backup-recovery-1) and multiple algorithms [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms). |
## 1003 - Unsupported Algorithms
| Error Name | Error Message |
| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------- |
| Unsupported Algorithms | The Algorithm is not supported by the workspace. Learn more [here](https://ncw-developers.fireblocks.com/docs/multiple-algorithms). |
# Exchange & Fiat Account Webhooks
Source: https://developers.fireblocks.com/reference/exchange-fiat-account-webhooks
> **Deprecation notice**
>
> Webhooks v1 will be deprecated on **June 15th, 2026**. Please use the Developer Center in the Fireblocks Console to upgrade to Webhooks V2, which offers improved reliability, performance, and observability.
This page describes all events relating to exchange and fiat accounts that produce webhook notifications, and their associated data objects.
The `type` parameter is automatically set to the description name for the data objects below.
## Exchange account added
Notification is sent when an exchange account is added.
**Webhook data**
| Parameter | Type | Description |
| --------- | --------------------------------------- | -------------------------------------- |
| type | string | EXCHANGE\_ACCOUNT\_ADDED |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | [ThirdPartyWebhook](#thirdpartywebhook) | Exchange accounts details |
## Fiat account added
Notification is sent when a fiat account is added.
**Webhook data**
| Parameter | Type | Description |
| --------- | --------------------------------------- | -------------------------------------- |
| type | string | FIAT\_ACCOUNT\_ADDED |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | [ThirdPartyWebhook](#thirdpartywebhook) | Fiat account details |
***
### ThirdPartyWebhook
| Parameter | Type | Description |
| --------- | ------ | ------------------------------------------------------------ |
| id | string | The ID of the third-party account on the Fireblocks platform |
| subType | string | The subtype of the third party, ie. exchange or fiat name |
| name | string | Account name |
# Exchange Account Objects
Source: https://developers.fireblocks.com/reference/exchange-objects
## ExchangeAccount
| Parameter | Type | Description |
| ------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| id | string | The ID of the exchange asset to return |
| type | [ExchangeType](#exchangetype) | The name of the exchange the account is associated with |
| name | string | Display name of the exchange account |
| status | [ConfigChangeRequestStatus](/reference/general-objects#configchangerequeststatus) | Status of the exchange account connection |
| assets | Array of [ExchangeAsset](#exchangeasset) | Assets in the account |
| isSubaccount | boolean | True if the account is a subaccount in an exchange |
| mainAccountId | string | The ID of the exchange main account |
| tradingAccounts | Array of [TradingAccount](#tradingaccount) | Trading accounts under this exchange account |
| fundableAccountType | [TradingAccountType](#tradingaccounttype) | The internal account that is used for deposits or withdrawals of this exchange's main or subaccount |
***
## ExchangeAsset
| Parameter | Type | Description |
| ------------ | ------ | ------------------------------------------------------------------------------------------- |
| id | string | The ID of the exchange asset to return |
| total | string | The total balance of the asset in the exchange account |
| available | string | The balance that can be withdrawn from the exchange account or moved to a different account |
| lockedAmount | string | Locked amount in the account |
| balance | string | Deprecated - replaced by "total" |
***
## ExchangeType
| Parameter | Type | Description |
| --------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type | string | \[BINANCE, BINANCEUS, BITFINEX, BITHUMB, BITMEX, BITSO, BITSTAMP, BITTREX, BYBIT, CIRCLE, COINBASEEXCHANGE, COINBASEPRO, COINMETRO, COINSPRO, CRYPTOCOM, DERIBIT, GATE, GEMINI, HITBTC, HUOBI, IR, KORBIT, KRAKEN, KRAKENINTL, LIQUID, POLONIEX, OKCOIN, OKEX, SEEDCX] |
> **Notes**
>
> * The `BINANCEUS` value should be used only by Binance.us customers.
> * The `KRAKENINTL` value should be used only by non-US Kraken customers.
***
## TradingAccount
| Parameter | Type | Description |
| --------- | ----------------------------------------- | ------------------------------------------------------- |
| type | [TradingAccountType](#tradingaccounttype) | The specific trading account under the exchange account |
| assets | Array of [ExchangeAsset](#exchangeasset) | Assets in the trading account |
***
## TradingAccountType
| Parameter | Type | Description |
| --------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type | string | \[SPOT, FUTURES, MARGIN, FUNDING, OPTIONS, EXCHANGE, COIN\_MARGINED\_SWAP, USDT\_FUTURES, COIN\_FUTURES, USDT\_ISOLATED\_MARGINED\_SWAP, USDT\_MARGINED\_SWAP\_CROSS, FUNDABLE, UNIFIED] |
# Execute Payouts
Source: https://developers.fireblocks.com/reference/executing-payouts
# Creating a payout instruction set
When a user wants to send a payment to one or more of their merchants, they can use the Payout Service API to send the payout from their exchange account.
First, the user creates a payout instruction set using the [Create a payout instruction set](/reference/createpayout) API call. The instruction set defines:
* the payment account and its account type (vault, exchange, or fiat).
* the account type (vault account, exchange account, whitelisted address, network connection, fiat account, or merchant account), the amount, and the asset of payment for each payee account.
In this example, the user wants to send funds from an exchange account (id: “EX\_SUB3”) in their Fireblocks workspace. They want to send 43 USDC to Merchant 1 (id: “bef85a1c-b605-4b2e-bdb5-2d400f4d0bf3”) who is configured as an external wallet and 4,423 USDC to Merchant 2 (id: “3adc1f92-e791-44a8-9aee-7f31c2108b78”) who is configured as a Fireblocks Network connection.
## Example
```json theme={"system"}
{
"paymentAccount": {
"id": "EX_SUB3",
"type": "EXCHANGE_ACCOUNT"
},
"instructionSet": [
{
"payeeAccount": {
"id": "bef85a1c-b605-4b2e-bdb5-2d400f4d0bf3",
"type": "EXTERNAL_WALLET"
},
"amount": {
"amount": "43",
"assetId": "USDC"
}
},
{
"payeeAccount": {
"id": "3adc1f92-e791-44a8-9aee-7f31c2108b78",
"type": "NETWORK_CONNECTION"
},
"amount": {
"amount": "4423",
"assetId": "USDC"
}
}
]
}
```
## Response
The user then receives a unique payoutId ("1fe3b61f-7e1f-4a19-aff0-4f0a524d44d7") for their payout instruction set. This payoutId can then be used for executing the payout.
The response body also lists the state of the payout instruction set as REQUESTED and the two payment states as NOT\_STARTED.
Following are descriptions of the parameters in the response:
* **payoutId**: unique ID for the payout
* **paymentAccount**
* **id**: the ID of the payment account
* **type**: the type of payment account (vault account, exchange account, or fiat account)
* **createdAt**: when the instruction set was created
* **state**: the state of the instruction set
* **initMethod**: method of creating the instruction set
* **instructionSet**: an array of instructions for the payout. Each one details the payee, the payment amount, and the status of the payment.
* **id**: the ID for the individual payment in the instruction set
* **name**: the name of the payee
* **payeeAccount**
* **id**: the ID of the account receiving the payment
* **type**: the type of account receiving the payment
* **amount**
* **amount**: the amount being sent
* **assetId**: the asset being sent
* **state**: the status of the individual payment
* **transactions**: the transactions included in the payment
```json theme={"system"}
{
"payoutId": "1fe3b61f-7e1f-4a19-aff0-4f0a524d44d7",
"paymentAccount": {
"id": "EX_SUB3",
"type": "EXCHANGE_ACCOUNT"
},
"createdAt": 1645365800,
"state": "REQUESTED",
"initMethod": "API",
"instructionSet": [
{
"id": "6ea4a016-536b-49af-b1a0-40b343ccf879",
"name": "Merchant 1",
"payeeAccount": {
"id": "bef85a1c-b605-4b2e-bdb5-2d400f4d0bf3",
"type": "EXTERNAL_WALLET"
},
"amount": {
"amount": "43",
"assetId": "USDC"
},
"state": "NOT_STARTED",
"transactions": []
},
{
"id": "e783a79b-6acc-4d18-885d-ed533cad8eeb",
"name": "Merchant 2",
"payeeAccount": {
"id": "3adc1f92-e791-44a8-9aee-7f31c2108b78",
"type": "NETWORK_CONNECTION"
},
"amount": {
"amount": "4423",
"assetId": "USDC"
},
"state": "NOT_STARTED"
"transactions": []
}
]
}
```
***
# Executing a payout instruction set
Once the payout instruction set is created, the user can execute the payout using the [Execute a payout instruction set](/reference/executepayoutaction) API call and entering the payoutId of the instruction set that was just created ("1fe3b61f-7e1f-4a19-aff0-4f0a524d44d7").
***
# Monitoring payouts
The user can also monitor the status of the newly executed payout using the [Get the status of a payout instruction set](/reference/getpayout) API call and entering the payoutId.
## Example
`GET /payments/payout/1fe3b61f-7e1f-4a19-aff0-4f0a524d44d7`
## Response
The state and the payout status are returned.
```json theme={"system"}
{
"payoutId": "1fe3b61f-7e1f-4a19-aff0-4f0a524d44d7",
"paymentAccount": {
"id": "EX_SUB3",
"type": "EXCHANGE_ACCOUNT"
},
"createdAt": 1645365800,
"state": "FINALIZED",
"status": " DONE"
"initMethod": "API",
"instructionSet": [
{
"id": "6ea4a016-536b-49af-b1a0-40b343ccf879",
"name": "Merchant 1",
"payeeAccount": {
"id": "bef85a1c-b605-4b2e-bdb5-2d400f4d0bf3",
"type": "EXTERNAL_WALLET"
},
"amount": {
"amount": "4312",
"assetId": "USDC"
},
"state": "COMPLETED",
"transactions": [{
"id": "35a4b10c-1f83-4f0b-ba2a-da0e73be2d6e",
"state": "COMPLETED",
"timestamp": 1645367429
}]
},
{
"id": "e783a79b-6acc-4d18-885d-ed533cad8eeb",
"name": "Merchant 2",
"payeeAccount": {
"id": "3adc1f92-e791-44a8-9aee-7f31c2108b78",
"type": "NETWORK_CONNECTION"
},
"amount": {
"amount": "4423",
"assetId": "USDC"
},
"state": "COMPLETED",
"transactions": [{
"id": "4505e7d9-bfc7-41bc-9750-54311fcbbf26",
"state": "COMPLETED",
"timestamp": 1645367449
}]
}
}
],
"reportUrl": "https://some-url.com/reports/cc5777c1-75a9-4337-aebd-f1f5a40a9391"
}
```
# Postman Guide
Source: https://developers.fireblocks.com/reference/explore-postman-collection
# Overview
Postman is an application designed to help with API integration and exploration. Intuitive for different tech skill levels, this is the tool of choice both for experienced developers and no-code enthusiasts to get familiar with our available endpoints, requests, and responses.
Using our Postman Collection, you can start testing our API before you write a single line of code.
## Install Postman and Fireblocks Collection
1. Download and install the [Postman app](https://www.postman.com/downloads/) or [use Postman online](https://identity.getpostman.com/login?continue=https%3A%2F%2Fweb.postman.co%2Fhome).
2. **Import the Fireblocks collection:**
[](https://god.gw.postman.com/run-collection/25881726-6597f15a-56e5-4c82-a75e-2befc2c5264d?action=collection%2Ffork\&collection-url=entityId%3D25881726-6597f15a-56e5-4c82-a75e-2befc2c5264d%26entityType%3Dcollection%26workspaceId%3Dddfe6a6b-2c7b-4005-89f3-7204e03ec3b6%3Fenv%3DBoilerplate%2520Fireblocks%2520Environment%253D%253D)
After following the steps above and opening Postman, you'll see the Fireblocks API collection.
# Fee Estimation Objects
Source: https://developers.fireblocks.com/reference/fee-estimation-objects
## NetworkFee
| Parameter | Type | Description |
| ----------- | ------ | ----------------------------------------------------------- |
| feePerByte | string | \[optional] For UTXOs |
| gasPrice | string | \[optional] For Ethereum assets (ETH and Tokens) |
| networkFee | string | \[optional] All other assets |
| baseFee | string | \[optional] Base Fee according to EIP-1559 (ETH assets) |
| priorityFee | string | \[optional] Priority Fee according to EIP-1559 (ETH assets) |
***
## TransactionFee
| Parameter | Type | Description |
| ----------- | ------ | ------------------------------------------------------------------------------------ |
| feePerByte | string | \[optional] For UTXOs, |
| gasPrice | string | \[optional] For Ethereum assets (ETH and Tokens) |
| gasLimit | string | \[optional] For Ethereum assets (ETH and Tokens), the limit for how much can be used |
| networkFee | string | \[optional] Transaction fee |
| baseFee | string | \[optional] Base Fee according to EIP-1559 (ETH assets) |
| priorityFee | string | \[optional] Priority Fee according to EIP-1559 (ETH assets) |
***
## EstimatedTransactionFeeResponse
| Parameter | Type | Description |
| --------- | --------------------------------- | ---------------------------------------------------------------- |
| low | [TransactionFee](#transactionfee) | Transactions with this fee will probably take longer to be mined |
| medium | [TransactionFee](#transactionfee) | Average transactions fee |
| high | [TransactionFee](#transactionfee) | Transactions with this fee should be mined the fastest |
## EstimatedFeeDetails
| Parameter | Type | Description |
| --------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| low | [FeeBreakdown - Solana Specific](#feebreakdown---solana-specific) OR [FeeBreakdown - Generic](#feebreakdown---generic) | Detailed fee breakdown where the transaction will probably take longer to be mined |
| medium | [FeeBreakdown - Solana Specific](#feebreakdown---solana-specific) OR [FeeBreakdown - Generic](#feebreakdown---generic) | Average transactions fee |
| high | [FeeBreakdown - Solana Specific](#feebreakdown---solana-specific) OR [FeeBreakdown - Generic](#feebreakdown---generic) | Detailed fee breakdown where the transaction will be mined the fastest |
## FeeBreakdown - Solana Specific
| Parameter | Type | Description |
| ----------- | ------ | -------------------------------------------- |
| baseFee | string | Base fee for Solana transaction |
| priorityFee | string | Priority fee for Solana transaction |
| rent | string | Rent fee for Solana account creation/storage |
| totalFee | string | Total fee amount |
## FeeBreakdown - Generic
| Parameter | Type | Description |
| ----------- | ------ | ---------------------- |
| baseFee | string | Base fee component |
| priorityFee | string | Priority fee component |
| totalFee | string | Total fee amount |
# Fiat Account Objects
Source: https://developers.fireblocks.com/reference/fiat-account-objects
## FiatAccount
| Parameter | Type | Description |
| --------- | --------------------------------- | ---------------------------------------- |
| id | string | The ID of the account |
| type | string | \[ BLINC ] |
| name | string | The display name of the fiat account |
| address | string | The address of the account |
| assets | Array of [FiatAssets](#fiatasset) | An array of the assets under the account |
***
## FiatAsset
| Parameter | Type | Description |
| --------- | ------ | ------------------------ |
| id | string | The ID of the asset |
| balance | string | The balance of the asset |
# Fund the Gas Station
Source: https://developers.fireblocks.com/reference/fund-the-gas-station
# Overview
Maintaining funds for the Gas Station is critical to avoid business interruptions. Transactions made from wallets with insufficient gas will continuously fail until you add more funds.
Ensure proper funding by depositing the appropriate base assets into the Gas Station wallet. The Gas Station will then use these assets to refuel your monitored vault accounts with gas for their outbound transactions.
***
# Funding with the API
1. Call the [List internal wallets endpoint](/api-reference/internal-wallets/list-internal-wallets) to find the Gas Station's wallet ID.
2. Call the [Create a new transaction endpoint](/api-reference/transactions/create-a-new-transaction), enter **INTERNAL\_WALLET** in the destination object's **type** field and the Gas Station's wallet ID in the **walletId** field, and then enter the appropriate base asset (as [defined in Fireblocks](/api-reference/blockchains-&-assets/list-assets-legacy)) in the **assetId** field.
The example below funds the Gas Station wallet with ETH based on its `gasStationWalletUUID`, in the value of 0.1 ETH transferred from vault account ID 0.
```javascript theme={"system"}
const fundGasStationWallet = async (
payload: TransactionRequest,
): Promise => {
try {
const result = await fireblocks.transactions.createTransaction({
transactionRequest: payload,
});
console.log(JSON.stringify(result, null, 2));
return result.data;
} catch (e) {
console.error(e);
}
};
fundGasStationWallet({
assetId: "ETH", //update the assetID
source: {
type: TransferPeerPathType.VaultAccount,
id: "1", // update to your funding vault account ID
},
destination: {
type: TransferPeerPathType.InternalWallet,
id: "904c6da6-5aae-4280-bcb3-d0b1a36fc6e9", //update to your Gas Station internal Wallet UUID
},
amount: 0.5,
note: "Gas Station Internal Wallet Funding",
});
```
```javascript theme={"system"}
async function fundGasStationWallet(assetId, gasStationWalletUUID, fillAmount, fundingVaultId){
const payload = {
assetId: assetId,
source: {
type: PeerType.VAULT_ACCOUNT,
id: fundingVaultId
},
destination: {
type: PeerType.INTERNAL_WALLET,
id: gasStationWalletUUID
},
amount: fillAmount,
note: "Gas Station Funding"
};
const result = await fireblocks.createTransaction(payload);
console.log(JSON.stringify(result, null, 2));
}
fundGasStationWallet("ETH", "gasStationWalletUUID" ,"0.1","0");
```
```python theme={"system"}
def fund_gas_station(asset_id: str, gas_station_wallet_uuid: str, fill_amount: str,funding_vault_id: str):
tx_id = fireblocks.create_transaction(asset_id=asset_id,
amount=fill_amount,
source=TransferPeerPath("VAULT_ACCOUNT", funding_vault_id),
destination=DestinationTransferPeerPath("INTERNAL_WALLET",gas_station_wallet_uuid)
)
print(tx_id)
fund_gas_station("ETH","gasStationWalletUUID", "0.1","0")
```
# Gas Station Objects
Source: https://developers.fireblocks.com/reference/gas-station-objects
## GasStationPropertiesResponse
| Parameter | Type | Description |
| ------------- | --------------------------------------------------- | ----------------------------------------------------------- |
| balance | dictionary | A dictionary of an asset and its balance in the Gas Station |
| configuration | [GasStationConfiguration](#gasstationconfiguration) | The settings of your Gas Station |
***
## GasStationConfiguration
| Parameter | Type | Description |
| ------------ | ------ | ----------------------------------------------------------------------------------------- |
| gasThreshold | string | Below this ETH balance the address will be funded up until the gasCap value, in ETH units |
| gasCap | string | Up to this level, the address will be funded with ETH, in ETH units |
| maxGasPrice | string | The funding transaction will be sent with this maximum value gas price, in Gwei units |
# General Objects
Source: https://developers.fireblocks.com/reference/general-objects
## ConfigChangeRequestStatus
| Parameter | Type | Description |
| --------- | ------ | ------------------------------------------------------------------ |
| status | string | \[ WAITING\_FOR\_APPROVAL, APPROVED, CANCELLED, REJECTED, FAILED ] |
***
## Paging
| Parameter | Type | Description |
| --------- | ------ | ------------------------ |
| next | string | Cursor to the next page. |
# Handle API Errors
Source: https://developers.fireblocks.com/reference/handling-api-errors
# Overview
Understanding errors and how to handle them is critical to user experience and business operations when working with *any* third-party API.
Some errors might include:
* A timeout as the third-party service is experiencing issues or is down.
* An improperly formatted request due to user error or a non-fatal software bug.
* A runtime error due to a system state or an "unexpected" error.
These types of errors are important to handle when working with third-party APIs and handling individual errors will depend on the nature of each API call.
## Error types
In this section, we will dive into how to handle API errors when using Fireblocks API in terms of best practices and common pitfalls.
As the Fireblocks API uses HTTP requests to send the calls, we will look into three main error types:
1. [Non-HTTP errors](doc:error-handling#non-http-errors)
2. [4xx status codes](doc:error-handling#4xx-status-codes)
3. [500 status code](doc:error-handling#500-status-code)
> **How to handle unspecified errors**
>
> While we do our best to cover all the errors that are possible, and are constantly improving error reporting, you might encounter an error you did not read about in this guide, or the approach and best practices do not suffice.
>
> We recommend making sure to read the message that accompanies every Fireblocks API error as these are usually descriptive and can help pinpoint the issue.
***
# Non-HTTP errors
Non-HTTP errors are a broad error type that relates to anything that is not specifically a response back from the Fireblocks API. As a result, this error type may contain many individual errors that can typically be resolved with the relevant third-party documentation.
Examples of such errors include:
* Errors that prevent the execution of `.js` or `.py` (or any other extension) files such as `command not found`, or `No such file or directory`
* Errors relating to internal formatting of a file (missing indent, missing bracket, `==` instead of `===`)
* Errors relating to system state, such as lack of memory, or network connectivity issues
As described in our API guides, signing a JWT (JSON Web Token) is a critical part of API usage as the means of authenticating your message and validating your identity. (This assumes the private key used to sign your API request is securely stored and not available to anyone else).
You may be unable to sign the JWT token if you are experiencing issues with your private key. These issues are classified as "**private key corruption**". While uncommon, it can be a serious issue when trying to sign API requests.
## Private key corruption
Observe the following error message:
(If you are unfamiliar with this error, a Google search will yield many results pointing to authentication problems.)
```text theme={"system"}
Error: Error: error:1E08010C:DECODER routines::unsupported
at Sign.sign (/myproject/lib/internal/crypto/sig.js:131:29)
at Object.sign /myproject/node_modules/jwa/index.js:152:45)
at Object.jwsSign [as sign] (/myproject/node_modules/jws/lib/sign-stream.js:32:24)
at module.exports [as sign] (/myproject/node_modules/jsonwebtoken/sign.js:204:16)
at ApiTokenProvider.signJwt (/myproject/fireblocks-sdk-js/src/api-token-provider.ts:11:28)
at ApiClient. (/myproject/fireblocks-sdk-js/src/api-client.ts:15:41)
at Generator.next ()
at /myproject/fireblocks-sdk-js/dist/api-client.js:8:71
at new Promise ()
at __awaiter (/myproject/fireblocks-sdk-js/dist/api-client.js:4:12)
at ApiClient.issueGetRequest (/myproject/fireblocks-sdk-js/dist/api-client.js:27:16)
at FireblocksSDK. (/myproject/fireblocks-sdk-js/src/fireblocks-sdk.ts:537:37)
at Generator.next ()
at /myproject/fireblocks-sdk-js/dist/fireblocks-sdk.js:18:71
at new Promise ()
at __awaiter (/myproject/fireblocks-sdk-js/dist/fireblocks-sdk.js:14:12)
```
```text theme={"system"}
Traceback (most recent call last):
File "/myproject/venv/lib/python3.10/site-packages/jwt/algorithms.py", line 257, in prepare_key
key = load_pem_private_key(key, password=None)
File "/myproject/venv/lib/python3.10/site-packages/cryptography/hazmat/primitives/serialization/base.py", line 22, in load_pem_private_key
return ossl.load_pem_private_key(data, password)
File "/myproject/venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 900, in load_pem_private_key
return self._load_key(
File "/myproject/venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1168, in _load_key
self._handle_key_loading_error()
File "/myproject/venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1227, in _handle_key_loading_error
raise ValueError(
ValueError: ('Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).', [_OpenSSLErrorWithText(code=503841036, lib=60, reason=524556, reason_text=b'error:1E08010C:DECODER routines::unsupported')])
```
The issue within this error is a "corruption" of the private key. "Corruption" can also mean human error such as submitting an incorrect file that is not a private key. Follow the instructions below to resolve this error.
1. Verify that the file being used is indeed a private key.
A private key typically looks like this:
```yaml theme={"system"}
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
```
2. Verify that the private key is intact.
3. Generate something out of the private key using OpenSSL.
This command will attempt to convert the private key into its corresponding public key:
`openssl rsa -in .key -pubout`
A valid response will look something like this:
```yaml theme={"system"}
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
```
***
# 4xx status codes
4xx status codes are codes that are returned as part of an HTTP request to indicate a problem on the client's side - in the context of this article, it means that there is an issue with the request that you have sent.
We will look into 3 specific status codes and how to handle each of them:
1. [400 - Bad request](doc:error-handling#400---bad-request) Indicates that the API request itself is incorrect and contains invalid or incorrect values
2. [401 - Unauthorized](doc:error-handling#401---unauthorized) - Indicates that the API request is sent with invalid authentication information (for example, bad JWT)
3. [403 - Forbidden](doc:error-handling#403---forbidden) - Indicates that the API request is trying to perform something that the user is not allowed to do
4. [404 - Not found](doc:error-handling#404---not-found) - Indicates that the API request is trying to query a page that does not exist
In addition to the three codes, we would also like to remind you that there is the status code `429 Too many requests`, which is caused by breaking the rate limits. More information can be found in the [Working with Rate Limits](doc:rate-limits) article.
> **Example code**
>
> The example code is written to illustrate how to approach the described scenario. It might contain functions or types which are not explicitly written out, but we add a short description of what they do after the code sample.
>
> No such type or function is written in the SDK and they merely are used to illustrate some logical container for an operation.
> **Assumptions for examples**
>
> Throughout each Error Handling section the following assumptions apply:
>
> * The user input ***may not*** be valid, through function call or direct integration.
> * The network connection is functioning as expected.
> * The system has sufficient resources (memory and disk space).
>
> This is important for security and stability, as it shows how to ensure your information is valid before submitting the request and how to double-check or sanitize the user input.
>
> Typical validations are provided at the bottom of the article.
## 400 - Bad request
As mentioned above, 400 response codes indicate that the request you sent contains incorrect information or is invalid.
#### 400 example - Bad request
Your internal database links users per asset public keys with their internal database reference (for example, their user ID).
To do this, upon registration or upon some update, your code calls the following `getPublicKey`\ `get_public_key` function with the asset **supplied by the user**:
```javascript theme={"system"}
const DEFAULT_VAULT_ACCOUNT_ID = "123";
/**
fbksSdk - an instance of FireblocksSDK
asset - the asset id
*/
async function getPublicKey(fbksSdk, asset){
let pubKey = await fbks.getPublicKeyInfoForVaultAccount({
vaultAccountId: DEFAULT_VAULT_ACCOUNT_ID,
assetId:asset,
compressed:true,
addressIndex:"0",
change:"0"
});
//... Some extra work on the public key ...
}
```
```python theme={"system"}
DEFAULT_VAULT_ACCOUNT_ID = "123";
def get_public_key(fbks, asset):
"""
fbks - FireblocksSDK instance
asset - the asset id
"""
pub_key = fbks.get_public_key_info_for_vault_account(
vault_account_id=DEFAULT_VAULT_ACCOUNT_ID,
asset_id=asset,
compressed=False,
change="0",
address_index="0"
)
# ... Some extra work on the public key ...
```
The user mistakenly put an invalid asset (for example `BTC1` instead of `BTC`). Your code will receive the following error:
```text theme={"system"}
Error: Request failed with status code 400
at createError (/myproject/fireblocks-sdk-js/node_modules/axios/lib/core/createError.js:16:15)
at settle (/myproject/fireblocks-sdk-js/node_modules/axios/lib/core/settle.js:17:12)
at IncomingMessage.handleStreamEnd (/myproject/fireblocks-sdk-js/node_modules/axios/lib/adapters/http.js:293:11)
at IncomingMessage.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
```
```text theme={"system"}
Traceback (most recent call last):
File "/myproject/main.py", line 10, in
get_public_key(fbksSdk, "jngjewqn")
File "/myproject/main.py", line 8, in get_public_key
fbks.get_public_key_info_for_vault_account(vault_account_id="2", asset_id=asset, compressed=False, change="0", address_index="0")
File "/myproject/venv/lib/python3.10/site-packages/fireblocks_sdk/sdk.py", line 1066, in get_public_key_info_for_vault_account
return self._get_request(url)
File "/myproject/venv/lib/python3.10/site-packages/fireblocks_sdk/sdk.py", line 1334, in _get_request
return handle_response(response, page_mode)
File "/myproject/venv/lib/python3.10/site-packages/fireblocks_sdk/sdk.py", line 22, in handle_response
raise FireblocksApiException("Got an error from fireblocks server: " + response.text, error_code)
fireblocks_sdk.api_types.FireblocksApiException:
Got an error from fireblocks server: {
"message":"The asset 'rando' is not supported by Fireblocks, please check the supported assets endpoint.",
"code":1503
}
```
For cases where you receive a 400 HTTP status code error, try using a `try{}catch{}`\ `try:...except...` block. This can be used to handle the error in the proper way, like notifying the user or adjusting the input parameters before attempting the call again.
The following is an example of how these types of 400-based errors can be handled for the specific scenario we described:
```javascript theme={"system"}
const DEFAULT_VAULT_ACCOUNT_ID = "123";
/**
fbksSdk - an instance of FireblocksSDK
asset - the asset id
*/
async function getPublicKey(fbksSdk, asset){
let pubKeyResponse = undefined;
try{
pubKeyResponse = await fbks.getPublicKeyInfoForVaultAccount({
vaultAccountId: DEFAULT_VAULT_ACCOUNT_ID,
assetId:asset,
compressed:true,
addressIndex:"0",
change:"0"
});
} catch (e) {
let response = e.response;
if(response.status < 400 || response.status >= 500){
// Non request based error
// We assume that execution of this function will be halted after this block is done
}
let respData = response.data;
if(respData.code === 1503){ // This is discussed later on in the article
return new Error("The asset you specified is invalid, please verify that you're sending the correct asset.");
}
// Other handling
}
//... Some extra work on the public key ...
}
```
```python theme={"system"}
DEFAULT_VAULT_ACCOUNT_ID = "123"
# fbksSdk - an instance of FireblocksSDK
# asset - the asset id
def get_public_key(fbks_sdk, asset):
pub_key = None
try:
pub_key = fbks_sdk.get_public_key_info_for_vault_account(
vault_account_id=DEFAULT_VAULT_ACCOUNT_ID,
asset_id=asset,
compressed=True,
address_index=0,
change=0
)
except FireblocksApiException as e:
if e.error_code == 1503:
raise Exception("The asset you specified is invalid, please verify that you're sending the correct asset.")
# Other handling
# ... Some extra work on the public key ...
```
In both code samples, start by verifying that you received a 4xx response code (for 5xx refer to the information below). Then, you'll get the call response data and reference the parameter called `code` which represents the error code returned for the request. Each error code indicates a different issue with the request.
[Refer to our API Responses page to learn more.](ref:api-responses)
* Fireblocks Python SDK does this seamlessly for 4xx and 5xx errors, therefore handling should only consider the error code or message
### Handling a 400 error
When a 400 response is returned from the Fireblocks API, you will receive the following message:
```json theme={"system"}
{
error_code: number (optional)
message: string
}
```
This message will provide a description to inform you of any potential issues.
A best practice for error handling that you can see below is setting up a proper error handling flow for sensitive error code responses. This is done by first outlining the following:
1. Identify the features/components you're using - Are you performing wallet-specific operations (whitelisting, creating a new wallet, adding a deposit address to a wallet, etc.)?
2. Identify the user / system-provided inputs - What is constant? What is received as part of the system state (a database query, a read from a file, etc.)? What is received from user input?
3. Identify the potential errors from the [API Responses page](ref:api-responses).
After you've identified the points above, prepare your error handling respective to the API calls to best fit your needs (inform the user, run some runtime fix of the system state, etc.).
#### Implementing 400 error handling
> **Integrating into your code**
>
> The code sample, as well as the general flow, is customizable to fit your code, business logic, or existing implementation.
>
> The best practice is to change the code (shown below) to match your code language preference, as well as your business-specific practices, regulations and systems.
>
> Errors should also receive the same treatment, with the errors written in this section as an example, and should be changed to work with your flow.
>
> The most important part to take away from this section is to identify the components you'll be using and what potential errors might occur based on what input you'll receive.
For example, you're working on a system that receives a request from a user to perform a withdrawal of some amount of a given asset from their Fireblocks asset wallet address.
1. Refresh the balance of the specific asset they'd want to withdraw from the vault account we assigned to this user - using the [refresh asset balance data](ref:post_vault-accounts-vaultaccountid-assetid-balance) operation.
2. Create a transaction to send the asset from their vault account to the target address - using the [create transaction](ref:post_transactions) operation.
The refresh balance operation uses a vault account (`vaultAccountId`) and an asset (`assetId`), while the create transaction has very many potential parameters. This means that the errors returned from these parameters You can narrow down the cause of the error by going through each operation requirement to perform for your desired end result.
1. The [refresh asset balance data](ref:post_vault-accounts-vaultaccountid-assetid-balance) operation requires a valid vault account Id and a valid asset.
2. The [create transaction](ref:post_transactions) operation requires:
1. A valid asset (can be assumed valid after operation #1 takes place)
2. A valid amount of said asset (which does not exceed what they have in the wallet)
3. A valid target address
Referencing the [API Responses page](ref:api-responses) shows that given the operation requirements you should expect to see these error codes:
1. `1503` - invalid asset
2. `11001` - invalid vault account id
You might be asking yourself - what about the amount and the target address? While incorrect in the scope of the example, these values could theoretically be anything (within their given domains, amount as a positive integer, and address as a string of some length).
> **Monitoring transaction status**
>
> The failures caused by amount and destination address values are not covered in this guide. [Please refer to Monitoring transaction status for more information about these specific errors.](doc:monitor-tx-status)
```javascript theme={"system"}
// Fireblocks SDK initialized beforehand and is defined as the parameter - fbks
// There exists some variable which allows us to query a database for information, defined as - dbSvc
async function withdrawal(userId, asset, amount, to){
if(!dbSvc.userExists(userId)){
return new Error(`Unknown user: ${userId}`);
}
if(!validateToAddress(to, asset)){
return new Error("The address provided does not match conventions for the asset specificed.");
}
// We assume that the information is stored somewhere you are able to retrieve it, but where it's stored is irrelevant, this is merely for the example
let userVaultAccountId = dbSvc.getVaultAccountForUser(userId);
let assetBalance = undefined;
try{
assetBalance = parseFloat((await fbks.refreshVaultAssetBalance(userVaultAccountId, asset)).available);
} catch (e) {
fbksError(e);
}
// At this point you might want to do additional checks against different information
// in your system, depending on what your needs are.
let txArgs = {
source: {
type: PeerType.VAULT_ACCOUNT,
id: userVaultAccountId
},
destination: {
type: PeerType.ONE_TIME_ADDRESS,
oneTimeAddress: {
address: to
}
},
operation: TransactionOperation.TRANSFER,
amount: amount,
assetId: asset
};
try{
let {txId: id} = (await fbks.createTransaction(txArgs));
// Continue monitoring the transaction
} catch (e) {
fbksError(e);
}
}
// This function is used as a generic error handler for all FireblocksAPI calls, preventing us from duplicating code and
// allowing us to easily fix issues in a single location. If a call requires custom handling, its catch clause can
// be written without using this function
function fbksError(e){
let resp = e.response;
if(resp !== 400) {
// Handle other errors and return
}
let respData = resp.data;
switch(respData.code){
case 1503:
throw new Error("The asset specified is invalid");
case 11001:
// In this scenario, since the vault account Id is stored in a local database, we might want to
// show a different error or potentially raise an alert, depending on your needs.
throw new Error("The vault account Id used is invalid");
default:
// If we didn't map the potential error code, it's important to write as much information
// about the error as possible, that way we can patch the code with minimal replications or intrusive investigation
logUnexpectedError(`Faced error: ${util.inspect(respData,false,null,true)} which is not mapped.`);
throw new Error("Unexpected error - please try again later");
}
}
```
```python theme={"system"}
# Fireblocks SDK initialized beforehand and is defined as the parameter - fbks
# There exists some variable which allows us to query a database for information, defined as - db_svc
def withdrawal(user_id, asset, amount, to):
if not db_svc.user_exists(user_id):
raise Exception(f"User does not exist: {user_id}")
if not validate_address(to, asset):
raise Exception("The address provided does not match conventions for the asset specificed.")
user_vault_account_id = db_svc.get_vault_account_for_user(user_id)
asset_balance = None
try:
asset_balance = fbks.refresh_vault_asset_balance(user_vault_account_id, asset)
except FireblocksApiException as e:
fbks_error_handler(e)
try:
fbks.create_transaction(
tx_type=fireblocks_sdk.TRANSACTION_TRANSFER,
amount=amount,
source=TransferPeerPath(fireblocks_sdk.VAULT_ACCOUNT, user_vault_account_id),
destination=DestinationTransferPeerPath(fireblocks_sdk.ONE_TIME_ADDRESS, one_time_address=to)
)
except FireblocksApiException as e:
fbks_error_handler(e)
# This function is used as a generic error handler for all FireblocksAPI calls, preventing us from duplicating code and
# allowing us to easily fix issues in a single location. If a call requires custom handling, its catch clause can
# be written without using this function
def fbks_error_handler(e):
if e.error_code == 1503:
raise Exception("The asset specified is invalid")
elif e.error_code == 11001:
# In this scenario, since the vault account Id is stored in a local database, we might want to
# show a different error or potentially raise an alert, depending on your needs.
raise Exception("The vault account Id used is invalid")
else:
# If we didn't map the potential error code, it's important to write as much information
# about the error as possible, that way we can patch the code with minimal replications or intrusive investigation
log_unexpected_error(f"Faced error: {e} which is not mapped.")
raise Exception("Unknown error - please try again later")
```
Let's dissect the above code (almost identical for Python);
1. **Lines 4-6**: Performs checks on the user. (This depends on your business logic.)
2. **Lines 7-9**: Performs validation of the `to` address. Using the asset, you'll see the format of the address to expect. You'll have to define this more thoroughly, however, there are libraries that already provide this functionality.
1. Example: BTC SegWit will start with `bc1`, and EVM-based chains will be a 40-character hex (with `0x` prefix and checksummed). You'll have to define this more thoroughly, however, there are libraries that already provide this functionality.
3. **Line 11**: Get the vault account id for the user. Similar to #1 it depends on your business logic and specific setup.
4. **Lines 13-17**: Refresh the balance of the provided information (asset and vault account ID), using the try and catch you catch any exceptions, and send them to the generic API handler (this is also specific to your implementation, the way it's described here might not be the correct way to handle it in your code). If there was an error, with one of the expected, we return some descriptive error message which can be changed to explain to the user what to do.
5. **Lines 22-36**: Build the withdrawal transaction.
6. **Lines 39-43**: Send the transaction. Refer to our generic handler for any error generated from creating the transaction.
> **Fixing live error code 11001**
>
> The only part of the above code above that does not apply to live error handling error code `11001`, which specifies an invalid vault account. In this example is derived from a mock database. In live scenarios you will need to decide how to fix this yourself.
## 401 - Unauthorized
This error, though not common, basically occurs when a request that was sent contains either a missing, invalid, or otherwise incorrect JWT, and therefore the transaction fails.
Different codes indicate different reasons for the error caused in the JWT. Unless there is a widespread issue with the SDKs themselves, 401 error response codes will only result from:
1. Signing with a different user's private key (e.g. signing with another API user's key instead of yours)
2. Signing with the correct private key, but the incorrect User ID.
Both scenarios are not directly code related, and will most likely occur during the development stages of integration or executions of impromptu scripts such as staking. As a result, we cannot provide code samples to address this.
[Refer to the API Responses page to review codes related to 401 errors for JWT.](ref:api-responses)
When encountered, simply validate the API User key and API User secret path (make sure it contains the correct private key). A JWT error code might indicate a critical issue on the production server which you should address immediately. If you encounter such an error during production, do the same on the server that the code is running on.
The only other cause of this error is when you do not use the official, unedited Fireblocks SDK (or one of the specific supported side branches). In this instance, modifications to the source code of the Fireblocks SDK caused the error.
To address this, you'll need to check code modification and check if a change was made that would yield such an error. Keep in mind, however, that there is no beneficial need to perform changes to the Fireblocks SDK. Therefore, we will not discuss any further details on this matter.
## 403 - Forbidden
For specific API calls, such as [get audit logs](ref:get_audits) or [list users](ref:get_users), you might receive HTTP status code 403. This is uncommon since the API currently does not include user changes capabilities and only a small number of operations that can trigger 403.
If you see that you might run into the error, test the code prior to moving it to production. This can make certain that your API user has the sufficient permissions needed.
[Refer to the API Responses page to review specific 403 errors.](ref:api-responses)
## 404 - Not Found
A very common error code, "404 not found". This indicates that the page you were looking for, does not exist. Simply, this error message type states that whatever query you performed, whatever information you wanted to get - does not exist.
How to address such an issue:
1. Identify what's missing - These errors usually happen with GET requests, more than with other HTTP methods, and those GET requests are usually no more than 3 different arguments (with some exceptions), to help you pinpoint which one is "incorrect".
2. Address the missing data by either regenerating it using a new Fireblocks API call or raising an exception/error to notify upstream whoever sent this data.
Let's take a look at an example:
We provide some code that is invoked by a different component of the system. This code will query a vault account for the number of different assets this wallet contains. If there are more than 10 different assets, `true`, otherwise, this value is `false`.
Using the [Find a vault account by ID](ref:get_vault-accounts-vaultaccountid) API reference, you know this specific call uses the vault feature, therefore you can quickly identify the likely one:
* `1004` - No vault account by that Id
You can assume this since the response of the API call provides all the data you need, while only needing a single argument - the vault account Id. So, you can identify that this is the most suitable error code.
The code:
```javascript theme={"system"}
// Fireblocks SDK initialized beforehand and is defined as the parameter - fbks
// There exists some variable which allows us to query a database for information, defined as - dbSvc
async function sufficientAssets(userId){
if(!dbSvc.userExists(userId)){
return new Error(`Unknown user: ${userId}`);
}
// We assume that the information is stored somewhere you are able to retrieve it, but where it's stored is irrelevant, this is merely for the example
let userVaultAccountId = dbSvc.getVaultAccountForUser(userId);
try{
let numberOfAssets = (await fbks.getVaultAccountById(userVaultAccountId)).assets.length;
return numberOfAssets <= 10;
} catch (e) {
fbksError(e);
}
}
// This function is used as a generic error handler for all FireblocksAPI calls, preventing us from duplicating code and
// allowing us to easily fix issues in a single location. If a call requires custom handling, its catch clause can
// be written without using this function
function fbksError(e){
let resp = e.response;
if(resp !== 400) {
// Handle other errors and return
}
let respData = resp.data;
switch(respData.code){
case 1004:
throw new UnknownVaultAccountIdError();
default:
// If we didn't map the potential error code, it's important to write as much information
// about the error as possible, that way we can patch the code with minimal replications or intrusive investigation
logUnexpectedError(`Faced error: ${util.inspect(respData,false,null,true)} which is not mapped.`);
throw new Error("Unexpected error - please try again later");
}
}
```
```python theme={"system"}
# Fireblocks SDK initialized beforehand and is defined as the parameter - fbks
# There exists some variable which allows us to query a database for information, defined as - db_svc
def sufficient_assets(user_id):
if not db_svc.user_exists(user_id):
raise Exception(f"User does not exist: {user_id}")
user_vault_account_id = db_svc.get_vault_account_for_user(user_id)
try:
asset_count = len(fbks.get_vault_account_by_id(user_vault_account_id)["assets"])
return asset_count <= 10
except FireblocksApiException as e:
fbks_error_handler(e)
# This function is used as a generic error handler for all FireblocksAPI calls, preventing us from duplicating code and
# allowing us to easily fix issues in a single location. If a call requires custom handling, its catch clause can
# be written without using this function
def fbks_error_handler(e):
if e.error_code == 1004:
raise UnknownVaultAccountIdException()
else:
# If we didn't map the potential error code, it's important to write as much information
# about the error as possible, that way we can patch the code with minimal replications or intrusive investigation
log_unexpected_error(f"Faced error: {e} which is not mapped.")
raise Exception("Unknown error - please try again later")
```
Let's dissect the code once more (almost identical for python):
1. Lines 4-6: Check the existence of such a `userId`
2. Line 8: Finds the vault account correlated to this `userId`
1. Let's assume, in this case, that if no such vault account exists in your internal database, you need to add a new entry incrementing from the last added vault account id
3. Lines 9-14: Gets the vault account and counts the number of assets. Returns based on our previous explanation (at most 10).
If there is an error, handle using the generic error handler. If there is an error code `1004`, you'll receive a specific type of error. This type of error, in our scenario, will generate a new vault account by something upstream from where the error occurred.
***
# 500 status code
500 status code is an indication that there was an issue that happened on the server side. Due to this, it is not possible for us to provide a way to handle such errors in the same manner as we did for the 4xx errors.
We suggest the following:
1. Do not immediately attempt the request again
2. Double-check the parameters you're passing, it might be that one of the parameters you're passing is not formatted correctly, thus resulting in a failure in our backend
3. Check the [status page](https://status.fireblocks.com/) to check if there is an ongoing issue
4. Open a Support ticket / reach out to Support on Slack to see address the issue
***
# Common validations to perform
Generally, validations should be done based on your needs and as soon as you have sufficient details to validate them. This will divide into two potential scenarios (but not limited to those two):
1. You received the value and can immediately perform validation on that value
2. You received the value but some additional data is required before performing the validation
We provide some common validations that can and should be done which will lower your risk of getting errors in your response that is caused by your code.
* Asset validation - When getting an asset, always verify that the asset is indeed a supported one. [More information can be found in the supported assets API reference](ref:get_supported-assets).
* OTA validation - When using one-time address, which is received from the user themselves, ensure that the format of the address matches the format of the network.
* For example, BTC SegWit will require an address starting with `bc1` and complying with Bech32 formatting. EVMs will be a 40-character checksummed hex string with a prefix of `0x`.
* Amount validation - In cases where you allow users to specify amounts, such as partial withdrawal uses, you'll always need to:
1. Get the current balance available for the user, either via an API call or via an internal ledger (depending on your business logic).
2. Verify that the amount is a positive decimal value in the range of (0, retrieved balance] (excluding 0).
* Vault account validation - Ensure the vault account is a non-negative integer.
You might want to add restrictions (both in your Transaction Authorization Policy and in your code, to prevent access to vault accounts you don't want users to be able to access).
# Fireblocks Hardhat Plugin
Source: https://developers.fireblocks.com/reference/hardhat-plugin
# Overview
Hardhat is a development environment for Ethereum software that provides tools for editing, compiling, debugging, and deploying smart contracts and dApps.
The [Fireblocks Hardhat Plugin](https://github.com/fireblocks/hardhat-fireblocks) integrates Fireblocks' secure transaction features into your Hardhat workflow, enabling secure deployment and transaction signing.
# Using Hardhat
To use the Fireblocks Hardhat Plugin, you must have [Hardhat installed](https://hardhat.org/hardhat-runner/docs/getting-started).
You can follow our abridged Hardhat installation steps below or skip to the [Fireblocks Hardhat Plugin](ref:hardhat-plugin#fireblocks-plugin) section if you already have Hardhat installed.
## Install Hardhat
If you need to install Hardhat, you can use our abridged installation guide below. For a complete guide, refer to the official [Hardhat installation guide](https://hardhat.org/hardhat-runner/docs/getting-started).
### Abridged Hardhat installation guide
1. Install the Hardhat package:
```bash theme={"system"}
npm install --save-dev hardhat
```
2. Initialize a new Hardhat project:
```bash theme={"system"}
npx hardhat
```
This generates the following Hardhat menu display:
```text theme={"system"}
888 888 888 888 888
888 888 888 888 888
888 888 888 888 888
8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
888 888 "88b 888P" d88" 888 888 "88b "88b 888
888 888 .d888888 888 888 888 888 888 .d888888 888
888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888
👷 Welcome to Hardhat v2.10.1 👷
? What do you want to do? …
❯ Create a JavaScript project
Create a TypeScript project
Create an empty hardhat.config.js
```
3. Select **Create a JavaScript project** and press **Enter**.
4. Follow the proceeding setup prompts.
Complete these steps to generate a new JavaScript Hardhat project in your current directory.
## Fireblocks Plugin
The [Fireblocks Hardhat Plugin](https://github.com/fireblocks/hardhat-fireblocks) helps seamlessly integrate Fireblocks into your Hardhat development stack. You can use it to deploy contracts, sign messages, and send transactions securely through Fireblocks.
### Installing the Hardhat plugin
1. Install the plugin package:
```bash theme={"system"}
npm install @fireblocks/hardhat-fireblocks
```
2. Import the plugin into your `hardhat.config.js` file:
```javascript theme={"system"}
require("@fireblocks/hardhat-fireblocks");
const { ApiBaseUrl } = require("@fireblocks/fireblocks-web3-provider");
require('dotenv').config();
```
### Configuring the Hardhat plugin
This plugin extends the `HttpNetworkUserConfig` object with an optional `fireblocks` field.
1. For this example, copy the code sample below into your `hardhat.config.js` configuration file:
```javascript theme={"system"}
module.exports = {
solidity: "0.8.17",
networks: {
sepolia: {
url: "https://sepolia.drpc.org",
fireblocks: {
apiBaseUrl: ApiBaseUrl.Sandbox, // Only use in a Sandbox workspace
privateKey: process.env.FIREBLOCKS_API_PRIVATE_KEY_PATH,
apiKey: process.env.FIREBLOCKS_API_KEY,
vaultAccountIds: process.env.FIREBLOCKS_VAULT_ACCOUNT_IDS,
}
},
},
};
```
> **Working in Sandbox**
>
> If you are not using a Sandbox workspace, remove the `apiBaseUrl` line.
2. Delete the `Lock.sol` file that came with your generated Hardhat environment:
```bash theme={"system"}
rm contracts/Lock.sol
```
## Deploy a contract using Hardhat Ignition
Now that your Hardhat plugin has been configured to work with Fireblocks, you can begin deploying a smart contract to the Sepolia Ethereum Testnet.
### Create and compile the Solidity file
1. Create a Solidity file in your project folder:
```bash theme={"system"}
touch contracts/HelloWorld.sol
```
2. Copy the following code sample into your `HelloWorld.sol` file:
```solidity theme={"system"}
pragma solidity ^0.8.17;
contract HelloWorld {
string public greet = "Hello World!";
}
```
3. Run the following command to compile the project:
```bash theme={"system"}
npx hardhat compile
```
### Update and deploy the script
1. Create a new file `ignition/modules/HelloWorld.js` and add the following module definition:
```javascript theme={"system"}
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
module.exports = buildModule("HelloWorld", (m) => {
const helloWorld = m.contract("HelloWorld");
return { helloWorld };
});
```
2. Deploy your contract to the Ethereum Sepolia Testnet using Hardhat Ignition:
```bash theme={"system"}
npx hardhat ignition deploy ignition/modules/HelloWorld.js --network sepolia
```
This should take a couple of minutes to run if everything was configured correctly.
Once the deploy script has finished running successfully, the following message will appear:
```bash theme={"system"}
Hardhat Ignition 🚀
Deploying [ HelloWorld ]
Batch #1
Executed HelloWorld#HelloWorld
[ HelloWorld ] successfully deployed 🚀
Deployed Addresses
HelloWorld#HelloWorld -
```
### Post-deployment
Hardhat Ignition creates an `ignition/deployments/chain-11155111` folder for Sepolia that contains all the deployment details. This data enables Hardhat Ignition to recover from errors, resume interrupted deployments, and manage deployment states.
## Summary
You have now integrated the Fireblocks Hardhat Plugin into your Ethereum development workflow and deployed a smart contract to the Sepolia Testnet using Hardhat Ignition! This setup enables you to securely deploy contracts and manage transactions with Fireblocks’ infrastructure.
# Hedera Token Service SDK
Source: https://developers.fireblocks.com/reference/hedera-token-service-sdk
> **This Tool Utilizes Fireblocks RAW Signing**
>
> Raw Signing is an insecure signing method and is not generally recommended.
> Bad actors can trick someone into signing a valid transaction message and use it to steal funds.
>
> For this reason, Raw Signing is a premium feature that requires an additional purchase and is not available in production workspaces by default. If you're interested in this feature and want to see if your use case is eligible for it, please contact your Customer Success Manager.
>
> **Note:** Fireblocks Sandbox workspaces have Raw Signing enabled by default to allow for testing purposes.
This library provides an implementation of the Hedera Client designed for signing operations with the Fireblocks TypeScript SDK. It adheres to [HIP-338](https://hips.hedera.com/hip/hip-338).
Internally, the implementation acts as a wrapper utilizing Raw Signing. It manages all necessary raw signing calls, abstracting the complexities to ensure easy and seamless integration with both Fireblocks and the Hedera SDK.
Additionally, this library supports any token operations on the Hedera blockchain that are not yet natively available through the Fireblocks console and APIs. For code examples and further guidance on how to use the library, please visit the [GitHub repository](https://github.com/fireblocks/hbar-fireblocks-sdk).
# How to Use Fireblocks TypeScript SDK with Travel Rule Messages
Source: https://developers.fireblocks.com/reference/how-to-use-fireblocks-typescript-sdk-with-travel-rule-messages
The legacy Fireblocks JS SDK already includes PII encryption, whereas the new Fireblocks TS SDK does not. Therefore, you need to implement a manual install to add the PII encryption to use Fireblocks TypeScript SDK with Travel Rule Messages. For details, please follow the steps below:
***
## Step 1: Install the SDK
* Run `yarn add @fireblocks/ts-sdk`or `npm install @fireblocks/ts-sdk`
## Step 2: Implement Notabene PII Encryption
Since the new TypeScript SDK does not include PII encryption, users must manually encrypt PII data before sending the request. The example below is using @notabene/pii-sdk:
```typescript theme={"system"}
import PIIsdk, { PIIEncryptionMethod } from "@notabene/pii-sdk";
const piiEncryption = new PIIsdk({
piiURL: "[https://pii.notabene.dev"](https://pii.notabene.dev"),
audience: "[https://pii.notabene.dev"](https://pii.notabene.dev"),
clientId: process.env.NOTABENE\_CLIENT\_ID,
clientSecret: process.env.NOTABENE\_CLIENT\_SECRET,
authURL: "[https://auth.notabene.id/oauth/token"](https://auth.notabene.id/oauth/token"),
});
// Encrypt the PII data
async encode(
travelRuleMessage: TravelRuleCreateTransactionRequest,
travelRuleEncryptionOptions?: TravelRuleEncryptionOptions,
): Promise {
// If there's no "pii" field, default to originator & beneficiary
const pii = travelRuleMessage.pii || {
originator: travelRuleMessage.originator,
beneficiary: travelRuleMessage.beneficiary,
};
const jsonDidKey = this.configService.config.notabene.jsonDIDKey;
const counterpartyDIDKey =
travelRuleEncryptionOptions?.beneficiaryPIIDidKey;
let piiIvms = await this.toolset.generatePIIField({
pii,
originatorVASPdid: travelRuleMessage.originatorVASPdid,
beneficiaryVASPdid: travelRuleMessage.beneficiaryVASPdid,
counterpartyDIDKey,
keypair: JSON.parse(jsonDidKey),
senderDIDKey: JSON.parse(jsonDidKey).did,
encryptionMethod: travelRuleEncryptionOptions?.sendToProvider
? PIIEncryptionMethod.HYBRID
: PIIEncryptionMethod.END_2_END,
});
travelRuleMessage.beneficiary = piiIvms.beneficiary;
travelRuleMessage.originator = piiIvms.originator;
return travelRuleMessage;
}
```
## Step 3: Send a Fireblocks Transaction with the Travel Rule Message
Once PII data is encrypted, users can pass it into the Fireblocks TypeScript SDK when creating a blockchain transaction.
```javascript theme={"system"}
import { FireblocksSDK, PeerType, TransactionArguments, TravelRuleCreateTransactionRequest } from "@fireblocks/ts-sdk";
// Initialize Fireblocks SDK
const fireblocks = new FireblocksSDK(
process.env.FIREBLOCKS_API_SECRET_KEY,
process.env.FIREBLOCKS_API_KEY,
process.env.FIREBLOCKS_API_URL
);
// Construct the transaction request
const transaction: TransactionArguments = {
assetId: "ETH_TEST",
source: {
type: PeerType.VAULT_ACCOUNT,
id: "1",
},
destination: {
type: PeerType.ONE_TIME_ADDRESS,
oneTimeAddress: {
address: "0x123456789abcdef123456789abcdef123456789a",
},
},
operation: "TRANSFER",
amount: "0.5",
note: "Travel Rule Test TX",
travelRuleMessage: TravelRuleCreateTransactionRequest, // Pass the encrypted Travel Rule message here
};
// Send the transaction request
const result = await fireblocks.createTransaction(transaction);
console.log("Transaction Created:", result);
```
# Add a new Co-signer to the workspace
Source: https://developers.fireblocks.com/reference/install-api-cosigner-add-new-cosigner-p2
To connect a new Co-signer to your workspace, pair it with an API user from the workspace. It is recommended to create a new API user for that purpose. The pairing process for the first API user requires admin-level access to the Fireblocks Console and the owner's availability to approve the necessary workspace configuration operations.
Pairing the Co-signer is performed using a JWT-encoded Pairing Token obtained from the Console for a specific API user. This pairing token is used during Co-signer installation to pair the initial API user, enabling communication with Fireblocks' SaaS. The Co-signer is identified exclusively by the workspace and the API user used to establish the connection.
***
## Prerequisites
During installation, you will use the following items from the Fireblocks Console. Copy them to your clipboard for later use.
* The API user's pairing token
* The download link of the installation script that matches your Co-signer type: Intel SGX, AWS Nitro, or Google Cloud Confidential Space.
***
## Step 1: Add a new API user
Add a new API user to the workspace using the [Fireblocks APIs](https://docs.fireblocks.com/api/swagger-ui/#/Api%20User/createApiUser) or the **API users** tab in the Console's Developer Center. This API user will enable the Co-signer to connect to the workspace.
* Enter the name of the new API user (you can enter up to 30 characters)
* Select the role you want to assign to the API user
* Attach [a CSR file](/docs/generate-a-csr-for-an-api-user)
> **Important note**
>
> While the Co-signer does not use the CSR file to connect to the workspace, you must still provide it. This is necessary because the API user can be used to make API calls.
***
## Step 2: Add a new Co-signer to the workspace
Add a new Co-signer to the workspace using the [Fireblocks Co-signer APIs](https://docs.fireblocks.com/api/swagger-ui/#/Cosigners%20\(Beta\)) or the **Co-signers** tab in the Console's Developer Center.
To add a new Co-signer to the workspace, click **Add co-signer** and follow the instructions:
* Enter the name of the new Co-signer
* Select **Install a new co-signer on the local machine** and press **Continue**
* Choose an available API user from the list (only API users not already paired with Co-signers will be displayed)
* Click **Add** to create a new Co-signer entry
The new Co-signer will now appear in the list of Co-signers in the Co-signers tab. It is not yet connected to the workspace, so it appears as offline. The connection will be established once you complete the installation process.
***
## Step 3: Copy the API user's pairing token & the installation script's download link
Click **Pair API user** in the new Co-signer's entry to open a dialog, and follow the instructions:
* Copy the API user's pairing token to your clipboard. In mainnet workspaces, the pairing token is valid for one hour.
* Copy the download link for the AWS Nitro Co-signer installation package (found under "Manual") to your clipboard. This link is valid for seven days.
> **Need help?**
>
> If you have any issues with finding or retrieving the download link of the Co-signer's installation script in the Console, [contact Fireblocks Support](https://support.fireblocks.io/hc/en-us/requests/new).
# Install SGX Alibaba Cloud API Co-signer
Source: https://developers.fireblocks.com/reference/install-api-cosigner-alibaba
## Overview
To install an SGX Co-signer in Alibaba Cloud and connect it to your workspace, follow these steps:
1. **Setup and configure your Alibaba Cloud environment**
Prepare your Alibaba Cloud environment by creating and configuring the required resources. Ensure it meets the necessary specifications and security settings.
2. **Add a Co-signer to the workspace using an API user**
Using the Fireblocks Console or APIs, create an API user and use it to add a Co-signer to the workspace.
3. **Install and connect the Co-signer to the workspace**
Download the installation script to the SGX-capable virtual machine and run the script to install the Co-signer. Once installation is complete, the workspace owner approves the new MPC key shares for the API user through the Fireblocks mobile app.
You can now view the Co-signer and its paired API user in your Fireblocks Console. Additionally, you can retrieve information about them using the Co-signer APIs.
***
## Step 1: Setup and configure your Alibaba Cloud environment
### 1.1. Allowlist domains
To ensure the Co-signer can be installed and operated successfully, add the following domains to your allowlist:
| Domain | Owner |
| --------------------------------------- | -------------------------- |
| `mobile-api.fireblocks.io` | Fireblocks |
| `signurl.fireblocks.io` | Fireblocks |
| `s3signurl.fireblocks.io` | Fireblocks |
| `fb-certs.s3.amazonaws.com` | AWS |
| `fb-customers.s3.amazonaws.com/uploads` | AWS |
| `fb-cosigner-images.s3.amazonaws.com` | AWS |
| `fb-customers.s3.amazonaws.com` | AWS |
| `download.docker.com` | Docker |
| `registry.gitlab.com` | GitLab |
| `cdn.registry.gitlab-static.net` | GitLab |
| `gitlab.com` | GitLab |
| `github.com` | GitHub |
| `download.01.org` | Intel SGX Driver |
| `bootstrap.pypa.io` | Python Software Foundation |
| `files.pythonhosted.org` | Python Software Foundation |
| `pypi.org` | Python Software Foundation |
| `pypi.python.org` | Python Software Foundation |
Fireblocks-owned domains differ based on the specific Fireblocks SaaS environment you are connected to. If you are connected to the European or Swiss SaaS, update your allowlist according to the domains listed in the table below:
| Fireblocks SaaS | Domains to Allow |
| --------------- | ------------------------------------------------------------------------------------------ |
| Global | `mobile-api.fireblocks.io` `signurl.fireblocks.io` `s3signurl.fireblocks.io` |
| Europe | `eu2-mobile-api.fireblocks.io` `eu2-signurl.fireblocks.io` `eu2-s3signurl.fireblocks.io` |
| Swiss | `eu-mobile-api.fireblocks.io` `eu-signurl.fireblocks.io` `eu-s3signurl.fireblocks.io` |
Additionally, ensure port access is configured for the following services:
| Port | Service URL |
| ---- | ------------------------------------------------ |
| 443 | `https://mobile-api.fireblocks.io` |
| 443 | `https://s3signurl.fireblocks.io` |
| 443 | `https://fb-certs.s3.amazonaws.com` |
| 443 | `https://fb-customers.s3.amazonaws.com/uploads/` |
| 443 | `https://bootstrap.pypa.io/get-pip.py` |
| 443 | `https://download.docker.com/linux` |
| 443 | `https://download.01.org/intel-sgx/` |
| 5000 | `https://registry.gitlab.com/customer-cosigner` |
### 1.2. Create an SGX virtual machine
> **Important:**
>
> See this [Alibaba Security Enhanced Instance Family Overview](https://www.alibabacloud.com/help/en/elastic-compute-service/latest/security-enhanced-instance-family-overview) document for details on which instance type to select.
**The minimum hardware requirements for the VM are:**
* RAM: 16GB
* Storage: 256GB
* OS:
* Ubuntu 20.04
* Latest Linux kernel version
* Latest Intel microcode (BIOS update)
Complete the following steps to create an SGX-capable VM in Alibaba Cloud:
1. On the **Workbench** page, click **Elastic Compute Service**.
2. On the Overview tab, click **Create Instance**.
3. Select the following options from Custom Launch:
1. Region: Select your region.
2. Instance Type: Enter "g7t" in "Search by instance type name", then select `ecs.g7t.2xlarge` (recommended).
4. Complete the Networking, System Configurations, and Grouping pages per your organization's policies for each.
5. Click **Create Instance**.
### 1.3. Verify SGX is enabled on your VM
After creating your virtual machine, confirm that SGX is enabled. The SGX Co-signer requires a server with SGX enabled and the latest patches applied. This verification ensures smooth operation and avoids potential issues.
To verify that SGX is enabled on the VM, run the following commands with root privileges::
```bash theme={"system"}
apt update
apt upgrade
apt install cpuid
cpuid -1 | grep -i sgx
```
Verify the following:
1. `SGX`: Software Guard Extensions supported is **true**
2. `SGX_LC`: SGX launch config supported is **true**
### 1.4. Additional security recommendations
It is highly recommended to control user and network access to Co-signer's machine. See [API Co-signer security checklist and recommended defense and monitoring systems](/docs/co-signer-security-checklist-defense-monitoring) for further information.
***
## Step 2: Add a Co-signer to the workspace using an API user
Follow the instructions to [add a new Co-signer to the workspace](/reference/install-api-cosigner-add-new-cosigner-p2). Ensure you copy to your clipboard the following items, which you will use during the installation process:
* The API user's pairing token
* The download link of the Co-signer's installation script
***
## Step 3: Install and connect the Co-signer to the workspace
> **Note:** You must have root privileges on the Co-signer machine to install the Co-signer. Ensure you are logged in as a root user or use `sudo` to execute the commands.
### 3.1. Download the installation script
Using the download link of the SGX Co-signer installation script you copied from the Console, run the `curl` command to download the package directly to your machine.
Paste the appropriate URL into the following command:
```bash theme={"system"}
curl -o cosigner "URL"
```
### 3.2. Run the installation script
After downloading the installation script, navigate to the directory containing the script and modify the script's permissions to make it executable:
```bash theme={"system"}
chmod +x cosigner
```
To install the Co-signer, run:
```bash theme={"system"}
./cosigner setup
```
You will be prompted to enter the **Pairing token** for the API user, which you retrieve from the Fireblocks Console. This token pairs the API user with the Co-signer.
At this stage, you will have the option to configure the Callback Handler parameters for the API user connecting the Co-signer to the workspace. This feature is optional. You can [configure it later through the Console, APIs, or locally](/reference/api-cosigner-operate) from the Co-signer's host machine.
For detailed instructions on setting up your Callback Handler's interface to the Co-signer and implement its logic and code, refer to the [Setup API Co-signer Callback Handler](/reference/api-cosigner-setup-callback-handler) section.
The setup process validates the machine's hardware and installs the necessary drivers to support the appropriate SGX version and the SGX Co-signer's executable image. It includes an attestation flow to ensure that the SGX Co-signer's executable runs securely inside an Intel SGX enclave. Additionally, the script installs other required components.
Once the installation is complete, the Co-signer will automatically start running. At the end of the process, the Co-Signer generates a JSON configuration file, which can be used for future configuration updates.
### 3.3: Approve MPC key shares for the API user
If the API user used to pair with the Co-Signer and connect it to your workspace has an Admin or User role, the workspace owner will receive a notification. This notification will prompt them to approve a new MPC key share request for that API user using the Fireblocks mobile app.
You can now see the Co-signer you installed in the Co-signers tab within the Console's Developer Center. Observe it is online and that the API user is paired to it.
***
> **To check the Co-signer's status and observe the logs, see the SGX Co-signer Maintenance article.**
# Install AWS Nitro API Co-signer
Source: https://developers.fireblocks.com/reference/install-api-cosigner-aws
## Overview
To install a Nitro Co-signer in AWS and connect it to your workspace, follow these steps:
1. **Setup and configure your AWS environment:** Prepare your AWS environment by creating and configuring the required resources. Ensure it meets the necessary specifications and security settings.
2. **Add a Co-signer to the workspace using an API user:** Using the Fireblocks Console or APIs, create an API user and use it to add a Co-signer to the workspace.
3. **Install and connect the Co-signer to the workspace:** Download the installation script to the Nitro-capable EC2 machine and run the script to install the Co-signer. Once installation is complete, the workspace owner approves the new MPC key shares for the API user through the Fireblocks mobile app.
You can now view the Co-signer and its paired API user in your Fireblocks Console. Additionally, you can retrieve information about them using the Co-signer APIs.
***
## Step 1: Set up and configure your AWS environment
Proper configuration of your AWS environment is straightforward but must be performed step by step in the specified order. Any misconfiguration could compromise the Co-signer's functionality or security.
### Required AWS account permissions
You must have the necessary AWS account permissions to enable network access to the required domains and to create and configure the following resources:
* IAM Role
* Customer Managed Key (CMK)
* S3 bucket
* Nitro-capable EC2 machine
### Step 1.1: Allowlist domains
To ensure the Co-signer can be installed and operated successfully, add the following domains to your allowlist:
| Domain | Owner |
| ---------------------------- | ------------------------------------------------ |
| `mobile-api.fireblocks.io` | Fireblocks |
| `signurl.fireblocks.io` | Fireblocks |
| `s3signurl.fireblocks.io` | Fireblocks |
| `s3.{region}.amazonaws.com` | AWS (Replace `{region}` with the applicable one) |
| `kms.{region}.amazonaws.com` | AWS (Replace `{region}` with the applicable one) |
| `bootstrap.pypa.io` | Python Software Foundation |
| `files.pythonhosted.org` | Python Software Foundation |
| `pypi.org` | Python Software Foundation |
| `pypi.python.org` | Python Software Foundation |
| `fb-certs.s3.amazonaws.com` | AWS |
Fireblocks-owned domains differ based on the specific Fireblocks SaaS environment you are connected to. If you are connected to the European or Swiss SaaS, update your allowlist according to the domains listed in the table below:
| Fireblocks SaaS | Domains to Allow |
| --------------- | ------------------------------------------------------------------------------------------ |
| Global | `mobile-api.fireblocks.io` `signurl.fireblocks.io` `s3signurl.fireblocks.io` |
| Europe | `eu2-mobile-api.fireblocks.io` `eu2-signurl.fireblocks.io` `eu2-s3signurl.fireblocks.io` |
| Swiss | `eu-mobile-api.fireblocks.io` `eu-signurl.fireblocks.io` `eu-s3signurl.fireblocks.io` |
> **Additional notes**
>
> * For a better understanding of the Co-Signer's communication with the above URLs, refer to the [AWS Nitro API Co-signer Architecture](/docs/aws-nitro-api-co-signer) article.
> * If you cannot support DNS IP whitelisting with an advanced firewall or within the cloud itself, you must allow egress traffic to any destination on port 443.
### Step 1.2: Set up and configure an IAM role
Identity and Access Management (IAM) roles are used to delegate access to your AWS resources. Create an IAM security role that ties everything together by granting only the necessary permissions to the specific resources.
1. From the Identity and Access Management (IAM) page, select **Roles** and **Create role**. On the Select trusted entity page, select:
1. **Trusted entity type:** AWS service
2. **Service or use case:** EC2
2. Select **Next**. On the Add permissions page, don’t make any selections.
3. Select **Next**. Enter the role’s name and select **Create role** without changing the trust policy.
4. Select the newly created role and copy the IAM ARN for the next steps. The IAM ARN has the following structure:
`arn:aws:iam::{ACCOUNT-ID}:role/{ROLE-NAME}`
When you finish, the Permissions policies section will be empty (as shown below). After setting up the S3 bucket and the Customer Managed Key (CMK) in the Key Management Service (KMS), you will return to Permissions policies to add the required policies for those resources.
### Step 1.3: Set up and configure an S3 bucket
Create the S3 bucket that serves as the Co-signer's persistent storage.
1. From the Amazon S3 page, select **Create bucket**. Enter its name, leave everything else as default, and create the bucket.
2. Select the newly created bucket and on the bucket’s details page, select **Permissions**.
3. In the Bucket policy section, select **Edit** and copy-paste the S3 policy from the text box below.
4. Select **Save changes** to complete the operation.
5. Select the newly created bucket and copy the Bucket ARN for the next steps. The Bucket ARN has the following structure:
`arn:aws:s3:::\{BUCKET-NAME}`
Make sure you replace the`{BUCKET-NAME}`, `{ACCOUNT-ID}` and `{ROLE-NAME}` with the correct values.
```json theme={"system"}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:AbortMultipartUpload",
"s3:GetObjectAcl",
"s3:PutObjectAcl",
"s3:RestoreObject"
],
"Resource": [
"arn:aws:s3:::{BUCKET-NAME}",
"arn:aws:s3:::{BUCKET-NAME}/*"
],
"Condition": {
"ArnNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::{ACCOUNT-ID}:role/{ROLE-NAME}"
}
}
}
]
}
```
### Step 1.4: Set up and configure a KMS Customer-Managed Key (CMK)
Create a Customer-Managed Key (CMK) in KMS to safeguard the Co-signer’s MPC key shares.
#### Create the key
1. Open the Key Management Service (KMS) page and select **Create key**.
2. On the Configure key page, select:
1. **Key type:** Symmetric
2. **Key usage:** Encrypt and decrypt
3. Expand the **Advanced options** section and select:
1. **Key material origin:** KMS
2. **Regionality:** Single-Region key.
**Note:** Select the Multi-Region key only if the EC2 instance is in a different region.
4. Select **Next**.
#### Add labels
1. On the Add labels page, set a display name for the key in the **Alias** field (e.g., `fireblocks-nitro-cosigner`).
2. Optionally, fill in the **Description** and **Tags** fields.
3. Select **Next**.
#### Configure permissions
1. On the Define key administrative permissions page, leave the **Key administrators** section blank and leave the **Key deletion** option checked.
2. Select **Next**.
3. On the Define key usage permissions page, leave the **Key users** section blank.
4. Select **Next**.
#### Finalize the key
1. On the Review page, scroll down to the Key policy section.
2. Paste the KMS policy in the Key policy section.
3. Select **Finish**.
#### Get the key ARN
1. Select the newly created key.
2. Copy the KMS ARN for the next steps.
The KMS ARN has the following structure: `arn:aws:kms:{KEY-REGION}:{ACCOUNT-ID}:key/{KEY-ID}`
Ensure you replace `{ACCOUNT-ID}` and `{KEY-ID}` with the correct values.
#### Understanding the policy warning
When you paste the KMS policy, you might see the following warning:
> **Unsupported Action For Condition Key**
>
> The following actions: `kms:GetKeyPolicy` are not supported by the condition key `kms:RecipientAttestation:PCR8`. The condition will not be evaluated for these actions. We recommend that you move these actions to a different statement without this condition key.
**Why you can safely ignore this warning:**
* The `kms:RecipientAttestation:PCR8` condition is only evaluated on KMS calls that include an attestation report from the enclave.
* AWS ignores the condition on actions that never carry a report in the request (such as `GetKeyPolicy` and `Encrypt`) and emits this advisory.
* **Security impact:** None. All sensitive operations (`Decrypt`, `DeriveSharedSecret`, `GenerateDataKey`, `GenerateRandom`) remain protected by the PCR8 attestation check.
* **Functionality impact:** Unaffected. This behavior is by design, and the key can be used by the Fireblocks Nitro Co-signer immediately.
The value for PCR8 varies based on the Fireblocks SaaS environment to which you are connected. Copy the correct value into the CMK policy:
| Fireblocks SaaS | `{PCR8-VALUE}` |
| --------------- | -------------------------------------------------------------------------------------------------- |
| Global | `da1d9eca20ce98ab4fdbc51f8e5a2307fd4c61829b7d8bff40976cd6676862c8f3476ff4bdd0f65ecf4a48d6eb3099a8` |
| Europe | `fffc94d68a150b49dc39b23954c793cd1a4f7972f528a1ee258dc130b6cd9454e29ae72ef66bd9697a55e774e17a2d49` |
| Swiss | `69b1fbe9fb4ea49e084fe6f9f9623d871bd22ceb5efad47b1a8d3708e6674868cad8bf088ced3976c2194360c7d58219` |
```json theme={"system"}
{
"Version": "2012-10-17",
"Id": "key-consolepolicy-4",
"Statement": [
{
"Sid": "Enable enclave data processing for specific role",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{ACCOUNT-ID}:role/{ROLE-NAME}"
},
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey",
"kms:GenerateDataKeyPair",
"kms:GenerateDataKeyWithoutPlaintext",
"kms:GenerateDataKeyPairWithoutPlaintext",
"kms:GenerateRandom",
"kms:GetKeyPolicy"
],
"Resource": "*",
"Condition": {
"StringEqualsIgnoreCase": {
"kms:RecipientAttestation:PCR8": "{PCR8-VALUE}"
}
}
},
{
"Sid": "Allow GetKeyPolicy to co-signer",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{ACCOUNT-ID}:role/{ROLE-NAME}"
},
"Action": "kms:GetKeyPolicy",
"Resource": "*"
},
{
"Sid": "Allow policy management to root user",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{ACCOUNT-ID}:root"
},
"Action": [
"kms:DescribeKey",
"kms:GetKeyPolicy",
"kms:PutKeyPolicy",
"kms:CreateAlias"
],
"Resource": "*"
}
]
}
```
### Step 1.5: Edit the IAM role's policy
Return to the IAM service and select the IAM role you created.
1. In the Permissions policies section, select **Attach policies**, select the `AmazonSSMManagedInstanceCore` policy, and then select **Add permissions**.
2. In the Permissions policies section, select **Create inline policy** and choose **JSON** in the Policy editor section. Copy-paste the IAM policy below in there. Finally, create the policy and assign it a name.
Make sure you replace the `{BUCKET-NAME}`, `{KEY-REGION}`, `{ACCOUNT-ID}` and `{KEY-ID}` with the correct values.
```json theme={"system"}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListBuckets",
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::{BUCKET-NAME}"
},
{
"Sid": "WritePermissionsOnBucket",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::{BUCKET-NAME}/*"
},
{
"Sid": "AccessToTheKey",
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey",
"kms:GenerateDataKeyPair",
"kms:GenerateDataKeyWithoutPlaintext",
"kms:GenerateDataKeyPairWithoutPlaintext",
"kms:GenerateRandom",
"kms:GetKeyPolicy"
],
"Resource": [
"arn:aws:kms:{KEY-REGION}:{ACCOUNT-ID}:key/{KEY-ID}"
]
}
]
}
```
### Step 1.6: Set up and configure an EC2 instance
> **Use only the c5.xlarge or c5a.xlarge instance types!**
>
> AWS Nitro secure enclaves must have a minimum of two dedicated vCPUs and 4GB memory per enclave, and Nitro secure enclaves can utilize up to 50% of the host EC2 instance's resources. Therefore, the minimum requirement is to have an instance with four vCPUs and 8GB memory (`c5.xlarge`).
1. Create a Nitro-capable EC2 instance by selecting **Launch instances** from the EC2 Instances page. Enter its name and choose the Amazon Machine Image (AMI) **Amazon Linux 2023 AMI with 64-bit (x86) architecture**.
2. In the Instance type section, select `c5.xlarge` (4vCPUs, 8GB RAM) or `c5a.xlarge` if the former is not available in your region.
3. In the Network settings section, set where to allow SSH traffic from. We recommend restricting access as much as possible.
4. In the Advanced details section:
1. **IAM instance profile:** Select the IAM Role you created in the previous steps.
2. **Nitro Enclave:** Select **Enable**. This field will be grayed out if you selected an instance type that is incompatible with Nitro.
3. **Metadata version:** Select **V2 only (token required)**.
4. **Metadata response hop limit:** Set to a minimum of 2 (two).
When you’re done, launch the instance.
### Step 1.7: Additional security recommendations
* It is highly recommended to control user and network access to your AWS environment and EC2 instance by properly configuring your VPC and security groups. Learn more about [controlling network traffic](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/infrastructure-security.html#control-network-traffic) in the AWS documentation.
* See [API Co-signer security checklist and recommended defense and monitoring systems](/docs/co-signer-security-checklist-defense-monitoring) for further information.
***
## Step 2: Add a Co-signer to the workspace using an API user
[Use this guide](/reference/install-api-cosigner-add-new-cosigner-p2) to add a new Co-signer to the workspace. Be sure to copy-paste (or otherwise record) the following items to your notes since they are required during the installation process:
* The API user's pairing token
* The download link of the Co-signer's installation script
***
## Step 3: Install and connect the Co-signer to the workspace
> **You must have root privileges on the EC2 instance to install the Co-signer**
>
> Ensure you are logged in as a root user or use `sudo` to execute the installation commands.
### Step 3.1: Connect to your EC2 Instance
Connect to your EC2 instance with your preferred method.
### Step 3.2: Download and unpack the installation package
Using the download link of the AWS Nitro Co-signer installation package you copied from the Console, run the `wget` command to download the package directly to your machine.
Paste the appropriate URL into the following command:
```bash theme={"system"}
wget -O nitro-cosigner.tar.gz "URL"
```
Unpack the installation package by running the following command:
```bash theme={"system"}
tar -xzvf nitro-cosigner.tar.gz
```
### Step 3.3: Run the installation script
The installation package contains an Enclave Image File (EIF) and installation scripts. To install the Co-signer, navigate to the directory where the installation package was unpacked and run:
```bash theme={"system"}
./install.sh
```
You will be prompted to enter the following parameters:
* **Pairing token**: Enter the API user’s pairing token that you copied from the Fireblocks Console. This token pairs the API user with the Co-signer, establishing the connection between the Co-signer and the workspace.
* **S3 bucket name**: Enter the name of the S3 bucket that you created before. You should only add the bucket name and not the full ARN of the bucket. For example: If your bucket ARN is `arn:aws:s3:::{BUCKET-NAME}`, you need to enter only `{BUCKET-NAME}`.
* **CMK ARN:** Enter the Amazon Resource Name (ARN) of the CMK that you created before.
At this stage, you will have the option to configure the Callback Handler parameters for the API user connecting the Co-signer to the workspace. This feature is optional. You can [configure it later through the Console, APIs, or locally](/reference/api-cosigner-operate) from the Co-signer's host machine.
For detailed instructions on setting up your Callback Handler's interface to the Co-signer and implementing its logic and code, refer to the [Setup API Co-signer Callback Handler](/reference/api-cosigner-setup-callback-handler) section.
Once the installation is complete, the Co-signer will automatically start running.
> **The Nitro cosigner installation script installs the below components as services**
>
> * cosigner
> * cosigner-networking
> * cosigner-logging
> * cosigner-env-export
>
> The cosigner service is started up during the execution of the installation script, and is also enabled to start on boot, which in turn starts up the three remaining services.
### Step 3.4: Approve MPC key shares for the API user
If the API user paired with the Co-signer has an Admin or Signer role, the workspace Owner will receive a notification. This notification will prompt them to approve a new MPC key share request for that API user using the Fireblocks mobile app. The Owner must approve this request within 120 hours of receiving it.
You can now see the Co-signer you installed in the Co-signers tab within the Console's Developer Center. Observe that it is online and that the API user is paired to it.
> **Looking for the Co-signer's status and logs?**
>
> Refer to the [AWS Nitro Co-signer Maintenance](/reference/api-cosigner-maintenance-aws-nitro) guide for more information.
***
# Install SGX Azure API Co-signer
Source: https://developers.fireblocks.com/reference/install-api-cosigner-azure
## Overview
To install an SGX Co-signer in Microsoft Azure and connect it to your workspace, follow these steps:
1. **Setup and configure your Azure environment**
Prepare your Azure environment by creating and configuring the required resources. Ensure it meets the necessary specifications and security settings.
2. **Add a Co-signer to the workspace using an API user**
Using the Fireblocks Console or APIs, create an API user and use it to add a Co-signer to the workspace.
3. **Install and connect the Co-signer to the workspace**
Download the installation script to the SGX-capable virtual machine and run the script to install the Co-signer. Once installation is complete, the workspace owner approves the new MPC key shares for the API user through the Fireblocks mobile app.
You can now view the Co-signer and its paired API user in your Fireblocks Console. Additionally, you can retrieve information about them using the Co-signer APIs.
***
## Step 1: Setup and configure your Azure environment
### 1.1. Allowlist domains
To ensure the Co-signer can be installed and operated successfully, add the following domains to your allowlist:
| Domain | Owner |
| ------------------------------------------------- | -------------------------- |
| `mobile-api.fireblocks.io` | Fireblocks |
| `signurl.fireblocks.io` | Fireblocks |
| `s3signurl.fireblocks.io` | Fireblocks |
| `fb-certs.s3.amazonaws.com` | AWS |
| `fb-cosigner-images.s3.amazonaws.com` | AWS |
| `fb-customers.s3.amazonaws.com` | AWS |
| `fb-customers.s3.amazonaws.com/uploads` | AWS |
| `fireblocks-eu-prod-fr-cosigner.s3.amazonaws.com` | AWS |
| `download.docker.com` | Docker |
| `github.com` | GitHub |
| `cdn.registry.gitlab-static.net` | GitLab |
| `gitlab.com` | GitLab |
| `registry.gitlab.com` | GitLab |
| `download.01.org` | Intel SGX Driver |
| `bootstrap.pypa.io` | Python Software Foundation |
| `files.pythonhosted.org` | Python Software Foundation |
| `pypi.org` | Python Software Foundation |
| `pypi.python.org` | Python Software Foundation |
Fireblocks-owned domains differ based on the specific Fireblocks SaaS environment you are connected to. If you are connected to the European or Swiss SaaS, update your allowlist according to the domains listed in the table below:
| Fireblocks SaaS | Domains to Allow |
| --------------- | ------------------------------------------------------------------------------------------ |
| Global | `mobile-api.fireblocks.io` `signurl.fireblocks.io` `s3signurl.fireblocks.io` |
| Europe | `eu2-mobile-api.fireblocks.io` `eu2-signurl.fireblocks.io` `eu2-s3signurl.fireblocks.io` |
| Swiss | `eu-mobile-api.fireblocks.io` `eu-signurl.fireblocks.io` `eu-s3signurl.fireblocks.io` |
Additionally, ensure port access is configured for the following services:
| Port | Service URL |
| ---- | --------------------------------------------------------- |
| 443 | `https://mobile-api.fireblocks.io` |
| 443 | `https://s3signurl.fireblocks.io` |
| 443 | `https://fb-certs.s3.amazonaws.com` |
| 443 | `https://fb-customers.s3.amazonaws.com/uploads/` |
| 443 | `https://bootstrap.pypa.io/get-pip.py` |
| 443 | `https://download.docker.com/linux` |
| 443 | `https://download.01.org/intel-sgx/` |
| 443 | `https://fireblocks-eu-prod-fr-cosigner.s3.amazonaws.com` |
| 5000 | `https://registry.gitlab.com/customer-cosigner` |
### 1.2. Create an Intel SGX virtual machine
Follow this [Microsoft installation guide](https://learn.microsoft.com/en-us/azure/confidential-computing/quick-create-portal) and create an Intel SGX virtual machine through the Azure portal.
> **Note**: Only the *Configure an Intel SGX virtual machine* section is required. The necessary settings are listed below. You do not need to complete the Connect to the Linux VM or Next Steps sections
**The minimum requirements for the VM are:**
* RAM: 16GB
* Storage: 256GB
* OS:
* Ubuntu 22.04 LTS or 24.04 LTS (Canonical)
* Latest Linux kernel version
* Latest Intel microcode (BIOS update)
* Install packages apt-update over port 80: [http://azure.archive.ubuntu.com/ubuntu](http://azure.archive.ubuntu.com/ubuntu)
See the official [Microsoft documentation to find which products are available per region](https://azure.microsoft.com/en-us/explore/global-infrastructure/products-by-region/?products=virtual-machines\®ions=all).
Complete the following steps to create an SGX-capable VM in Azure:
1. Select Ubuntu 22.04 LTS or Ubuntu 24.04 LTS (Canonical) as the image, with the latest Intel microcode (BIOS update). The microcode is automatically updated on Azure.
2. Select your region.
3. Under the **Advanced** tab, select **Gen 2**.
4. Select Size. The recommended size is `Standard_DC4s_v3`.
> **Note**: `Standard_DC4s_v3` is not mandatory. `Standard_DC4s_v2` also works, but v3 allows for optimized performance that is not available out of the box with v2. Therefore, requesting a quota increase by opening a ticket with the Azure support team is required. Consult with the official Microsoft documentation for a list of SGX-supported instances.
5. Name your Co-signer VM and create it.
The final resource setup window should look like this:
### 1.3. Verify SGX is enabled on your VM
After creating your virtual machine, confirm that SGX is enabled. The SGX Co-signer requires a server with SGX enabled and the latest patches applied. This verification ensures smooth operation and avoids potential issues.
To verify that SGX is enabled on the VM, run the following commands with root privileges::
```bash theme={"system"}
apt update
apt upgrade
apt install cpuid
cpuid -1 | grep -i sgx
```
Verify the following:
1. `SGX`: Software Guard Extensions supported is **true**
2. `SGX_LC`: SGX launch config supported is **true**
> **Note**: Azure `Standard_DC4s_v2` instances do not support SGX2. However, SGX2 is not required to run the Co-signer.
### 1.4. Install the required software packages
* Install Docker
* Install Docker compose
* Install PIP
* If not already installed, download the SGX driver from:
`[https://download.01.org/intel-sgx/sgx-dcap/1.10.3/linux/distro/ubuntu20.04-server/](<>)`
### 1.5. Additional security recommendations
It is highly recommended to control user and network access to Co-signer's machine. See [API Co-signer security checklist and recommended defense and monitoring systems](/docs/co-signer-security-checklist-defense-monitoring) for further information.
***
## Step 2: Add a Co-signer to the workspace using an API user
Follow the instructions to [add a new Co-signer to the workspace](/reference/install-api-cosigner-add-new-cosigner-p2). Ensure you copy to your clipboard the following items, which you will use during the installation process:
* The API user's pairing token
* The download link of the Co-signer's installation script
***
## Step 3: Install and connect the Co-signer to the workspace
> **Note:** You must have root privileges on the Co-signer machine to install the Co-signer. Ensure you are logged in as a root user or use `sudo` to execute the commands.
### 3.1. Download the installation script
Using the download link of the SGX Co-signer installation script you copied from the Console, run the `curl` command to download the package directly to your machine.
Paste the appropriate URL into the following command:
```bash theme={"system"}
curl -o cosigner "URL"
```
### 3.2. Run the installation script
After downloading the installation script, navigate to the directory containing the script and modify the script's permissions to make it executable:
```bash theme={"system"}
chmod +x cosigner
```
To install the Co-signer, run:
```bash theme={"system"}
./cosigner setup
```
You will be prompted to enter the **Pairing token** for the API user, which you retrieve from the Fireblocks Console. This token pairs the API user with the Co-signer.
At this stage, you will have the option to configure the Callback Handler parameters for the API user connecting the Co-signer to the workspace. This feature is optional. You can [configure it later through the Console, APIs, or locally](/reference/api-cosigner-operate) from the Co-signer's host machine.
For detailed instructions on setting up your Callback Handler's interface to the Co-signer and implement its logic and code, refer to the [Setup API Co-signer Callback Handler](/reference/api-cosigner-setup-callback-handler) section.
The setup process validates the machine's hardware and installs the necessary drivers to support the appropriate SGX version and the SGX Co-signer's executable image. It includes an attestation flow to ensure that the SGX Co-signer's executable runs securely inside an Intel SGX enclave. Additionally, the script installs other required components.
Once installation is complete, to start the cosigner run: `./cosigner start`. At the end of the process, the Co-Signer generates a JSON configuration file, which can be used for future configuration updates.
### 3.3: Approve MPC key shares for the API user
If the API user used to pair with the Co-Signer and connect it to your workspace has an Admin or User role, the workspace owner will receive a notification. This notification will prompt them to approve a new MPC key share request for that API user using the Fireblocks mobile app.
You can now see the Co-signer you installed in the Co-signers tab within the Console's Developer Center. Observe it is online and that the API user is paired to it.
***
> **To check the Co-signer's status and observe the logs, see the SGX Co-signer Maintenance article.**
# Install SGX Azure Marketplace API Co-signer
Source: https://developers.fireblocks.com/reference/install-api-cosigner-azure-marketplace
The Fireblocks API Co-signer script is available as a managed and versioned component through [the Azure Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/fireblocksinc1626390946623.co-signer?tab=Overview). This solution automates the deployment process, eliminating the need to create an SGX-enabled VM and install the Co-signer.
To install an SGX Co-signer in Microsoft Azure and connect it to your workspace through the Azure Marketplace, complete the following steps.
## Step 1: Add a Co-signer to the workspace using an API user
Follow the instructions to [add a new Co-signer to the workspace](/reference/install-api-cosigner-add-new-cosigner-p2). Ensure you copy to your clipboard the following items, which you will use during the installation process:
* The API user's pairing token
* The download link of the Co-signer's installation script
## Step 2: Set up your Azure environment, install and connect the Co-signer to the workspace
### 2.1. Azure prerequisites
You must have a valid Azure Subscription with permissions to create Confidential Compute VMs, VNets, Resource Groups, and OS Disk at a minimum. Your subscription must also be registered for `Microsoft.Compute`, `Microsoft.Solutions` and `Microsoft.Network` service providers.
Your Azure subscription must have Quota limits enabled for `Standard_DC4s_v3` VM. If you are unsure, check with your Azure Administrator. You may have to submit a support ticket with Microsoft to increase the quota limits.
Also, your Azure subscription must have the following permissions:
* `Microsoft.Solutions/locations/operationStatuses/read`
* `Microsoft.Resources/deployments/write`
* `Microsoft.Network/virtualNetworks/write`
* `Microsoft.Network/networkInterfaces/write`
* `Microsoft.Compute/virtualMachines/write`
* `Microsoft.Compute/virtualMachines/extensions/write`
### 2.2. Using the marketplace automation
Complete the following steps to deploy a new SGX Co-signer using the Azure Marketplace.
#### Basics tab
* Under **Subscription**, select or enter your existing Azure subscription where you want to deploy this Co-signer.
* Under **Resource group**, select or create a group that properly organizes your resources within your subscription (i.e. geographic, commercial, sales affiliation, etc).
* Under **Region**, select the geographic region where you want your virtual machine to be deployed.
* Under **Virtual Machine**, select a name for your machine that is aligned with your best practices. Here you can also change the machine’s size, depending on your estimate of your projected transaction volume. We recommend DC4S as a minimum, but you may decide to change it based on your expected processing volume.
* Under **Username**, enter a username, and we will create one for you with an admin role, which is necessary for the creation of your API Co-signer and for logging into and fully managing your Azure’s virtual machine.
* Alternatively, if you are not interested in a username and password, you can upload a **Public key**. Once we receive it from you, we will use it to create a virtual machine for you, and you can use this key to log into the machine.
* If you decide to go with a username, enter and confirm a **Password** of your choice. The password must meet the specifications listed on the marketplace.
* Under **Managed application**, which is where we package all of your resources (the VM, Virtual network, storage), enter the name of your managed application (just as you entered the name of your Subscription above).
* Similarly, under **Managed resource group**, enter the name of your Managed resource group (just as you entered the name of your Resource group above).
* Select Next to move on to the next tab.
#### API Cosigner Settings tab
* Enter the API user's pairing token you copied from the Console
* Enter the download link of the SGX Co-signer's installation script you copied from the Console
At this stage, you will have the option to configure the Callback Handler parameters for the API user connecting the Co-signer to the workspace. This feature is optional. You can [configure it later through the Console, APIs, or locally](/reference/api-cosigner-operate) from the Co-signer's host machine.
For detailed instructions on setting up your Callback Handler's interface to the Co-signer and implementing its logic and code, refer to the [Setup API Co-signer Callback Handler](/reference/api-cosigner-setup-callback-handler) section.
#### Review + Create tab
In this tab, you can review all the information you provided in the previous sections and confirm it is accurate, or go back to modify whatever needs correction.
Select **Create**, and the Azure Marketplace solution will initiate the creation of the Azure SGX API Co-signer after a few minutes. If the deployment fails, you will see an error on the Azure Marketplace portal along with details on its root cause. Refer to the Troubleshooting section below for potential issues that could cause such a failure.
#### Co-signer script
The Azure Co-signer script is installed in the home folder of the admin user (e.g., `/home/yourname/`). You can [operate](/reference/api-cosigner-operate) and [maintain](/reference/api-cosigner-maintenance-sgx) the Co-signer using the Console or the script from the Azure VM, just as you would from the command line of an SGX machine you set up manually.
### 2.3: Approve MPC key shares for the API user
If the API user used to pair with the Co-Signer and connect it to your workspace has an Admin or User role, the workspace owner will receive a notification. This notification will prompt them to approve a new MPC key share request for that API user using the Fireblocks mobile app.
You can now see the Co-signer you installed in the Co-signers tab within the Console's Developer Center. Observe it is online and that the API user is paired to it.
## Troubleshooting
> **Co-signer Maintenance**
>
> To check the Co-signer's status and observe the logs, see the [SGX Co-signer Maintenance](/reference/api-cosigner-maintenance-sgx) article.
Since the solution is deployed on an Azure instance in your environment, a wide range of issues may occur depending on your configuration. Here are some common issues:
* Quota limits on your subscription may prevent the provisioning of `Standard_DC4s_v3 VM`. You may have to request an increase in quota limits or open a support ticket with Microsoft to increase the quota limits.
* Review the Azure deployment logs for any permissions-related errors. [Learn more about resolving these errors in the official Microsoft Azure documentation](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-register-resource-provider?tabs=azure-portal).
* Ensure your subscription has Microsoft.Compute, Microsoft.Solutions, and Microsoft.Network registered.
* Your subscription should also have permission to create resource groups.
* Your Azure subscription should have the permissions listed in the prerequisites section above.
* Check if your pairing token has expired. If it has, renew the token and try again.
* The API Co-signer script URL must be entered with opening and closing double quotes.
* If you modified the default VM, make sure you selected an SGX-enabled VM.
* Log a ticket with Fireblocks Support and attach the `*_run.log` files from the `/var/lib/waagent/custom-script/download/0` folder.
* You may need to delete the VM and any resources created during the deployment of the solution.
# Install Google Cloud Confidential Space API Co-signer
Source: https://developers.fireblocks.com/reference/install-api-cosigner-gcp
## Overview
To install a Confidential Space Co-signer in Google Cloud and connect it to your workspace, follow these steps:
1. **Setup and configure your Google Cloud environment**
Prepare your Google Cloud environment and the machine where you plan to install the Co-signer from (e.g., your laptop).
2. **Add a Co-signer to the workspace using an API user**
Using the Fireblocks Console or APIs, create an API user and use it to add a Co-signer to the workspace.
3. **Install and connect the Co-signer to the workspace**
Download the installation script to the machine where you plan to execute it, run the script to set up the necessary Google Cloud resources, and install the Co-signer. Once installation is complete, the workspace owner approves the new MPC key shares for the API user through the Fireblocks mobile app.
You can now view the Co-signer and its paired API user in your Fireblocks Console. Additionally, you can retrieve information about them using the Co-signer APIs.
## Step 1: Set up and configure your Google Cloud environment
Proper configuration of your Google Cloud environment is straightforward but must be performed step by step in the specified order. The installation script automates the resource creation and setup process and it is not recommended to change it. Any misconfiguration could compromise the Co-signer's functionality or security.
### 1.1. Allowlist Domains
To ensure the Co-signer can be installed and operated successfully, add the Fireblocks' domains to your allowlist. Fireblocks-owned domains differ based on the specific Fireblocks SaaS environment you are connected to. If you are connected to the European or Swiss SaaS, update your allowlist according to the domains in the table below.
| Fireblocks SaaS | Domains to Allow |
| --------------- | ---------------------------------------------------------------------------------- |
| Global | `mobile-api.fireblocks.iosignurl.fireblocks.ios3signurl.fireblocks.io` |
| Europe | `eu2-mobile-api.fireblocks.ioeu2-signurl.fireblocks.ioeu2-s3signurl.fireblocks.io` |
| Swiss | `eu-mobile-api.fireblocks.ioeu-signurl.fireblocks.ioeu-s3signurl.fireblocks.io` |
### 1.2. Install the required software packages
Ensure the following software packages are installed on the machine where you will run the installation script (e.g., your laptop):
* [**gcloud**](https://cloud.google.com/sdk/gcloud): The installation script automates the setup process by using gcloud and prompts you for the required inputs. It assumes you have the necessary credentials and permissions for your Google Cloud account. **gcloud sdk version of 396+ is required.**
* **uuidgen**: used for generating the Co-signer’s unique ID during installation.
* **jq**: used to create an output JSON configuration file.
The installation script uses those packages to create the resources and install the Co-signer.
### 1.3. Ensure account permissions for the required Google Cloud resources
You must have the necessary Google Cloud account permissions to enable network access to required domains and to create and configure the following resources:
* Project
* IAM Role
* Workload Identity Pool provider
* Customer Managed Key (CMK)
* Bucket
* Workload Container
### 1.4. Additional security recommendations
It is highly recommended to control user and network access to your Google Cloud environment. See [API Co-signer security checklist and recommended defense and monitoring systems](/docs/co-signer-security-checklist-defense-monitoring) for further information.
## Step 2: Add a Co-signer to the workspace using an API user
Follow the instructions to [add a new Co-signer to the workspace](/reference/install-api-cosigner-add-new-cosigner-p2). Ensure you copy to your clipboard the following items, which you will use during the installation process:
* The API user's pairing token
* The download link of the Co-signer's installation script
## Step 3: Install and connect the Co-signer to the workspace
### 3.1. Download and unpack the installation package
Using the download link of the GCP Co-signer installation package you copied from the Console, run the `wget` command to download the package directly to your machine.
Paste the appropriate URL into the following command:
`wget -O gcp-cosigner.zip "URL"`
Unpack the installation package by running the following command:
`tar -xzvf gcp-cosigner.zip`
### 3.2. Run the installation script
1. Log in to gcloud with `gcloud auth login`.
2. The installation package contains an installation script. To install the Co-signer, navigate to the directory where the installation package was unpacked and run `client_install_gcp_api_cosigner_script.sh` script in an interactive shell and respond to prompts as the script executes.
3. When prompted, select option **"1 - Create"** for first-time setup.
### 3.3. Approve MPC key shares for the API user
If the API user used to pair with the Co-Signer and connect it to your workspace has an Admin or User role, the workspace owner will receive a notification. This notification prompts them to approve a new MPC key share request for that API user in the Fireblocks mobile app.
You can now see the Co-signer you installed in the Co-signers tab within the Console's Developer Center. [Observe that it is online](/reference/api-cosigner-maintenance-gcp-confspace) and that the API user is paired to it.
## **Proxy configuration (optional)**
The Co-signer can route outbound traffic through an HTTPS proxy. When a proxy is configured, the Co-signer automatically switches from WebSocket to long-polling (REST), since WebSocket connections cannot reliably traverse proxies.
The script prompts you for a proxy URL during installation. If you don't need a proxy, press **Enter** to skip this step.
```text theme={"system"}
Please enter HTTPS proxy URL [can be empty; e.g. http://proxy:8080 or http://user:pass@proxy:8080]:
```
To authenticate to the proxy, include the credentials directly in the URL:
```http theme={"system"}
http://username:password@proxy.example.com:8080
```
The proxy URL — including any credentials — is encrypted immediately using your Cloud KMS key and is never stored in plaintext. Only the encrypted value is written to the `cloud-resources-*.yaml` file.
If you provide a proxy URL, the script also prompts for `NO_PROXY` patterns: a comma-separated list of hosts that should bypass the proxy. The recommended defaults are:
```text theme={"system"}
169.254.169.254,metadata.google.internal,googleapis.com
```
These cover the GCP metadata server and Google APIs, which must remain reachable directly.
**For non-interactive installs**, set these fields in your `install-config.yaml`:
```yaml theme={"system"}
# Optional proxy fields
proxy_url: http://username:password@proxy.example.com:8080
no_proxy: 169.254.169.254,metadata.google.internal,googleapis.com
```
# Install SGX IBM Cloud API Co-signer
Source: https://developers.fireblocks.com/reference/install-api-cosigner-ibm
## Overview
To install an SGX Co-signer in IBM Cloud and connect it to your workspace, follow these steps:
1. **Setup and configure your IBM Cloud environment**
Prepare your IBM Cloud environment by creating and configuring the required resources. Ensure it meets the necessary specifications and security settings.
2. **Add a Co-signer to the workspace using an API user**
Using the Fireblocks Console or APIs, create an API user and use it to add a Co-signer to the workspace.
3. **Install and connect the Co-signer to the workspace**
Download the installation script to the SGX-capable virtual machine and run the script to install the Co-signer. Once installation is complete, the workspace owner approves the new MPC key shares for the API user through the Fireblocks mobile app.
You can now view the Co-signer and its paired API user in your Fireblocks Console. Additionally, you can retrieve information about them using the Co-signer APIs.
***
## Step 1: Setup and configure your IBM Cloud environment
### 1.1. Allowlist domains
To ensure the Co-signer can be installed and operated successfully, add the following domains to your allowlist:
| Domain | Owner |
| --------------------------------------- | -------------------------- |
| `mobile-api.fireblocks.io` | Fireblocks |
| `signurl.fireblocks.io` | Fireblocks |
| `s3signurl.fireblocks.io` | Fireblocks |
| `fb-certs.s3.amazonaws.com` | AWS |
| `fb-cosigner-images.s3.amazonaws.com` | AWS |
| `fb-customers.s3.amazonaws.com` | AWS |
| `fb-customers.s3.amazonaws.com/uploads` | AWS |
| `download.docker.com` | Docker |
| `registry.gitlab.com` | GitLab |
| `cdn.registry.gitlab-static.net` | GitLab |
| `gitlab.com` | GitLab |
| `github.com` | GitHub |
| `download.01.org` | Intel SGX Driver |
| `bootstrap.pypa.io` | Python Software Foundation |
| `files.pythonhosted.org` | Python Software Foundation |
| `pypi.org` | Python Software Foundation |
| `pypi.python.org` | Python Software Foundation |
Fireblocks-owned domains differ based on the specific Fireblocks SaaS environment you are connected to. If you are connected to the European or Swiss SaaS, update your allowlist according to the domains listed in the table below:
| Fireblocks SaaS | Domains to Allow |
| --------------- | ------------------------------------------------------------------------------------------ |
| Global | `mobile-api.fireblocks.io` `signurl.fireblocks.io` `s3signurl.fireblocks.io` |
| Europe | `eu2-mobile-api.fireblocks.io` `eu2-signurl.fireblocks.io` `eu2-s3signurl.fireblocks.io` |
| Swiss | `eu-mobile-api.fireblocks.io` `eu-signurl.fireblocks.io` `eu-s3signurl.fireblocks.io` |
Additionally, ensure port access is configured for the following services:
| Port | Service URL |
| ---- | ------------------------------------------------ |
| 443 | `https://mobile-api.fireblocks.io` |
| 443 | `https://s3signurl.fireblocks.io` |
| 443 | `https://fb-certs.s3.amazonaws.com` |
| 443 | `https://fb-customers.s3.amazonaws.com/uploads/` |
| 443 | `https://bootstrap.pypa.io/get-pip.py` |
| 443 | `https://download.docker.com/linux` |
| 443 | `https://download.01.org/intel-sgx/` |
| 5000 | `https://registry.gitlab.com/customer-cosigner` |
### 1.2. Create an SGX virtual machine
**The minimum hardware requirements for the VM are:**
* RAM: 32GB
* Storage: 256GB
* OS:
* Ubuntu 20.04
* Latest Linux kernel version
* Latest Intel microcode (BIOS update)
Complete the following steps to create an SGX-capable VM in IBM Cloud:
1. On the Dashboard page, select **Create Resource**.
2. Go to **IBM Cloud catalog** > **Compute** > **Bare Metal Servers**.
3. In the Server Profile section, select **View all profiles**.
4. Select **Intel Xeon E-2174G CPU**.
5. In the Operating System section, select the following options:
1. Vendor: Ubuntu
2. Version: 18.04 LTS (64-bit)
3. RAM (recommended): 32 GB
6. Select the **Software Guard Extensions** toggle under Add-ons > **Security and Business Continuity**.
7. Lastly, create the VM.
### 1.3. Verify SGX is enabled on your VM
After creating your virtual machine, confirm that SGX is enabled. The SGX Co-signer requires a server with SGX enabled and the latest patches applied. This verification ensures smooth operation and avoids potential issues.
To verify that SGX is enabled on the VM, run the following commands with root privileges::
```bash theme={"system"}
apt update
apt upgrade
apt install cpuid
cpuid -1 | grep -i sgx
```
Verify the following:
1. `SGX`: Software Guard Extensions supported is **true**
2. `SGX_LC`: SGX launch config supported is **true**
### 1.4. Additional security recommendations
It is highly recommended to control user and network access to Co-signer's machine. See [API Co-signer security checklist and recommended defense and monitoring systems](/docs/co-signer-security-checklist-defense-monitoring) for further information.
***
## Step 2: Add a Co-signer to the workspace using an API user
Follow the instructions to [add a new Co-signer to the workspace](/reference/install-api-cosigner-add-new-cosigner-p2). Ensure you copy to your clipboard the following items, which you will use during the installation process:
* The API user's pairing token
* The download link of the Co-signer's installation script
***
## Step 3: Install and connect the Co-signer to the workspace
> **Note:** You must have root privileges on the Co-signer machine to install the Co-signer. Ensure you are logged in as a root user or use `sudo` to execute the commands.
### 3.1. Download the installation script
Using the download link of the SGX Co-signer installation script you copied from the Console, run the `curl` command to download the package directly to your machine.
Paste the appropriate URL into the following command:
```bash theme={"system"}
curl -o cosigner "URL"
```
### 3.2. Run the installation script
After downloading the installation script, navigate to the directory containing the script and modify the script's permissions to make it executable:
```bash theme={"system"}
chmod +x cosigner
```
To install the Co-signer, run:
```bash theme={"system"}
./cosigner setup
```
You will be prompted to enter the **Pairing token** for the API user, which you retrieve from the Fireblocks Console. This token pairs the API user with the Co-signer.
At this stage, you will have the option to configure the Callback Handler parameters for the API user connecting the Co-signer to the workspace. This feature is optional. You can [configure it later through the Console, APIs, or locally](/reference/api-cosigner-operate) from the Co-signer's host machine.
For detailed instructions on setting up your Callback Handler's interface to the Co-signer and implement its logic and code, refer to the [Setup API Co-signer Callback Handler](/reference/api-cosigner-setup-callback-handler) section.
The setup process validates the machine's hardware and installs the necessary drivers to support the appropriate SGX version and the SGX Co-signer's executable image. It includes an attestation flow to ensure that the SGX Co-signer's executable runs securely inside an Intel SGX enclave. Additionally, the script installs other required components.
Once the installation is complete, the Co-signer will automatically start running. At the end of the process, the Co-Signer generates a JSON configuration file, which can be used for future configuration updates.
### 3.3: Approve MPC key shares for the API user
If the API user used to pair with the Co-Signer and connect it to your workspace has an Admin or User role, the workspace owner will receive a notification. This notification will prompt them to approve a new MPC key share request for that API user using the Fireblocks mobile app.
You can now see the Co-signer you installed in the Co-signers tab within the Console's Developer Center. Observe it is online and that the API user is paired to it.
***
> **To check the Co-signer's status and observe the logs, see the SGX Co-signer Maintenance article.**
# Install SGX On-prem API Co-signer
Source: https://developers.fireblocks.com/reference/install-api-cosigner-onprem
## Overview
To install an SGX Co-signer on-premises and connect it to your workspace, follow these steps:
1. **Setup and configure your on-prem environment:** Prepare your on-prem environment by creating and configuring the required resources. Ensure it meets the necessary specifications and security settings.
2. **Add a Co-signer to the workspace using an API user:** Using the Fireblocks Console or APIs, create an API user and use it to add a Co-signer to the workspace.
3. **Install and connect the Co-signer to the workspace:** Download the installation script to the SGX-capable machine, then run it to install the Co-signer. Once installation is complete, the workspace owner approves the new MPC key shares for the API user through the Fireblocks mobile app.
You can now view the Co-signer and its paired API user in your Fireblocks Console. Additionally, you can retrieve information about them using the Co-signer APIs.
## Step 1: Set up and configure your on-prem environment and SGX server
### Step 1.1: Allowlist domains
To ensure the Co-signer can be installed and operated successfully, add the following domains to your allowlist:
| Domain | Owner |
| --------------------------------------- | -------------------------- |
| `mobile-api.fireblocks.io` | Fireblocks |
| `signurl.fireblocks.io` | Fireblocks |
| `s3signurl.fireblocks.io` | Fireblocks |
| `fb-certs.s3.amazonaws.com` | AWS |
| `fb-cosigner-images.s3.amazonaws.com` | AWS |
| `fb-customers.s3.amazonaws.com` | AWS |
| `fb-customers.s3.amazonaws.com/uploads` | AWS |
| `download.docker.com` | Docker |
| `github.com` | GitHub |
| `cdn.registry.gitlab-static.net` | GitLab |
| `gitlab.com` | GitLab |
| `registry.gitlab.com` | GitLab |
| `download.01.org` | Intel SGX Driver |
| `bootstrap.pypa.io` | Python Software Foundation |
| `files.pythonhosted.org` | Python Software Foundation |
| `pypi.org` | Python Software Foundation |
| `pypi.python.org` | Python Software Foundation |
Fireblocks-owned domains differ based on the specific Fireblocks SaaS environment you are connected to. If you are connected to the European or Swiss SaaS, update your allowlist according to the domains listed in the table below:
| Fireblocks SaaS | Domains to Allow |
| --------------- | ---------------------------------------------------------------------------------------- |
| Global | `mobile-api.fireblocks.io` `signurl.fireblocks.io` `s3signurl.fireblocks.io` |
| Europe | `eu2-mobile-api.fireblocks.io` `eu2-signurl.fireblocks.io` `eu2-s3signurl.fireblocks.io` |
| Swiss | `eu-mobile-api.fireblocks.io` `eu-signurl.fireblocks.io` `eu-s3signurl.fireblocks.io` |
Additionally, ensure port access is configured for the following services:
| Port | Service URL |
| ---- | ------------------------------------------------ |
| 443 | `https://mobile-api.fireblocks.io` |
| 443 | `https://s3signurl.fireblocks.io` |
| 443 | `https://fb-certs.s3.amazonaws.com` |
| 443 | `https://fb-customers.s3.amazonaws.com/uploads/` |
| 443 | `https://bootstrap.pypa.io/get-pip.py` |
| 443 | `https://download.docker.com/linux` |
| 443 | `https://download.01.org/intel-sgx/` |
| 5000 | `https://registry.gitlab.com/customer-cosigner` |
### Step 1.2: Set up and configure an on-prem SGX server
Your on-prem SGX server should meet the following hardware requirements:
* **CPU processor:** Only one of the following [Intel® processors](https://www.intel.com/content/www/us/en/architecture-and-technology/software-guard-extensions-processors.html)
* **CPU cores:** Minimum 4
* **OS:** Ubuntu 22.04 LTS or 24.04 LTS (Canonical) with -
* Latest Linux kernel version
* Latest Intel microcode (BIOS update)
* **RAM:** Minimum 16GB
* **Storage:** Minimum 128GB
* **SGX Memory:** Minimum 2GB EPC
> **Fireblocks also supports on-prem SGX servers installed on OVHcloud providers.**
Additionally, configure your on-prem SGX server BIOS to match the following setup:
* Enable Intel SGX (Software Guard Extension)
* Enable DCAP (FLC)
* Disable hyper threading
* Disable Intel SpeedStep Technology
* Disable Onboard VGA
### Step 1.3: Verify SGX is enabled on your SGX server
After setting up your on-prem SGX server, confirm that SGX is enabled. The SGX Co-signer requires a server with SGX enabled and the latest patches applied. This verification ensures smooth operation and avoids potential issues.
To verify that SGX is enabled on the VM, run the following commands with root privileges:
```bash theme={"system"}
apt update
apt upgrade
apt install cpuid
cpuid -1 | grep -i sgx
```
Verify the following:
1. `SGX`: Software Guard Extensions supported is **true**
2. `SGX_LC`: SGX launch config supported is **true**
### Step 1.4: Install the SGX drivers
1. [Subscribe to the Intel PCS for ECDSA Attestation and to obtain the required API keys](https://api.portal.trustedservices.intel.com/provisioning-certification).
2. Set up Intel's reference caching service, the Provisioning Certification Caching Service (PCCS):
1. **Redhat/Debian:** [Installation Guide, page 39](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_SW_Installation_Guide_for_Linux.pdf?#page=39)
2. **Another Debian approach:** Follow the steps in the document above (intel-dcap.pdf), but skip the *Verify the empty cache* step.
3. **Cache Fill Mode:** [Intel SGX DCAP Caching Service Design Guide, page 38](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/SGX_DCAP_Caching_Service_Design_Guide.pdf#page=38)
3. Provision the Intel SGX-enabled platform for Intel SGX workloads. The goal is to run PCKIDRetrievalTool. *Make sure pckid\_retrieval.csv is created.* This file will be used to register the CPU data with Intel. Without this registration, the remote attestation will fail.
1. **Debian resources:** [Intel SGX DCAP Quick Install Guide, page 4](https://drive.google.com/file/d/1lZWM4_dTSdOID9PdKGFDenkyi4DA9OR8/view)
2. **Redhat resources:** Download the binary file from one of these locations:
1. [https://download.01.org/intel-sgx/sgx-dcap/1.18/linux/distro/rhel8.6-server/](https://download.01.org/intel-sgx/sgx-dcap/1.18/linux/distro/rhel8.6-server/)
2. [https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/main/tools/PCKRetrievalTool](https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/main/tools/PCKRetrievalTool)
4. Convert the pckid\_retrieval.csv file to JSON format using this Python script and submit it to Intel for registration. You can view a sample JSON [here](https://drive.google.com/file/d/1x9NCvFHYMR8-MaauEWspZZAsZjU6qjdS/view).
```python theme={"system"}
import json
import sys
if len(sys.argv) != 2 and len(sys.argv) != 3:
print("usage: pckid2json ")
exit(0)
f = open(sys.argv[1], 'r')
data = f.read().split(',')
f.close()
if len(data) == 5:
print("WARNING: platform metadata is missing from pckid file")
elif len(data) != 6:
print("ERROR: pckid file has invalid format")
exit(-1)
obj = {}
obj['enc_ppid'] = data[0]
obj['pce_id'] = data[1]
obj['cpu_svn'] = data[2]
obj['pce_svn'] = data[3]
obj['qe_id'] = data[4]
if len(data) == 6:
obj['platform_manifest'] = data[5]
if len(sys.argv) == 3:
f = open(sys.argv[2], 'w')
json.dump(obj, f)
f.close()
else:
print(json.dumps(obj))
```
1. For more information about the registration process, visit the following references:
1. [Design Guide for Intel SGX PCCS, page 20](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/SGX_DCAP_Caching_Service_Design_Guide.pdf#page=20\&zoom=100,92,200)
2. [Get PCK Certificates, V4](https://api.portal.trustedservices.intel.com/content/documentation.html#pcs-certificates-v4)
5. When prompted to verify the provisioning data, skip this step.
6. Reimage the Intel SGX-enabled platform.
7. Load the Intel SGX runtime stack onto the reimaged system:
1. **Debian:** Refer to the [Intel SGX DCAP Quick Install Guide, page 5](https://drive.google.com/file/d/1lZWM4_dTSdOID9PdKGFDenkyi4DA9OR8/view). Note that steps 5 and 6 are bulked up in the "Runtime configuration" section.
2. **Redhat:** Refer to the [Intel Confidential Computing Documentation](https://cc-enabling.trustedservices.intel.com/intel-sgx-sw-installation-guide-linux/01/introduction/).
### Step 1.5: Registration with Intel
1. Follow the registration instructions located [here](https://api.portal.trustedservices.intel.com/content/documentation.html#pcs-tcb-info-v4). Note that you'll need the JSON format of the pckid\_retrieval.csv file for this step.
2. Verify that your CSV is registered with Intel via Fireblocks:
```bash theme={"system"}
curl -L
"https://mobile-api.fireblocks.io/sgx/certification/v3/pckcert?qeid=FC88E54A32E9BE6455A01CE78A55B85C&encrypted_ppid=635DBA646F13077DC75291B12ABE96D4D69A956D7FF5524D8090290EEB8ACC6450F72CD7539D1578E636911321D96E0CEC15E04FACBC7652DE1775F76DF460D472A7F5C8118B22C37F4590789F46161D99F2758D120C5BD4CD8FD302C444F56E620A98DFAFD156887B73DAEEB04EA6C9007C2EEB9B00DF49FBBD4B9535B8DB61445A28F73CADDADB36B27E35DACE6A4287621D2FF6E01B31C579FC9D73512B631558427370020DAB10DF315D740400ED73D64AACBFC76A0B88975A52086CD656809A58821A9B8516A4571BF33CBA042B76EC4409745635ADF2DE5F62FA8C0F6E4970712209F3D2EF83E5850646105B841F1905CB3E7F5AE21BF8759250C9981F8DEA229265CC619D9990842AC71739BCF155FCBA6AD262EDF04AA8A9E668E2F87A3FA822E7F6F330CA955C9B6244E5C35BFA71DA08655C1244156E598F97B97BAF1DF6CF79B624E5129AF190A24930436BDCC2371BEA322EEF2D733769372D5F763763B937BF680D4245441F234623051FAFCF0DA8FA79D744E3F261FD352275&cpusvn=0C0C0F0EFFFF01000000000000000000&pcesvn=0C00&pceid=0000"
```
3. A certificate will appear in the response if the registration was successful:
```yaml theme={"system"}
-----BEGIN CERTIFICATE-----
MIIE8jCCBJigAwIBAgIUUWcKdCIgJwOmz/lT0UrRd9zVUU8wCgYIKoZIzj0EAwIw
cDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBDSyBQbGF0Zm9ybSBDQTEaMBgGA1UECgwR
SW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQI
DAJDQTELMAkGA1UEBhMCVVMwHhcNMjQxMjAzMDg1MzA2WhcNMzExMjAzMDg1MzA2
…….
…….
…….
-----END CERTIFICATE-----
```
## Step 2: Add a Co-signer to the workspace using an API user
Follow the instructions to [add a new Co-signer to the workspace](/reference/install-api-cosigner-add-new-cosigner-p2). Ensure you copy to your clipboard the following items, which you will use during the installation process:
* The API user's pairing token
* The download link of the Co-signer's installation script
## Step 3: Install and connect the Co-signer to the workspace
> **You must have root privileges on the Co-signer server to install the Co-signer**
>
> Ensure you are logged in as a root user or use `sudo` to execute the commands.
### Step 3.1: Download the installation script
Using the download link of the SGX Co-signer installation script you copied from the Console, run the `curl` command to download the package directly to your machine.
Paste the appropriate URL into the following command:
```bash theme={"system"}
curl -o cosigner "URL"
```
### Step 3.2: Run the installation script
After downloading the installation script, navigate to the directory containing the script and modify the script's permissions to make it executable:
```bash theme={"system"}
chmod +x cosigner
```
To install the Co-signer, run:
```bash theme={"system"}
./cosigner setup
```
You will be prompted to enter the **Pairing token** for the API user, which you retrieve from the Fireblocks Console. This token pairs the API user with the Co-signer.
At this stage, you will have the option to configure the Callback Handler parameters for the API user connecting the Co-signer to the workspace. This feature is optional. You can [configure it later through the Console, APIs, or locally](/reference/api-cosigner-operate) from the Co-signer's host machine.
For detailed instructions on setting up your Callback Handler's interface to the Co-signer and implementing its logic and code, refer to the [Setup API Co-signer Callback Handler](/reference/api-cosigner-setup-callback-handler) section.
The setup process validates the machine's hardware and installs the necessary drivers to support the appropriate SGX version and the SGX Co-signer's executable image. It includes an attestation flow to ensure that the SGX Co-signer's executable runs securely inside an Intel SGX enclave. Additionally, the script installs other required components.
Once the installation is complete, the Co-signer will automatically start running. At the end of the process, the Co-Signer generates a JSON configuration file, which can be used for future configuration updates.
### Step 3.3: Approve MPC key shares for the API user
If the API user used to pair with the Co-Signer and connect it to your workspace has an Admin or User role, the workspace owner will receive a notification. This notification prompts them to approve a new MPC key share request for that API user in the Fireblocks mobile app.
You can now see the Co-signer you installed in the Co-signers tab within the Console's Developer Center. Observe it is online and that the API user is paired to it.
> **To check the Co-signer's status and observe the logs, see the SGX Co-signer Maintenance article.**
# Interact with Solana Programs
Source: https://developers.fireblocks.com/reference/interact-with-solana-programs
> **Solana Program Calls require hot wallets**
>
> Solana Program Calls require a hot wallet and cannot be used in cold workspaces.
# Overview of Solana transactions & programs
Solana programs are on-chain executable codes that power the decentralized applications (dApps) and other functionalities within the Solana blockchain. They enable smart contract-like behavior, allowing developers to write logic that processes transactions and manages state.
## Solana transactions
A Solana transaction is a set of instructions bundled together to be executed automatically on the blockchain. It typically consists of the following components:
1. **Signatures:** A list of cryptographic signatures to authorize the transaction.
2. **Message:** The core of the transaction, which includes:
1. **Instructions:** The set of actions to be performed. Each instruction targets a specific program on the blockchain, includes accounts to be accessed or modified, and contains any necessary data for the operation.
2. **Account Keys:** A list of all accounts involved in the transaction.
3. **Recent Blockhash:** A reference to a recent block to ensure the transaction is processed promptly and prevent replay attacks.
When a transaction is submitted, it is signed by the relevant parties and serialized before being broadcast to the network.
Fireblocks simplifies interacting with Solana programs by allowing you to use the [createTransaction](/reference/createtransaction) endpoint. This endpoint supports Solana program calls through the `PROGRAM_CALL` operation, ensuring secure transaction signing and execution.
> **SetAuthority instruction not allowed**
>
> Fireblocks' policy does not allow using the `SetAuthority` instruction, as it may expose users to malicious activity.
***
# Policy configuration
Solana Program Calls can be executed in Fireblocks without whitelisting any addresses if the One-Time Address feature is enabled. In this scenario, the Policy rule should include a condition for the `Program Call` operation, with the destination set to `Any`.
For clients who prefer to work with whitelisted addresses due to security concerns and Fireblocks' best practices, the Policy rule should be configured with the destination type set to `Whitelisted only` for any `Program Call` operation. In this case, the client must whitelist the following addresses involved in the Solana Program Call transaction:
1. **Any non-prewhitelisted program:** Fireblocks internally whitelists certain built-in Solana programs, including:
* [System Program](https://docs.anza.xyz/runtime/programs#system-program)
* [Compute Budget Program](https://github.com/solana-program/compute-budget)
Additionally, the following [Sysvar Cluster Data](https://docs.anza.xyz/runtime/sysvars) accounts are pre-whitelisted:
* [Recent Block Hashes](https://docs.anza.xyz/runtime/sysvars#recentblockhashes)
* [Rental Rate](https://docs.anza.xyz/runtime/sysvars#rent)
Any other program must be explicitly whitelisted as an **External Wallet/Contract** in Fireblocks.
2. **Any account designated as a destination:** For the [Transfer instructions](https://solana.com/docs/core/transactions#instruction) (if applicable) within the `Program Call` transaction.
***
# Practical example
When performing a SOL to USDC swap on **Jupiter**, the following list of programs participates in the transaction:
In the example above, **Programs 1, 2, and 4 (Green)** are automatically whitelisted. However, in this scenario, the customer must manually whitelist the following programs (Red):
1. **Associated Token Program**
2. **Token Program**
3. **Program #6**, which is a custom **Jupiter program**
> **Looking for a program's address?**
>
> You can expand a specific program's section to view its address (the `programId` value).
Additionally, expanding the **System Program** section reveals that this program includes a single instruction: `Transfer`. Expanding the `Transfer` instruction shows that, as expected, two accounts are involved:
* **`from`account** (index 1)
* **`to`account** (index 2)
To ensure the `Program Call` operation functions correctly, the `pubkey`value of the`to` address must be whitelisted.
> **Warning: For demonstrative purposes only**
>
> The addresses shown above are for demonstrative purposes only! Customers should always review and determine which addresses need to be whitelisted based on the specific Program Call context relevant to their use case.
***
# How do program calls work on Fireblocks?
To make a Solana program call using the Fireblocks API, you will:
1. **Build the Solana Transaction:** Use the Solana `web3.js` library or other tools to construct the unsigned transaction. Ensure the transaction includes all necessary instructions and accounts.
**Note:** Fireblocks supports legacy and versioned v0 Solana transaction payloads only. Transactions built with any other message version are not supported and will fail with INTERNAL\_ERROR.
2. **Serialize and Encode:** Serialize the unsigned transaction object and encode it in Base64 format.
3. **Call Fireblocks API:**
1. Use the Create Transaction endpoint.
2. Set the operation parameter to `PROGRAM_CALL`.
3. Pass the serialized, Base64 encoded transaction object in the `programCallData` parameter within the `extraParams` object.
Fireblocks securely signs the transaction using your organization’s private key, ensuring seamless execution without exposing sensitive cryptographic materials.
## Example transaction structure
Below is a sample payload for invoking a Solana program using the [Create Transaction API](/reference/createtransaction) :
```json theme={"system"}
{
"operation": "PROGRAM_CALL",
"assetId": "SOL",
"source": {
"type": "VAULT_ACCOUNT",
"id": ""
},
"extraParameters": {
"programCallData": ""
}
}
```
#### Parameters
1. **operation:** Must be `PROGRAM_CALL` for Solana program calls.
2. **assetId:** Use SOL for Solana mainnet transactions, SOL\_TEST for devnet.
3. **source:** The vault account ID that holds the funds and signs the transaction.
4. **extraParams.programCallData:** The unsigned, serialized transaction object (Base64 encoded).
5. **extraParams.useDurableNonce:** (Optional; boolean) The configurable durable nonce. The default is `true`.
6. **extraParams.signOnly:** (Optional; boolean) Set to `true` to sign the transaction without submitting it to the blockchain. The default is `false`.
> **Durable nonce & Sign-only mode usage**
>
> #### Durable nonce usage
>
> By default, Fireblocks includes a [durable nonce](https://solana.com/developers/courses/offline-transactions/durable-nonces) in your transaction by adding an `AdvanceNonce` instruction. This ensures the transaction remains valid even if it's not immediately submitted.
>
> Set **useDurableNonce** to `false` to use the recent blockhash instead. This reduces transaction size, which may be necessary to stay within Solana's maximum transaction size limit.
>
> **useDurableNonce** is only used with Solana Program Calls. Other transactions do not use this field and will ignore its value.
>
> #### Sign-only mode usage
>
> Use sign-only mode when you want to sign a transaction but submit it to the blockchain through another method or service.
>
> After you sign a transaction, it normally moves from `PENDING_SIGNATURE` to `BROADCASTING` as Fireblocks submits it to the blockchain. When you enable sign-only mode, the transaction moves from `PENDING_SIGNATURE` to `SIGNED` instead. Fireblocks doesn't submit the transaction, but updates its status to `COMPLETED` if the blockchain includes it in a new block.
>
> **signOnly** is only used with Solana Program Calls. Other transactions do not use this field and will ignore its value.
# Fireblocks Solana Web3 Connection Adapter
[The Fireblocks Solana Web3 Connection Adapter](/reference/solana-web3-adapter) serves as a bridge between the Fireblocks API and the Solana blockchain, streamlining transaction submissions via Fireblocks when using Solana's official `web3.js` library.
# Internal, External & Contract Wallet Webhooks
Source: https://developers.fireblocks.com/reference/internal-external-contract-wallet-webhooks
> **Deprecation notice**
>
> Webhooks v1 will be deprecated on **June 15th, 2026**. Please use the Developer Center in the Fireblocks Console to upgrade to Webhooks V2, which offers improved reliability, performance, and observability.
This page describes all events relating to internal, external, and contract whitelisted wallets that produce webhook notifications, and their associated data objects.
The `type` parameter is automatically set to the description name for the data objects below.
***
## Asset added to internal wallet
Notification is sent when an asset is added to an internal wallet.
| Parameter | Type | Description |
| --------- | ----------------------------------------- | -------------------------------------- |
| type | string | INTERNAL\_WALLET\_ASSET\_ADDED |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | [WalletAssetWebhook](#walletassetwebhook) | Internal wallet details |
## Asset removed from internal wallet
Notification is sent when an asset is removed from an internal wallet.
| Parameter | Type | Description |
| --------- | ----------------------------------------- | -------------------------------------- |
| type | string | INTERNAL\_WALLET\_ASSET\_REMOVED |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | [WalletAssetWebhook](#walletassetwebhook) | Internal wallet details |
## Asset added to external wallet
Notification is sent when an asset is added to an external wallet.
| Parameter | Type | Description |
| --------- | ----------------------------------------- | -------------------------------------- |
| type | string | EXTERNAL\_WALLET\_ASSET\_ADDED |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | [WalletAssetWebhook](#walletassetwebhook) | External wallet details |
## Asset removed from external wallet
Notification is sent when an asset is removed from an external wallet.
| Parameter | Type | Description |
| --------- | ----------------------------------------- | -------------------------------------- |
| type | string | EXTERNAL\_WALLET\_ASSET\_REMOVED |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | [WalletAssetWebhook](#walletassetwebhook) | External wallet details |
## Asset added to contract wallet
Notification is sent when an asset is added to a contract wallet.
| Parameter | Type | Description |
| --------- | ----------------------------------------- | -------------------------------------- |
| type | string | CONTRACT\_WALLET\_ASSET\_ADDED |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | [WalletAssetWebhook](#walletassetwebhook) | Contract wallet details |
## Asset removed from contract wallet
Notification is sent when an asset is removed from a contract wallet.
| Parameter | Type | Description |
| --------- | ----------------------------------------- | -------------------------------------- |
| type | string | CONTRACT\_WALLET\_ASSET\_REMOVED |
| tenantId | string | Unique ID of your Fireblocks workspace |
| timestamp | number | Timestamp in milliseconds |
| data | [WalletAssetWebhook](#walletassetwebhook) | Contract wallet details |
***
### WalletAssetWebhook
| Parameter | Type | Description |
| -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| assetId | string | The wallet's asset |
| walletId | string | The ID of the wallet |
| walletName | string | The name of the wallet |
| address | string | The address of the wallet |
| tag | string | Destination address tag for Ripple; destination memo for Cosmos, EOS, Luna, Luna Classic, NEM, Stellar, Hedera, & DigitalBits; destination note for Algorand; bank transfer description for fiat providers. |
| activationTime | number | The time the wallet will be activated, if wallet activation is postponed according to your workspace definition |
# Internal/External Wallet Objects
Source: https://developers.fireblocks.com/reference/internalexternal-wallet-objects
## WalletAsset
| Parameter | Type | Description |
| -------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| id | string | The ID of the asset |
| balance | string | The balance of the wallet |
| lockedAmount | string | Locked amount in the wallet |
| status | [ConfigChangeRequestStatus](/reference/general-objects#configchangerequeststatus) | Status of the Internal Wallet |
| activationTime | string | The time the wallet will be activated if wallet activation is postponed according to the workspace definition |
| address | string | The address of the wallet |
| tag | string | Used as destination tag for XRP; `memo` for ATOM, EOS, HBAR, LUNA, LUNC, XDB, XEM; `memo_text` for XLM; `notes` for ALGO. |
***
## ExternalWalletAsset
| Parameter | Type | Description |
| -------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | string | The ID of the asset |
| status | [ConfigChangeRequestStatus](/reference/general-objects#configchangerequeststatus) | Status of the External Wallet |
| activationTime | string | The time the wallet will be activated if wallet activation is postponed according to the workspace definition |
| address | string | The address of the wallet |
| tag | string | Used as destination tag for XRP; `memo` for ATOM, EOS, HBAR, LUNA, LUNC, XDB, XEM; `memo_text` for XLM; `notes` for ALGO; bank transfer description for fiat providers |
***
## UnmanagedWallet
| Parameter | Type | Description |
| ------------- | ------------------------------------ | -------------------------------------------------------------------------------------- |
| id | string | The ID of the Unmanaged Wallet |
| name | string | Name of the Wallet Container |
| customerRefId | string | \[optional] The ID for AML providers to associate the owner of funds with transactions |
| assets | Array of [WalletAsset](#walletasset) | An array of the assets available in the unmanaged wallet |
***
## ExternalWallet
| Parameter | Type | Description |
| ------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------- |
| id | string | The ID of the Unmanaged Wallet |
| name | string | Name of the Wallet Container |
| customerRefId | string | \[optional] The ID for AML providers to associate the owner of funds with transactions |
| assets | Array of [ExternalWalletAsset](#externalwalletasset) | An array of the assets available in the external wallet |
# iOS SDK errors
Source: https://developers.fireblocks.com/reference/ios-sdk-errors
| Error Code | Error Message |
| :--------- | :------------------------------------------------------------------------------- |
| 100 | Unknown error |
| 102 | Failed to download certificates |
| 106 | Missing algorithms |
| 107 | Missing private keys |
| 108 | Failed to upload logs |
| 109 | Failed to send version |
| 111 | Maximum number of devices per wallet reached |
| 200 | Timeout during key creation, didn't get startup message |
| 201 | Unknown algorithm |
| 202 | Failed to generate key, key exists in server but not on the device |
| 203 | Timeout during key creation |
| 204 | Failed to send public key |
| 205 | Failed to request key |
| 206 | Failed to enroll player |
| 207 | Failed to create key |
| 300 | Failed to request end-user takeover |
| 301 | Failed to takeover keys |
| 302 | Timeout during key takeover |
| 400 | Failed to export keys |
| 401 | Missing public keys |
| 402 | Missing public key |
| 403 | Failed to derive asset key |
| 404 | Missing cloud private keys |
| 405 | Missing chain code |
| 406 | Missing private key |
| 407 | Failed to export key, recovered PublicKey is not equal to the original PublicKey |
| 408 | Failed to export key |
| 500 | Failed to sign transaction, unknown txId |
| 501 | Error during transaction signing creation, didn't get start signing message |
| 502 | Failed to sign transaction |
| 503 | Timeout during transaction signing |
| 600 | Backup not available |
| 601 | Failed to recover keys |
| 603 | The provided passphrase is wrong |
| 700 | Failed to get key IDs |
| 701 | Missing key IDs in server for backup |
| 702 | We have a discrepancy between valid key IDs between server and client |
| 703 | Failed to backup keys, missing keys |
| 704 | Failed to backup key |
| 705 | Invalid passphrase error |
| 800 | Invalid add device setup data |
| 900 | Failed to join wallet |
| 901 | Timeout during join wallet |
| 902 | Join wallet was stopped |
| 1000 | Failed to approve join wallet |
| 1001 | Timeout during approve join wallet |
| 1002 | No keys to provision |
| 1003 | Approve join wallet was stopped |
# Issue New ERC20F Tokens
Source: https://developers.fireblocks.com/reference/issue-new-erc-20f-tokens
This guide explains how to use the `/v1/tokenization/tokens` endpoint through the SDK to issue a new ERC20F token. This will allow you to deploy and link the token to an asset, enabling easy management of issuance, minting, and burning operations.
## What is ERC20F?
ERC20F is a fungible token reference implementation developed by Fireblocks. It builds upon the widely used ERC-20 token standard, with added functionality for upgradability and enhanced control over token operations. This implementation is designed to be flexible, allowing for token minting, burning, and secure integration within Fireblocks' ecosystem. It is optimized for compliance, making it ideal for organizations requiring scalable and customizable token management solutions.
It's important to note that the ERC20F token uses a proxy pattern, which decouples the state (in the proxy) from the
smart contract logic (referred to as `implementation` in this guide) to support upgradability. Read more about the upgradability features of this contract [here](https://support.fireblocks.io/hc/en-us/articles/14018887816476-Fireblocks-upgradeable-smart-contracts).
We built a contract template for ERC20F tokens that you can use to issue new tokens. To find more information about Templates, refer to the [Contract Template guide](/reference/upload-contract-template#what-are-contract-templates).
## Prerequisites
Before issuing a new ERC20F token using the Fireblocks SDK, ensure you know the following:
1. **Asset ID:** The `assetId` of the blockchain where the token will be deployed (e.g. ETH\_TEST5 for Sepolia). This is the Fireblocks ID of the gas token of the blockchain where the token will be deployed. (To get the asset ID, refer to this [assetId list](https://support.fireblocks.io/hc/en-us/articles/8993656344092-Supported-blockchain-networks))
2. **Vault Account:** The `vaultAccountId` that will deploy the token. Ensure the vault has sufficient native gas for transaction fees. You can retrieve the vaultAccountId from the Fireblocks console by checking the URL of the selected vault, e.g., `https://console.fireblocks.io/v2/accounts/vault/`. For more details about Vault Accounts, refer to the [Create Vault Account guide](/reference/create-vault-account).
3. **Contract Template:** Ensure the contract template is uploaded, and you have the `templateId` from the template. for details. (For `ERC20F`, the contract template ID is `41c76f08-3144-4641-96c9-260c8fe846a7` for `Prod US` workspaces).
4. Ensure you have access to the `Fireblocks Smart Contracts package`, which includes the reference protocol contracts.
With these in place, you can use the Fireblocks SDK to issue a new token.
## Example: Issuing a New ERC20F Token
Here's an example of how to issue a new ERC20F token using the Fireblocks SDK:
### 1. Initialize the Fireblocks SDK
First, the Fireblocks SDK and initialize the SDK with your Fireblocks API key and private key:
```javascript theme={"system"}
import {
Fireblocks,
BasePath,
} from '@fireblocks/ts-sdk';
const privateKey = '...'; // Your Fireblocks API private key
const apiKey = '...'; // Your Fireblocks API key
const fireblocksSdk = new Fireblocks({
apiKey,
basePath: BasePath.US, // Use BasePath.EU for the EU region
secretKey: privateKey,
});
```
### 2. Retrieve ERC20F Contract Template
We need to retrieve the ERC20F contract template using the `getContractTemplate` method:
For more information, refer to the [Get Contract Template API reference page](/reference/getcontracttemplatebyid).
```javascript theme={"system"}
const template = await fireblocksSdk.contractTemplates.getContractTemplate({contractTemplateId: '00000000-0000-0000-0000-000000000003'});
```
As part of the response, you'll receive the `implementationContractId` which is required for the next steps.
### 3. Retrieve Implementation Contract Address
To get the address of the implementation contract, you need to call the `getDeployedContracts` method:
This extra step is required only for templates of contracts that follow the proxy pattern (such as ERC20F).
```javascript theme={"system"}
const contractDetails = await fireblocksSdk.deployedContracts.getDeployedContracts({
baseAssetId: 'ETH_TEST5',
contractTemplateId: 'YOUR_TEMPLATE_ID_HERE'
})
```
As part of the response, you'll receive the `contractAddress` which is required for the next step.
### 4. Issue New Token
To proceed with deploying the new token, you need to define the following deployment variables:
* `name`: The token name (e.g., "MyToken").
* `symbol`: The token symbol (e.g., "MTK").
* `defaultAdminAddress`: The address that will receive the DEFAULT\_ADMIN\_ROLE.
* `minterAddress`: The address that will receive the MINTER\_ROLE.
* `pauserAddress`: The address that will receive the PAUSER\_ROLE.
For more information about the roles, refer to the [Roles in Fireblocks smart contracts article](https://support.fireblocks.io/hc/en-us/articles/13926413716892-Roles-in-Fireblocks-smart-contracts).
Example:
```javascript theme={"system"}
const name = 'MyToken';
const symbol = 'MTK';
const defaultAdminAddress = '0x1234567890123456789012345678901234567890';
const minterAddress = '0x1234567890123456789012345678901234567890';
const pauserAddress = '0x1234567890123456789012345678901234567890';
```
It's important to recall that the ERC20F token uses a proxy pattern. This means that when deploying the token, you must provide both the implementation contract address and the encoded initialize function in the `constructorParams` field. The proxy will reference the implementation contract and use the initialize method to set up the token parameters.
Now let's issue the new token:
```javascript theme={"system"}
let deployRequest: CreateTokenRequestDto = {
assetId: 'ETH_TEST5', // Fireblocks asset ID for Sepolia network
vaultAccountId: '0', // The vault account ID to manage the token
createParams: {
contractId: '41c76f08-3144-4641-96c9-260c8fe846a7', // The ERC20F contract template ID
deployFunctionParams: [
{
name: 'implementation',
type: 'address',
internalType: 'address',
value: 'implementationContractAddress', // Address of the implementation contract retrieved in Step 3
},
{
"name": "_data",
"type": "bytes",
"functionValue": {
"name": "initialize",
"type": "function",
"inputs": [
{
"name": "_name",
"type": "string",
"internalType": "string",
"value": name // _name (e.g., 'MyToken')
},
{
"name": "_symbol",
"type": "string",
"internalType": "string",
"value": symbol // _symbol (e.g., 'MTK')
},
{
"name": "defaultAdmin",
"type": "address",
"internalType": "address",
"value": defaultAdminAddress // Address with DEFAULT_ADMIN_ROLE
},
{
"name": "minter",
"type": "address",
"internalType": "address",
"value": minterAddress // Address with MINTER_ROLE
},
{
"name": "pauser",
"type": "address",
"internalType": "address",
"value": pauserAddress // Address with PAUSER_ROLE
}
],
}
}
],
},
};
// Issue the token
const response = await fireblocksSdk.tokenization.issueNewToken({createTokenRequestDto: deployRequest});
console.log('New token issued:', response);
```
## Highlights:
* Ensure that `contractId` passed in the `createParams` corresponds to the template ID of the contract you want to deploy. In this case, it is the ERC20F contract template ID.
* Replace the example addresses with your own values for `defaultAdminAddress`, `minterAddress`, and `pauserAddress`.
* Ensure that the vault account has sufficient native gas for transaction fees.
* If you need to obtain the ABI for the `initialize` function of the proxy used in step 4, you can find it in the
contract template:
```javascript theme={"system"}
const implementationTemplate = await fireblocksSdk.contractTemplates.getContractTemplate({contractTemplateId: 'implementationContractId'});
```
## Further Reading
For more detailed information on API parameters and responses, including examples for using plain HTTP requests or in other programming languages, please have a look at the [Fireblocks API Reference](/reference/issuenewtoken).
For more specific guidance on ERC20F contract operations, refer to the [Operating the Upgradable ERC20F Contract Support Center Articles](https://support.fireblocks.io/hc/en-us/articles/13926379966876-Operating-the-Upgradeable-ERC-20F-contract).
# Issue new ERC721F/ERC1155F Tokens
Source: https://developers.fireblocks.com/reference/issue-new-erc721ferc1155f-tokens
This guide explains how to use the `v1/tokenization/collections` endpoint through the Fireblocks SDK to issue new ERC721F/ERC1155F tokens. It will walk you through the process that will result in deploying collection contracts, making them available in the Tokenization Engine. It will also show how to perform minting, burning, and other operations related to their respective standards.
## What are ERC721F and ERC1155F contracts?
ERC721F and ERC1155F are non-fungible and semi-fungible token reference implementations developed by Fireblocks. They build upon the widely used ERC-721 and ERC-1155 token standards. ERC721F and ERC1155F tokens can represent ownership of digital or physical assets. They are used in various applications such as digital art, collectibles, and gaming. These implementations are designed to be flexible, allowing for token minting, burning, and secure integration within Fireblocks' ecosystem. They are designed for compliance, making them ideal for organizations requiring scalable and customizable token management solutions.
## Why use Collections API?
The Collections API allows you to easily deploy mint, burn and manage non-fungible and semi-fungible tokens. It is a wrapper around the Tokenization API that enables you to handle operations related to ERC721F/ERC1155F tokens. This means the Collections API will deploy and link the NFT contract by leveraging the tokenization API, with additional helpers to manage the NFT metadata. Essentially, it's a convenience layer on top of the Tokenization API that abstracts the complexity of deploying and linking NFT contracts.
> **Note:**
>
> Collections API is only available for ERC721F and ERC1155F tokens.
## Prerequisites
Before issuing a new ERC721F/ERC1155F token using the Fireblocks SDK, ensure you know the following:
1. assetId: The Asset Id of the blockchain where the token will be deployed (e.g. ETH\_TEST5 for Sepolia). This is the Fireblocks ID of the gas token of the blockchain where the token will be deployed. (To get the asset ID, refer to this [assetId](https://support.fireblocks.io/hc/en-us/articles/8993656344092-Supported-blockchain-networks) list)
2. vaultAccountId: The Id of the Vault that will deploy the token. Ensure the vault has sufficient native gas for transaction fees. The vaultAccountId can be retrieved from the Fireblocks console by checking the URL of the selected vault, e.g., `https://console.fireblocks.io/v2/accounts/vault/`. For more details about Vault Accounts, refer to the Create Vault Account [guide](/reference/create-vault-account).
3. Ensure you have access to the Fireblocks Smart Contracts package, which includes the reference protocol contracts. Contact your CSM if unsure if your workspace has this SKU.
## Example 1: Issuing a New NFT collection
Here's an example of how to issue a new ERC721F or ERC1155F token using the Fireblocks SDK:
### 1. Initialize the Fireblocks SDK
First, import the Fireblocks SDK and initialize it by providing your Fireblocks API key and private key:
```javascript theme={"system"}
import {
Fireblocks,
BasePath,
} from '@fireblocks/ts-sdk';
const privateKey = '...'; // Your Fireblocks API private key
const apiKey = '...'; // Your Fireblocks API key
const fireblocksSdk = new Fireblocks({
apiKey,
basePath: BasePath.US, // Use BasePath.EU for the EU region
secretKey: privateKey,
});
```
### 2. Create a new Collection
To deploy a new ERC721F/ERC1155F collection contract, you need to know the following:
* `baseAssetId`: The assetId of the blockchain where the collection will be deployed (e.g. ETH\_TEST5 for Sepolia).
* `vaultAccountId`: The vaultAccountId of the vault that will deploy the token.
* `type`: The type of the collection, either `NON_FUNGIBLE_TOKEN` or `SEMI_FUNGIBLE_TOKEN`.
* when type is `NON_FUNGIBLE_TOKEN` the collection will be an ERC721F contract.
* when type is `SEMI_FUNGIBLE_TOKEN` the collection will be an ERC1155F contract.
* `name`: The name of the collection. This name will be stored on the smart contract.
* `symbol`: The symbol of the collection.
* `adminAddress`: The address that will receive admin roles on the contract. Ensure that it's an address you control.
* `displayName`: The display name of the collection. This name will be displayed in the Fireblocks console.
For the purpose of this example, we will create an ERC721F collection on the Ethereum Sepolia network.
```javascript theme={"system"}
let collectionRequest: CollectionDeployRequestDto = {
baseAssetId: 'ETH_TEST5',
vaultAccountId: '0',
type: 'NON_FUNGIBLE_TOKEN',
name: 'My Collection',
symbol: 'MC',
adminAddress: '0x5503766D27d1ED4525f5053222E18b29C38eDdB2',
displayName: 'My Collection',
};
const collection = await fireblocksSdk.tokenization.createCollection({
collectionDeployRequest: collectionRequest,
});
```
This will return a collection object with the following properties:
* `id`: The token link id of the collection. Since collections are linked to Tokenization Engine just like fungible tokens deployed using the tokenization API, the collection will have a token link id.
* `status`: The token link status. Possible values are `PENDING`, `COMPLETED` and `FAILED` but, right after sending create collection request, status will be `PENDING`.
* `type`: The type of the collection, either `NON_FUNGIBLE_TOKEN` or `SEMI_FUNGIBLE_TOKEN`.
* `displayName`: The display name of the collection as it appears in the Fireblocks console.
* `tokenMetadata`: The metadata of the collection. For now, it will be empty. But once the deployment transaction is completed, and the collection is linked, the metadata will be updated with the contract address and other details. For more information, refer to the [Collection Metadata](/reference/issue-new-erc721ferc1155f-tokens#collection-metadata) section below.
> **Note:**
>
> The procedure for creating an ERC1155F collection is the same, only that the type should be changed to `SEMI_FUNGIBLE_TOKEN`.
#### Collection Metadata:
The token metadata can be one of the following:
* `ContractMetadataDto`: If the contract is a utility contract (i.e. any arbitrary contract).
* `AssetMetadataDto`: If the contract is a fungible token (i.e. ERC20).
* `CollectionMetadataDto`: If the contract is a non-fungible token (i.e. ERC721 or ERC1155).
Once the contract is deployed and the collection is linked. The `tokenMetadata` will assume a value of type `collectionMetadataDto`. This metadata object that holds the contract address and other details. This object will be stored on the Fireblocks database and it looks like this:
```json theme={"system"}
{
name: "My Collection",
symbol: "MC",
standard: "ERC721F",
blockchainDescriptor: "ETH",
contractAddress: "0x5503766D27d1ED4525f5053222E18b29C38eDdB2",
}
```
Now that we have a token link with a pending status, we can poll the status of the token link to check if the collection is deployed and the linkage is complete. To do that we can use the `getLinkedCollections` method.
#### 2.1 Fetching a Collection
To fetch a collection, you need to know the id of the collection, which is the token link id of the linked token. In this example we will use the id of the collection we created in the previous step. If the id is not known, you can use the getLinkedCollections method, which will return a list of all linked collections. Then you can find and use the id of the collection you want to fetch.
```javascript theme={"system"}
const collectionId = collection.id; // collection object from the previous step
const fetchedCollection = await fireblocksSdk.tokenization.getCollectionById({ TokenIdParamDto: collectionId });
This will return a collection object with the same properties as mentioned in the previous step.
```
If you want to continue to mint an NFT, you can proceed to the next example below.
## Example 2: Minting an NFT
To mint an NFT, the caller must have the `MINTER_ROLE` role on the collection contract. If the collection was deployed through Collections API, the `MINTER_ROLE` role is assigned to the adminAddress that was provided when creating the collection. You also need to perform two steps mentioned in Issuing a New NFT collection example above.
> **Note:**
>
> If you wish to use a different address to mint tokens, you can assign the `MINTER_ROLE` role to the desired address. The process is similar to the one described in the [Assigning Roles](/reference/setting-up-roles-in-erc20f-tokens#3-grant-role-to-address) guide for ERC20F.
### 3. Minting an NFT
To mint an NFT, you need to know the following:
* `vaultAccountId`: The vaultAccountId that will mint the token. Make sure this vault has enough native gas tokens for the transaction fees and the MINTER\_ROLE role on the smart contract.
* `to`: The address that will receive the minted token.
* `tokenId`: The id of the token to mint. This id must be unique within the collection. For this field, it is recommended to have a numerical format and in sequential order.
* `amount`: (Optional) The amount of the token to mint. For ERC721F, amount is ignored. For ERC1155F, the amount should be 1 or greater.
* `metadataURI`: (Optional) The metadata URI of the token. This URI will be stored on the smart contract and can be used to fetch the metadata of the token. This URL is usually an IPFS URL.
* `metadata`: (Optional) The metadata of the token. This metadata object will be uploaded to IPFS and the URI will be stored on the smart contract. For detailed information about the metadata, refer to the [NFT metadata](/reference/issue-new-erc721ferc1155f-tokens#nft-metadata) section below.
#### NFT Metadata:
The metadata object should have the following properties:
* `name`: The name of the token.
* `description`: The description of the token.
* `image`: (Optional) The image of the token. This should be a URL to the image of the token. (e.g. [https://some\\\_domain.com/image\\\_filepath](https://some\\_domain.com/image\\_filepath)).
* `animation`: (Optional) The animation of the token. This should be a URL to the animation of the token. (e.g. [https://some\\\_domain.com/animation\\\_filepath](https://some\\_domain.com/animation\\_filepath)).
* `external_url`: (Optional) The external URL of the token. This should be a URL to the token's external page. (e.g. [https://some\\\_domain.com/token\\\_page](https://some\\_domain.com/token\\_page)).
* `attributes`: (Optional) The attributes of the token. The token can have many attributes or traits depending on the use case. This should be an array of objects, each object should have the following properties:
* `trait_type`: The trait type of the attribute. (e.g. rarity).
* `value`: The value of the attribute. (e.g. common, legendary).
* `display_type`: (Optional) The display type of the attribute. This describes how would you like the trait to be displayed (e.g. number, date).
Here is an example of a metadata object:
```json theme={"system"}
{
name: "My Token",
description: "This is my token",
image: "https\://some_domain.com/image_filepath",
animation: "https\://some_domain.com/animation_filepath",
external_url: "https\://some_domain.com/token_page",
attributes: [
{
trait_type: "rarity",
value: "common",
display_type: "string"
},
{
trait_type: "level",
value: 1,
display_type: "number"
}
]
}
```
**What if I don't want to upload images and animations to a hosted server?**
If you don't want to upload images and animations to a hosted server, you can encode the image and animation files to base64 and pass them in the metadata object. Fireblocks will upload the metadata object containing base64 content to IPFS. This can be done as follows for an image in PNG format:
```javascript theme={"system"}
const image = fs.readFileSync('path/to/fileimage.png').toString('base64');
const metadata = {
name: "My Token",
description: "This is my token",
image: `data:image/png;base64,${image}`,
attributes: [
{
trait_type: "rarity",
value: "common",
display_type: "string"
},
{
trait_type: "level",
value: 1,
display_type: "number"
}
]
}
```
Once you have the metadata object, you can pass it to the metadata field in the mint request.
For this example, we assume that the metadata is already uploaded to IPFS and we have the URI of the metadata. We are also minting an ERC721F token, so we will not use the amount field. If you are minting an ERC1155F token, you can set the amount field to the desired amount.
> **Caution:**
>
> Make sure to use either `metadataURI` or `metadata` - not both. If you use both metadataURI and metadata the request will fail.
```javascript theme={"system"}
let mintRequest: CollectionMintRequestDto = {
vaultAccountId: 'vaultAccountId',
to: '0x5503766D27d1ED4525f5053222E18b29C38eDdB2',
tokenId: 1,
metadataURI: 'ipfs://QmP4P6f7mDHzikhdwLBVSCxCPEgmjwcWSVBHbtSyfBYzBC',
};
const collectionId: CollectionIdParamDto = { id: collection.id }; // collection object from the previous step
const txId = await fireblocksSdk.tokenization.mintCollectionToken({
colletionId,
collectionMintRequest: mintRequest,
});
```
This will return the Fireblocks transaction id of the Mint transaction.
#### 3.1. Fetching the minted token
To fetch the minted token, you need to know the tokenId of the token. In this example we will use the tokenId we minted in the previous step. To fetch the token you can use the fetchCollectionTokenDetails method that will return the nft token object.
```javascript theme={"system"}
const tokenId = mintRequest.tokenId; // tokenId from the mint request
const fetchedToken = await fireblocksSdk.tokenization.fetchCollectionTokenDetails(collectionId, tokenId);
```
This will return a token object with the following properties:
* `tokenId`: The id of the token.
* `metadataURI`: The metadata URI of the token.
* `totalSupply`: The total supply of the token.
If you would like to continue learn how to burn NFT, you can proceed to the next example.
## Example 3: Burning an NFT
To burn an NFT, the caller must have the `BURNER_ROLE` role on the collection contract. The `BURNER_ROLE` role is not assigned to anyone by default. You also need to make sure you have a collection of NFTs and an NFT to burn which described in example 1 and 2. To assign the `BURNER_ROLE` role to an address, you can use the `grantRole` method. For more information, refer to the [Assigning Roles](/reference/setting-up-roles-in-erc20f-tokens#3-grant-role-to-address) guide for ERC20F. The process is the same for ERC721F/ERC1155F.
### 4. Burning an NFT
To burn an NFT, you need to know the following:
* `collectionId`: The id of the collection.
* `vaultAccountId`: The vaultAccountId that will burn the token. Make sure this vault has enough native gas for the transaction fees and the BURNER\_ROLE role on the smart contract.
* `tokenId`: The id of the token to burn.
* `amount`: (Optional) The amount of the token to burn. For ERC721F, amount is ignored. For ERC1155F, amount should be 1 or greater.
For this example, we will burn an ERC721F token, so we will not use the amount field. If you are burning an ERC1155F token, you can set the amount field to the desired amount.
```javascript theme={"system"}
let burnRequest: CollectionBurnRequestDto = {
vaultAccountId: 'vaultAccountId',
tokenId: 1,
};
let collectionId = { id: collection.id }: CollectionIdParamDto; // collection object from the previous step
const txId = await fireblocksSdk.tokenization.burnCollectionToken({
colletionId,
collectionBurnRequestDto: burnRequest,
});
```
This will return the Fireblocks transaction id of the Burn transaction.
## Summary
The Collections API is a high-level API provides a simple interface to manage NFTs. Without collections API, you would need to:
1. Fetch the templates from `getContractTemplates`.
2. Find the template (e.g. ERC721F) from the list.
3. Fetch the template using `getContractTemplate`.
4. Deploy the contract.
5. Mint the NFT.
With collections API all of that is abstracted into the purpose-driven methods explained in this guide.
## Further Reading
For more detailed information on API parameters and responses, including examples for using plain HTTP requests or in other programming languages, please have a look at the [Fireblocks API Reference](/reference/createnewcollection).
For more specific guidance on ERC721F and ERC1155F contracts operations, refer to the \[Operating the Upgradable ERC721F Contract Support Center Articles]\(Operating the Upgradable ERC721F Contract Support Center Articles) guides.
# Java SDK
Source: https://developers.fireblocks.com/reference/java-sdk
**Install the Fireblocks Documentation MCP first.** Whether you're using an AI assistant or not, this makes it easy to search, reference, and keep your Fireblocks work grounded in the official docs. The setup steps are in [Getting Started](/docs/quickstart).
# Overview
Java developers can use [the official Fireblocks Java SDK](https://github.com/fireblocks/java-sdk) to interact with the Fireblocks API. Instructions for setup and usage can be found in the repo's README.md file.
# Using the Fireblocks Java SDK
Building the API client library requires:
1. Java 11+
2. Maven/Gradle
## Installation
To install the API client library to your local Maven repository, execute:
```bash theme={"system"}
mvn clean install
```
To deploy it to a remote Maven repository instead, configure the settings of the repository and execute:
```bash theme={"system"}
mvn clean deploy
```
Refer to the [OSSRH Guide](http://central.sonatype.org/pages/ossrh-guide.html) for more information.
### Maven users
Add this dependency to your project's POM:
```xml theme={"system"}
com.fireblocks.sdk``
fireblocks-sdk``
0.0.0``
compile``
``
```
### Gradle users
Add this dependency to your project's build file:
```groovy theme={"system"}
compile "com.fireblocks.sdk:fireblocks-sdk:0.0.0"
```
### Others
At first, generate the JAR by executing:
```bash theme={"system"}
mvn clean package
```
Then manually install the following JARs:
* `target/fireblocks-sdk-0.0.0.jar`
* `target/lib/*.jar`
## Getting Started
### Initiate Fireblocks Client
You can initialize the Fireblocks SDK in two ways: either by setting environment variables or by providing the parameters directly:
**Using Environment Variables**
You can initialize the SDK using environment variables from your .env file or by setting them programmatically.
> **Use the correct API Base URL**
>
> In the following script, make sure you're using the correct value for `FIREBLOCKS_BASE_PATH` for your environment:
>
> * For Sandbox workspaces: `https://sandbox-api.fireblocks.io`
> * For US Mainnet or Testnet workspaces: `https://api.fireblocks.io`
> * For EU Mainnet or Testnet workspaces: `https://eu-api.fireblocks.io`
> * For EU2 Mainnet or Testnet workspaces: `https://eu2-api.fireblocks.io`
>
> [Learn more about workspace differences](doc:workspace-environments).
Use bash commands to set environment variables:
```bash theme={"system"}
export FIREBLOCKS_BASE_PATH="https://sandbox-api.fireblocks.io/v1"
export FIREBLOCKS_API_KEY="my-api-key"
export FIREBLOCKS_SECRET_KEY="my-secret-key"
```
Execute the following Java code:
```java theme={"system"}
import com.fireblocks.sdk.Fireblocks;
import com.fireblocks.sdk.ConfigurationOptions;
ConfigurationOptions configurationOptions = new ConfigurationOptions();
Fireblocks fireblocks = new Fireblocks(configurationOptions);
```
**Providing Local Variables**
Alternatively, you can directly pass the required parameters when initializing the Fireblocks API instance:
```java theme={"system"}
import com.fireblocks.sdk.BasePath;
import com.fireblocks.sdk.Fireblocks;
import com.fireblocks.sdk.ConfigurationOptions;
ConfigurationOptions configurationOptions = new ConfigurationOptions()
.basePath(BasePath.Sandbox)
.apiKey("my-api-key")
.secretKey("my-secret-key");
Fireblocks fireblocks = new Fireblocks(configurationOptions);
```
## Examples
### Creating a Vault Account
```java theme={"system"}
CreateVaultAccountRequest request = new CreateVaultAccountRequest().name("My Vault Account");
String idempotencyKey = Integer.toString(new Random().nextInt()); // String | A unique identifier for the request. If the request is sent multiple times with the same idempotency key, the server will return the same response as the first request. The idempotency key is valid for 24 hours.
// Async request
CompletableFuture response = fireblocks.vaults().createVaultAccount(request, idempotencyKey);
// Waiting for the request
VaultAccount vaultAccount = response.get();
```
### Retrieving Vault Accounts
```java theme={"system"}
BigDecimal limit = new BigDecimal(10);
CompletableFuture response = fireblocks.vaults().getPagedVaultAccounts(null, null, null, null, null, null, null, limit);
VaultAccountsPagedResponse vaultAccountsPagedResponse = response.get();
```
### Creating a Transaction
```java theme={"system"}
TransactionRequest transactionRequest = new TransactionRequest()
.operation(TransactionOperation.TRANSFER)
.source(new TransferPeerPath()
.type(TransferPeerPath.TypeEnum.VAULT_ACCOUNT)
.id("0"))
.destination(new DestinationTransferPeerPath()
.type(DestinationTransferPeerPath.TypeEnum.VAULT_ACCOUNT)
.id("1"))
.amount(new TransactionRequestAmount("0.001"))
.assetId("ETH_TEST3"); // Ethereum Goerli testnet
.note("My first Java transaction!");
String idempotencyKey = Integer.toString(new Random().nextInt()); // String | A unique identifier for the request. If the request is sent multiple times with the same idempotency key, the server will return the same response as the first request. The idempotency key is valid for 24 hours.
CompletableFuture response = fireblocks.transactions().createTransaction(transactionRequest, null, idempotencyKey);
CreateTransactionResponse transactionResponse = response.get();
String txId = transactionResponse.getId();
```
# JavaScript SDK errors
Source: https://developers.fireblocks.com/reference/javascript-sdk-errors
| Error Code | Error Message |
| :--------- | :--------------------------------------- |
| 100 | UNKNOWN\_ERROR |
| 101 | PROCESS\_ALREADY\_RUNNING |
| 102 | INVALID\_CERTIFICATE |
| 103 | INVALID\_MPC\_MESSAGE |
| 104 | FAILED\_MPC\_BROADCAST |
| 105 | UNEXPECTED\_MPC\_MESSAGE |
| 106 | MISSING\_ALGORITHMS |
| 107 | MISSING\_PRIVATE\_KEYS |
| 108 | INCOMPLETE\_DEVICE |
| 109 | INSTANCE\_ALREADY\_INITIALIZED |
| 110 | INVALID\_PHYSICAL\_DEVICE\_ID |
| 111 | MAX\_DEVICES\_PER\_WALLET\_REACHED |
| 112 | UNKNOWN\_RESPONSE\_FROM\_MESSAGEHANDLER |
| 113 | API\_CALL\_FAILED |
| 200 | NO\_FIRST\_MESSAGE\_TIMEOUT |
| 201 | UNKNOWN\_ALGORITHM |
| 202 | MISSING\_KEY\_ON\_DEVICE |
| 203 | KEY\_CREATION\_TIMEOUT |
| 204 | FAILED\_TO\_SEND\_PUBLIC\_KEY |
| 205 | FAILED\_TO\_REQUEST\_KEY |
| 206 | FAILED\_TO\_ENROLL\_PLAYER |
| 207 | FAILED\_TO\_CREATE\_KEY |
| 208 | FAILED\_TO\_CONFIRM\_KEY |
| 300 | FAILED\_TO\_REQUEST\_END\_USER\_TAKEOVER |
| 301 | FAILED\_TO\_TAKEOVER\_KEYS |
| 302 | KEY\_TAKEOVER\_TIMEOUT |
| 400 | FAILED\_TO\_EXPORT\_KEYS |
| 401 | MISSING\_PUBLIC\_KEYS |
| 402 | MISSING\_PUBLIC\_KEY |
| 403 | FAILED\_TO\_DERIVE\_ASSET\_KEY |
| 404 | MISSING\_CLOUD\_PRIVATE\_KEYS |
| 405 | MISSING\_CHAIN\_CODE |
| 406 | MISSING\_PRIVATE\_KEY |
| 407 | PUBLIC\_KEYS\_DISCREPANCY\_ERROR |
| 408 | FAILED\_TO\_EXPORT\_KEY |
| 500 | UNKNOWN\_TX\_ID |
| 501 | NO\_FIRST\_TX\_SIGNING\_MESSAGE |
| 502 | FAILED\_TO\_SIGN\_TRANSACTION |
| 503 | TRANSACTION\_SIGNING\_TIMEOUT |
| 504 | SIGNING\_STOPPED |
| 505 | TRANSACTION\_STATUS\_FAILURE |
| 600 | BACKUP\_NOT\_AVAILABLE\_ERROR |
| 601 | FAILED\_TO\_RECOVER\_KEYS |
| 602 | UNKNOWN\_BACKUP\_ALGORITHM |
| 603 | WRONG\_RECOVERY\_PASSPHRASE |
| 700 | FAILED\_TO\_GET\_KEY\_IDS |
| 701 | MISSING\_KEY\_IDS\_FOR\_BACKUP |
| 702 | KEYS\_DISCREPANCY\_BACKUP\_ERROR |
| 703 | MISSING\_KEYS\_BACKUP\_ERROR |
| 704 | FAILED\_TO\_BACKUP\_KEY |
| 705 | INVALID\_PASSPHRASE\_ERROR |
| 706 | INCOMPLETE\_BACKUP |
| 800 | INVALID\_ADD\_DEVICE\_SETUP\_DATA |
| 801 | MPC\_SETUP\_ALREADY\_STARTED |
| 900 | FAILED\_TO\_JOIN\_WALLET |
| 901 | JOIN\_WALLET\_TIMEOUT |
| 902 | JOIN\_WALLET\_STOPPED |
| 1000 | FAILED\_TO\_APPROVE\_JOIN\_WALLET |
| 1001 | APPROVE\_JOIN\_WALLET\_TIMEOUT |
| 1002 | NO\_KEYS\_TO\_PROVISION |
| 1003 | APPROVE\_JOIN\_WALLET\_STOPPED |
# JS SDK (Legacy)
Source: https://developers.fireblocks.com/reference/js-sdk-legacy
> **We released our official TypeScript SDK! Make sure to check it out in here**
# Overview
A JavaScript or Typescript developer can use the Fireblocks API in 2 different ways:
1. [The Fireblocks JavaScript SDK.](https://github.com/fireblocks/fireblocks-sdk-js)
2. A standard HTTP library, such as [Axios.](https://axios-http.com/docs/intro)
In this guide, you'll set up the Fireblocks SDK and see an example of non-SDK usage (including signing the JWT token).
Additionally if you are developing on EVM chains - you might be using some of the familiar libraries, such as `web3.js` or `ethers.js` - Fireblocks is well intergrated into these libraries as described in the [Ethereum Development](doc:ethereum-development).
# Using the Fireblocks SDK
## Install Node v16 or newer
The Fireblocks JavaScript SDK requires **Node v16 or newer**. You can check which version of Node you already have installed by running the following command.
`node -v`
[Learn how to install or update Node to a newer version.](https://nodejs.org/en/download/)
## Install fireblocks-sdk
The Fireblocks JavaScript SDK is open-source and hosted on both GitHub and PIP, the official package repository.
* **Source code:** [https://github.com/fireblocks/fireblocks-sdk-js](https://github.com/fireblocks/fireblocks-sdk-js)
* **JavaScript Package:** [https://www.npmjs.com/package/fireblocks-sdk](https://www.npmjs.com/package/fireblocks-sdk)
Installing the latest SDK is easy with `npm`:
`npm install fireblocks-sdk`
## Your First Fireblocks JavaScript script!
Now that you're set-up, run a quick check for the API. The script will query existing vaults, create a new vault and then query again to see that the vaults were created.
This Axios-based implementation will require some library dependencies:
* [Axios](https://www.npmjs.com/package/axios)
* [jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken)
> **Use the correct API Base URL**
>
> In the following script, make sure you're using the correct value for `baseUrl` for your environment:
>
> * For Sandbox workspaces: `https://sandbox-api.fireblocks.io`
> * For Mainnet or Testnet workspaces: `https://api.fireblocks.io`
>
> [Learn more about workspace differences](doc:workspace-environments).
```javascript theme={"system"}
const fs = require('fs');
const path = require('path');
const { FireblocksSDK } = require('fireblocks-sdk');
const { exit } = require('process');
const { inspect } = require('util');
const apiSecret = fs.readFileSync(path.resolve("``"), "utf8");
const apiKey = ""
// Choose the right api url for your workspace type
const baseUrl = "https://sandbox-api.fireblocks.io";
const fireblocks = new FireblocksSDK(apiSecret, apiKey, baseUrl);
(async () => {
// Print vaults before creation
let vaultAccounts = await fireblocks.getVaultAccountsWithPageInfo({});
console.log(inspect(vaultAccounts, false, null, true));
// Create vault account
const vaultCreation = await fireblocks.createVaultAccount("QuickStart_Vault");
console.log(inspect(vaultCreation, false, null, true));
// Print vaults after creation
vaultAccounts = await fireblocks.getVaultAccountsWithPageInfo({});
console.log(inspect(vaultAccounts, false, null, true));
})().catch((e)=>{
console.error(`Failed: ${e}`);
exit(-1);
})
```
```javascript theme={"system"}
const fs = require('fs');
const path = require('path');
const { FireblocksSDK } = require('fireblocks-sdk');
const { exit } = require('process');
const { inspect } = require('util');
const axios = require('axios');
const { sign } = require('jsonwebtoken');
const { v4: uuid } = require('uuid');
const crypto = require('crypto');
const apiSecret = fs.readFileSync(path.resolve("``"), "utf8");
const apiKey = ""
// Choose the right api url for your workspace type
const baseUrl = "https://sandbox-api.fireblocks.io";
const fireblocks = new FireblocksSDK(apiSecret, apiKey, baseUrl);
class FireblocksRequestHandler{
baseUrl;
apiSecret;
apiKey;
constructor(apiSecret, apiKey, baseUrl = "https://api.fireblocks.io"){
this.baseUrl = baseUrl;
this.apiSecret = apiSecret;
this.apiKey = apiKey;
}
async post(path, data){
const jwt = this.jwtSign(path,data);
return (await this.req(jwt, path, data, "POST"));
}
async get(path) {
const jwt = this.jwtSign(path);
return (await this.req(jwt, path, undefined, "GET"));
}
async req(jwt, path, data, method){
const resp = await axios({
url: `${this.baseUrl}${path}`,
method: method,
data,
headers:{
"X-API-Key":this.apiKey,
"Authorization": `Bearer ${jwt}`
}
});
return resp.data;
}
jwtSign(path, data){
const token = sign({
uri: path,
nonce: uuid(),
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 55,
sub: this.apiKey,
bodyHash: crypto.createHash("sha256").update(JSON.stringify(data || "")).digest().toString("hex")
}, this.apiSecret, {algorithm: "RS256"});
return token;
}
}
(async () => {
const requestHandler = new FireblocksRequestHandler(apiSecret, apiKey);
// Print vaults before creation
let vaults = await requestHandler.get("/v1/vault/accounts_paged");
console.log(inspect(vaults, false, null, true));
// Create vault account
const vaultCreation = await requestHandler.post("/v1/vault/accounts", {"name":"QuickStart_Vault"});
console.log(inspect(vaultCreation, false, null, true));
// Print vaults after creation
vaults = await requestHandler.get("/v1/vault/accounts_paged");
console.log(inspect(vaults, false, null, true));
})().catch((e)=>{
console.error(`Failed: ${e}`);
exit(-1);
});
```
# Launch Workflow Execution
Source: https://developers.fireblocks.com/reference/launch-workflow-execution
Once the WE is in **READY\_FOR\_LAUNCH** status, call the [POST /payments/workflow\_execution//actions/execute](/reference/launchflowexecution) endpoint.
The WE proceeds through the following statuses. These statuses will be applied to each WEO and the WE as a whole.
1. **EXECUTION\_IN\_PROGRESS:** The execution process has started.
2. **EXECUTION\_COMPLETED** or **EXECUTION\_FAILED:** The execution completed or failed. These are finite states.
# Mint an NFT
Source: https://developers.fireblocks.com/reference/mint-an-nft
First, upload an image of your newly almost minted NFT. The minting function will receive it as one of its parameters.
> **Image hosting options**
>
> You can upload your selected image using any image-hosting site.
>
> While not covered in this guide, another option would be to use a system like [IPFS protocol](https://en.wikipedia.org/wiki/InterPlanetary_File_System) to store your image on-chain as a decentralized solution.
Then we call upon the function while passing these values with it.
| Parameter | Description |
| --------- | ----------------------------------------------------------- |
| `sender` | The transaction signer address (your address) |
| `tokenId` | The ID value of the newly minted NFT |
| `uri` | The NFT's name, description, properties, and image location |
Now we will use Hardhat for the actual deployment. First, we need to make sure it is well set up as described in the [Fireblocks Hardhat Plugin](/reference/hardhat-plugin) guide and then we follow the steps described in this guide.
***
# Using Hardhat
> **Hardhat Runtime Environment required**
>
> We specifically require the Hardhat Runtime Environment.
>
> This is optional but useful for running the script in a standalone fashion through `node