Skip to content

Builder Integration Guide

Overview

This guide explains how to integrate your application with GRVT and enable trading on behalf of your users.

Integration steps

1. Connect User Wallet

2. Authorize Builder

Choose the environment you want to authenticate against.

# stg
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/builder/authorize"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/builder/authorize"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/builder/authorize"

Request Parameters

Retrieving Funding Addresses

Both main_account_id and builder_account_id are funding addresses that can be retrieved by accessing the GRVT Exchange API Keys page: https://grvt.io/exchange/account/api-keys

This endpoint supports two modes depending on whether you provide the API key fields:

  • With API key (provide builder_api_key_signer + builder_api_key_permissions + builder_api_key_label): Authorizes the builder on-chain via AddAccountSignerWithBuilder and creates a GRVT API key. The API key is returned in the response.
  • Without API key (omit all three builder_api_key_* fields): Authorizes the builder on-chain via AuthorizeBuilder without creating an API key. Returns an empty response.
"name" Type Required Description
main_account_id string True The funding address of the user granting the authorization.
builder_account_id string True The funding address of the Builder receiving the authorization.
max_futures_fee_rate string True The maximum fee rate cap in percentage for Futures trades executed by this builder. The builder cannot charge fees exceeding this limit. Eg. "0.1" means 0.1%
max_spot_fee_rate string True The maximum fee rate cap in percentage for Spot trades executed by this builder. The builder cannot charge fees exceeding this limit. Eg. "0.1" means 0.1%
signature Signature True The cryptographic signature authenticating this request. Must be signed by the private key associated with mainAccountID. See Signing Payload section below for details.
builder_api_key_label string False Required when builder_api_key_signer and builder_api_key_permissions are provided. The user will see this label on the gravity api list UI.
builder_api_key_signer string False An Ethereum public key pair that you generate for your user. This key can sign trades on behalf of your user across all sub-accounts they have. You can use the private key to sign trades on behalf of your user without sending Grvt the private key. Must be provided together with builder_api_key_permissions.
builder_api_key_permissions string False Permissions as a sorted string (lowest bit to highest bit), separated by &:
- Examples: "Trade", "Admin", "Admin&Trade"
- Bit mapping: ADMIN=1, INTERNAL_TRANSFER=2, EXTERNAL_TRANSFER=3, WITHDRAW=4, VAULT_INVESTOR=5, TRADE=6

Please use TRADE for now
Must be provided together with builder_api_key_signer.

Example Request

With API key creation:

{
    "main_account_id": "'0x...'",
    "builder_account_id": "'0x....'",
    "max_futures_fee_rate": "0.001",
    "max_spot_fee_rate": "0.0001",
    "signature": {
        "signer": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
        "r": "0xb788d96fee91c7cdc35918e0441b756d4000ec1d07d900c73347d9abbc20acc8",
        "s": "0x3d786193125f7c29c958647da64d0e2875ece2c3f845a591bdd7dae8c475e26d",
        "v": 28,
        "expiration": "1697788800000000000",
        "nonce": 1234567890,
        "chain_id": "327"
    },
    "builder_api_key_label": "superbuilder",
    "builder_api_key_signer": "0x....",
    "builder_api_key_permissions": "Admin&Trade"
}

Without API key (on-chain authorization only):

{
    "main_account_id": "'0x...'",
    "builder_account_id": "'0x....'",
    "max_futures_fee_rate": "0.001",
    "max_spot_fee_rate": "0.0001",
    "signature": {
        "signer": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
        "r": "0xb788d96fee91c7cdc35918e0441b756d4000ec1d07d900c73347d9abbc20acc8",
        "s": "0x3d786193125f7c29c958647da64d0e2875ece2c3f845a591bdd7dae8c475e26d",
        "v": 28,
        "expiration": "1697788800000000000",
        "nonce": 1234567890,
        "chain_id": "327"
    }
}

Signing Payload

The signature must be created using EIP-712 typed data signing. The structure differs based on the authorization mode:

With API key (when providing builder_api_key_signer + builder_api_key_permissions):

{
  "domain": {
    "chainId": 327,
    "name": "GRVT Exchange",
    "version": "0"
  },
  "message": {
    "accountID": "'0x...'",
    "signer": "'0x....'",
    "permissions": "Trade",
    "builderAccountID": "'0x....'",
    "maxFutureFeeRate": 100,
    "maxSpotFeeRate": 10,
    "nonce": 1234567890,
    "expiration": 1697788800000000000
  },
  "primaryType": "AddAccountSignerWithBuilder",
  "types": {
    "EIP712Domain": [
      { "name": "name", "type": "string" },
      { "name": "version", "type": "string" },
      { "name": "chainId", "type": "uint256" }
    ],
    "AddAccountSignerWithBuilder": [
      { "name": "accountID", "type": "address" },
      { "name": "signer", "type": "address" },
      { "name": "permissions", "type": "string" },
      { "name": "builderAccountID", "type": "address" },
      { "name": "maxFutureFeeRate", "type": "uint32" },
      { "name": "maxSpotFeeRate", "type": "uint32" },
      { "name": "nonce", "type": "uint32" },
      { "name": "expiration", "type": "int64" }
    ]
  }
}

Without API key (on-chain authorization only):

{
  "domain": {
    "chainId": 327,
    "name": "GRVT Exchange",
    "version": "0"
  },
  "message": {
    "mainAccountID": "'0x...'",
    "builderAccountID": "'0x....'",
    "maxFutureFeeRate": 100,
    "maxSpotFeeRate": 10,
    "nonce": 1234567890,
    "expiration": 1697788800000000000
  },
  "primaryType": "AuthorizeBuilder",
  "types": {
    "EIP712Domain": [
      { "name": "name", "type": "string" },
      { "name": "version", "type": "string" },
      { "name": "chainId", "type": "uint256" }
    ],
    "AuthorizeBuilder": [
      { "name": "mainAccountID", "type": "address" },
      { "name": "builderAccountID", "type": "address" },
      { "name": "maxFutureFeeRate", "type": "uint32" },
      { "name": "maxSpotFeeRate", "type": "uint32" },
      { "name": "nonce", "type": "uint32" },
      { "name": "expiration", "type": "int64" }
    ]
  }
}

Chain ID

The chainId value in the domain field must match the GRVT L2 Chain ID for your target environment. The example above uses 327 (Sepolia Stg). Refer to the Chain IDs table for all network-specific values.

Fee Rate Units

The maxFutureFeeRate and maxSpotFeeRate fields in the signing payload are expressed as integers multiplied by 10,000 (1e4): - Calculation: fee_rate × 10,000 - Example conversions:

- `0.001` fee rate = `10` (0.001 × 10,000)
- `0.0005` fee rate = `5` (0.0005 × 10,000)
- `0.0001` fee rate = `1` (0.0001 × 10,000)

Payload Fields:

Field Type Mode Description
chainId uint256 Both The GRVT L2 Chain ID for the target network (in domain field). Refer to Chain IDs table for network-specific values.
mainAccountID address Without API key The Main Account ID (Ethereum address) of the user granting authorization (used in AuthorizeBuilder type)
accountID address With API key The Main Account ID (Ethereum address) of the user granting authorization (used in AddAccountSignerWithBuilder type)
builderAccountID address Both The builder_account_id - Main Account ID of the Builder
maxFutureFeeRate uint32 Both The max_futures_fee_rate - Maximum fee rate for Futures trades (multiplied by 10,000)
maxSpotFeeRate uint32 Both The max_spot_fee_rate - Maximum fee rate for Spot trades (multiplied by 10,000)
nonce uint32 Both Random value for signature deconflicting (0 to 4,294,967,295)
expiration int64 Both Timestamp in unix nanoseconds when signature expires (max 30 days)
signer address With API key The builder_api_key_signer - Ethereum public key that can sign trades on behalf of the user
permissions string With API key The builder_api_key_permissions as a sorted string (lowest bit to highest bit), separated by &:
- Single permission: "Admin" or "Trade"
- Multiple permissions: "Admin&InternalTransfer", "Admin&InternalTransfer&Trade"
- Bit mapping: ADMIN=1, INTERNAL_TRANSFER=2, EXTERNAL_TRANSFER=3, WITHDRAW=4, VAULT_INVESTOR=5, TRADE=6
- Note: Permissions are always sorted by bit position (e.g., "Admin&Trade", never "Trade&Admin")

Permission String Format

  • Both the permissions field in the signing payload and the builder_api_key_permissions request parameter must use the sorted string format
  • When multiple permissions are granted, they must be sorted by bit position (lowest to highest) and joined with &
  • Examples:
    • Single permission: "Trade" or "Admin"
    • Multiple permissions: "Admin&InternalTransfer" (correct) vs "InternalTransfer&Admin" (incorrect - wrong order)
    • Combined: "Admin&InternalTransfer&Trade"
  • Note: The permission string format ensures a 1-to-1 mapping between the string and its bitmask value

Signing Process:

  1. The user must sign this EIP-712 typed data payload with their private key associated with main_account_id
  2. The signing produces three values: r, s, and v
  3. These values, along with the signer address, nonce, expiration, and chain_id are included in the signature field of the request

Note

The signature fields correspond to the Signature type used throughout the GRVT API.

Example Response

With API key creation — the API key is used for authentication in step 3:

{
    "api_key": "abc....."
}

Without API key — returns an empty response on success:

{}

3. Authenticate with API Key

Note

This step applies only when using the with API key authorization mode.

Use the api_key returned from step 2 to authenticate with the GRVT API and use trading functions.

For detailed authentication instructions, please refer to the Authentication page.

4. Manage Sub-Accounts

Query available sub-accounts that your builder can trade on.

Reference: Builder Codes - Get Sub Accounts

5. Execute Trades

Your builder can now execute trades on all authorized sub-accounts using the Trade permission and the builder_api_signer key pair from one of the sub accounts.

Reference: Builder Codes - Trading on Behalf of Users

Get Deposit Addresses

Returns the chains and tokens supported for depositing into the authenticated user's GRVT account, along with the on-chain deposit address to send funds to on each chain.

Use this endpoint to discover where a user should send funds when topping up their GRVT account. Each chain entry includes the deposit address generated for the user, the supported tokens, and their on-chain contract addresses.

Endpoint

# staging
GRVT_DEPOSIT_ENDPOINT="https://edge.staging.gravitymarkets.io/api/v1/deposit/addresses"
# testnet
GRVT_DEPOSIT_ENDPOINT="https://edge.testnet.grvt.io/api/v1/deposit/addresses"
# prod
GRVT_DEPOSIT_ENDPOINT="https://edge.grvt.io/api/v1/deposit/addresses"
Method Path
GET /api/v1/deposit/addresses

Authentication

This endpoint accepts either authentication method:

  • API key — pass your API key in the X-API-Key header. The account is resolved directly from the key, so no session cookie is required.
  • Session cookie — authenticate via login to obtain a session cookie (gravity=...) and the X-Grvt-Account-Id header value, then pass both on the request.

See the Authentication page for details on both methods.

The resolved account must have completed chain account setup. Requests are rejected when the bridge feature is disabled or the account has no chain account address.

Request Parameters

This endpoint takes no query parameters or request body. The chains and tokens are derived from the resolved account.

Example Request

Using an API key:

GRVT_API_KEY="<insert_key_here>"

curl "$GRVT_DEPOSIT_ENDPOINT" \
    -H "X-API-Key: $GRVT_API_KEY" \
    -s

Using a session cookie:

curl "$GRVT_DEPOSIT_ENDPOINT" \
    -H "Cookie: $GRVT_COOKIE" \
    -H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
    -s

Response Fields

Field Type Description
chains array of ChainInfo List of chains supported for deposits, one per chain.

ChainInfo

Field Type Description
chain string The chain identifier (e.g. ARBITRUM, BASE, BINANCE, KAIA, SOLANA, TRON).
chain_id string The native chain ID for the chain (e.g. 42161 for Arbitrum). For non-EVM chains this is a chain name such as solana or tron.
deposit_address string The on-chain address to send deposits to for this chain. Empty for on-demand-only chains where a deposit address has not yet been generated for the user (see note below).
supported_tokens array of TokenInfo The tokens that can be deposited on this chain.

TokenInfo

Field Type Description
name string The token symbol (e.g. USDT, USDC).
contract_address string The token's on-chain contract address on the given chain. May be empty for native chain assets.

Example Response

{
    "chains": [
        {
            "chain": "ARBITRUM",
            "chain_id": "42161",
            "deposit_address": "0xYourArbitrumDepositAddress",
            "supported_tokens": [
                {
                    "name": "USDT",
                    "contract_address": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"
                },
                {
                    "name": "USDC",
                    "contract_address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
                }
            ]
        },
        {
            "chain": "BASE",
            "chain_id": "8453",
            "deposit_address": "0xYourBaseDepositAddress",
            "supported_tokens": [
                {
                    "name": "USDC",
                    "contract_address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
                }
            ]
        },
        {
            "chain": "BINANCE",
            "chain_id": "56",
            "deposit_address": "0xYourBinanceDepositAddress",
            "supported_tokens": [
                {
                    "name": "USDT",
                    "contract_address": "0x55d398326f99059fF775485246999027B3197955"
                },
                {
                    "name": "USDC",
                    "contract_address": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"
                }
            ]
        },
        {
            "chain": "KAIA",
            "chain_id": "8217",
            "deposit_address": "0xYourKaiaDepositAddress",
            "supported_tokens": [
                {
                    "name": "USDT",
                    "contract_address": "0xd077a400968890eacc75cdc901f0356c943e4fdb"
                }
            ]
        },
        {
            "chain": "TRON",
            "chain_id": "tron",
            "deposit_address": "TYourTronDepositAddress",
            "supported_tokens": [
                {
                    "name": "USDT",
                    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
                }
            ]
        },
        {
            "chain": "SOLANA",
            "chain_id": "solana",
            "deposit_address": "",
            "supported_tokens": [
                {
                    "name": "USDT",
                    "contract_address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"
                },
                {
                    "name": "USDC",
                    "contract_address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
                }
            ]
        }
    ]
}

On-demand chains

Some chains (e.g. SOLANA) are on-demand only. They are not automatically registered for wallet generation, so they are returned with an empty deposit_address until a deposit address is provisioned for the user. The chain and its supported tokens are still listed so clients can surface them in the UI.

Token contract addresses

Token contract_address values are resolved dynamically from the bridge provider's configuration. If the bridge provider cannot be reached, a chain's tokens may be returned with empty contract_address values.