CHANGE LOG
2026-10-06
- Added integration guide.
2026-09-17
- Add
POST /api/v1/user/lockso a user can permanently lock their account. A locked user cannot update profile, payout address, light mode, or request a manual withdrawal. Unlock is not available through the API. -
GET /api/v1/user/infoincludeslocked. - Add
POST /api/v1/ssv/validator/mode/enableandPOST /api/v1/obol/validator/mode/enableto enable light mode for SSV or Obol keys (same rules asPOST /api/v1/validator/mode/enable, scoped to that key type).
2026-09-16
- Add
POST /api/v1/validator/mode/enableso a user can enable light mode for their preconf account and up to 100 owned validator keys. Light mode cannot be disabled through this API. Open markets are unchanged.
2026-07-23
- paymentHistory accepts
slots(comma-separated original/paid slot numbers), same form as blockHistory.
2026-07-17
- paymentHistory rows include
validatorPayoutAddressfor the original market/slot (hex, no0xprefix).
2026-07-16
- paymentHistory rows include
operatorName(COALESCE(verified_name, display_name));operatorNamefilter matchesdisplay_nameorverified_name.
2026-07-15
- Add dashboard operator paymentHistory API with paying-slot filters (
fromPaymentSlot/toPaymentSlot),operatorNameorvalidatorUserIdidentity (like blockHistory), ISO payment/slot times, and ordering by paying slot.
2026-06-24
- Update builder delegation API for builder entity delegation.
- Add public builder entity list API.
2026-02-20
Update Error codes and minor cleanups
2026-01-14
Update documentation. Minor cleanups.
2025-10-31
Support Ethereum Fusaka upgrade
2025-10-11
Updated contract address for mainnet and hoodi
2025-07-08
- Update inclusion-preconf cancel-all-orders api
- Update inclusion-preconf/markets api by adding validator_type field
- Allow user to update its payment address
- Allow user to specify its collater per slot for block owner / validator
- Rename field fee_recipient to validator_payout_address
- Added new api endpoint
POST /api/v1/user/payoutAddress - Removed api endpoint
POST /api/v1/builder/verify- Now user can use
POST /api/v1/builder/registerto register and verify builder public keys with signatures
- Now user can use
2025-06-26
- Update validator api
2025-06-18
- Update builder delegation api
2025-05-14
- Add validator fees payout api
- Add set User onchain_payout_enabled api
- Add contract address for different environments
2025-05-06
- Update withdraw api
- Rename
/api/v1/p/blockchainto/api/v1/p/network
2025-04-16
- Add user fees api
2025-04-02
- Mainnet v1 launched.
- Updated mainnet collateral deposit address
2025-03-28
- Updated get wholeblock and inclusion preconf markets API
2025-03-25
Updated Production Hoodi API and WS base url Updated testchain url for example usage Updated Validator API and User deposit collateral API
2025-03-15
- Updated Production Hoodi API and WS base url
- Updated testchain url for example usage
- Updated Validator API and User deposit collateral API
2025-02-21
- Update API naming. Added version control (v1)
2025-01-12
- Added block building api for submitting bundles
- Added get user validators api for retrieving a list of validators for the user
2024-12-01
- Updated RPC endpoint for Holesky chain
2024-10-01
- Ready for Testnet launch
INTRODUCTION
Welcome
ETHGas provides REST and WebSocket APIs for market data, orders, and account operations.
Code samples are HTTP and Python. Switch languages with the tabs at the upper right.
Support: info@ethgas.com or Telegram.
Environments
| Environment | Chain | RPC URL | Chain ID | API base URL | Websocket base URL | Collateral Contract |
|---|---|---|---|---|---|---|
| Mainnet | Ethereum Chain | https://eth.llamarpc.com | 1 | https://prod-mainnet.ethgas.com | wss://prod-mainnet.ethgas.com/ws | 0x3314Fb492a5d205A601f2A0521fAFbD039502Fc3 |
| Testnet | Hoodi Chain | https://ethereum-hoodi-rpc.publicnode.com | 560048 | https://hoodi.app.ethgas.com | wss://hoodi.app.ethgas.com/ws | 0x104Ef4192a97E0A93aBe8893c8A2d2484DFCBAF1 |
- Chain IDs are decimal. Hoodi is
560048(0x88BB0). - Mainnet RPC endpoints are listed at chainlist.org/chain/1.
Connecting to ETHGas
Set ETHGAS_BASE_URL from the table above. This example reads ETHGAS_PRIVATE_KEY from the environment. Use a signing service in production, and keep keys and tokens out of logs.
import json
import os
import requests
from eth_account import Account, messages
base_url = os.environ["ETHGAS_BASE_URL"].rstrip("/")
signer = Account.from_key(os.environ["ETHGAS_PRIVATE_KEY"])
session = requests.Session()
session.headers["User-Agent"] = "ethgas-docs-example/1.0"
def data_or_error(response):
response.raise_for_status()
if "application/json" not in response.headers.get("Content-Type", "").lower():
raise RuntimeError("Expected an application/json response")
body = response.json()
if not body.get("success"):
raise RuntimeError(f"ETHGas error {body.get('errorCode')}: {body.get('errorMsgKey')}")
return body["data"]
challenge = data_or_error(session.post(
base_url + "/api/v1/user/login", data={"addr": signer.address}, timeout=30
))
typed_data = json.loads(challenge["eip712Message"])
signed = signer.sign_message(messages.encode_typed_data(full_message=typed_data))
login = data_or_error(session.post(
base_url + "/api/v1/user/login/verify",
data={"addr": signer.address, "nonceHash": challenge["nonceHash"],
"signature": "0x" + bytes(signed.signature).hex()},
timeout=30,
))
access_token = login["accessToken"]["token"]
# Session retains the x_auth_refresh_token cookie from verification.
accounts = data_or_error(session.get(
base_url + "/api/v1/user/accounts",
headers={"Authorization": "Bearer " + access_token}, timeout=30
))
print(accounts)
# Use the same session/client context; an access bearer is not required here.
refreshed = data_or_error(session.post(base_url + "/api/v1/user/login/refresh", timeout=30))
access_token = refreshed["accessToken"]["token"]
# To log out later, POST /api/v1/user/logout with this session and bearer token.
This example signs in and loads your accounts. It does not place an order. Sign the EIP-712 message returned by login.
- Request a challenge.
-
Verify the signature. Send
data.accessToken.tokenasAuthorization: Bearer {{access_token}}. - Keep the
x_auth_refresh_tokencookie and refresh beforeexp.expis Unix time in seconds. Sign in again if refresh fails.
Market data under /api/v1/p/ is public. Login, verify, and refresh are public. Other /api/v1/ routes require a bearer token. A valid token still needs permission for the account you use.
For WebSocket, connect to the WebSocket base URL and send login with the access token. Units, pagination, and retries are in the Integration guide.
REST API
Response structure
A successful JSON response normally contains success: true and data. Application failures use success: false, errorCode and errorMsgKey. HTTP 200 alone does not mean the operation succeeded. Cancellation and withdrawal batches also require checking each item/result list.
| Name | Type | Presence / description |
|---|---|---|
| success | boolean | Present in application JSON responses. |
| data | object | Operation-specific payload. May be empty; some typed error responses omit it. |
| errorCode | integer | Application error code on failure; usually omitted on success. |
| errorMsgKey | string | Stable message key on failure; usually omitted on success. |
Optional fields are omitted when empty. Ignore response fields you do not use.
HTTP status
| Status | Meaning | What to do |
|---|---|---|
| 200 | Success, or an application error in the JSON body | Check success, then any per-item codes. |
| 400 | Invalid request | Correct the request. Validation uses code 23. An unsupported method uses 24. |
| 401 | Not signed in. Code 1, with WWW-Authenticate: Bearer
|
Refresh once, or sign in again. |
| 403 | Not permitted. Code 1
|
Use an account you are allowed to access. |
| 415 | Unsupported content type. Code 25
|
Use the content type shown for the endpoint. |
| 429 | Busy. Code 20
|
Wait for Retry-After, then retry a read. |
| 500 | Server error. Code 21
|
Look up the result before repeating a create, cancel, withdrawal, or bundle. |
| 503 | Unavailable. Code 20 or 26, with Retry-After
|
Retry a read after the delay. Look up a request whose result you did not receive. |
Check the HTTP status and Content-Type before parsing. A proxy or network error can return a non-JSON body.
Busy responses (429 and 503) include Retry-After and data.retryAfterSeconds, in seconds, plus X-Request-ID and data.requestId. An application error from an endpoint can omit those fields.
Example error. The HTTP status can be 200:
{"success":false,"errorCode":66,"errorMsgKey":"error.accountId.required","data":{}}
See Error Codes and the Integration guide.
Integration guide
Use this guide with the endpoint pages. It covers request format, units, pagination, and retries. Routes use the /api/v1 prefix. Read the changelog before upgrading a client.
Reference and examples
Follow the field names, units, and content type on each endpoint. The server can ignore a field it does not recognize, so check names against that page.
Accounts, markets, slots, and signatures in the examples are samples. Sign in, select your account and an open market, then check price and quantity against that market. Use Hoodi for testing. Submit your own signatures and signed transactions.
openapi-core.json covers authentication and order creation and cancellation. All other operations are described in this reference.
Request encoding
JSON operations require Content-Type: application/json and a JSON body. Query parameters do not replace that body.
Other POST operations accept URL-encoded form fields, as shown on the endpoint. Send tokens and signatures in the form body. Send GET parameters in the query string, and quote curl URLs that contain &.
Use JSON booleans true and false, and send amounts as decimal strings. Use the list format shown for that endpoint: a JSON array, or a comma-separated form or query value.
Types and units
| Concept | Format |
|---|---|
| Decimal amount or price | Decimal string. Trailing zeros may be omitted. Use decimal arithmetic. |
| Order price | ETH per gas, within the market minPrice, maxPrice, and priceStep. |
| Whole-block quantity |
1. |
| Inclusion quantity | Decimal gas quantity, within the market minimum, maximum, and step. |
| REST timestamps | Epoch milliseconds, unless the field gives another format. |
JWT iat and exp
|
Epoch seconds. |
Dashboard slotTime and paymentTime
|
UTC ISO-8601 with milliseconds, such as 2026-10-01T00:00:00.000Z. |
| Slot | Ethereum slot number. |
| Identifiers | Integers. Some values exceed the range JavaScript stores exactly, so use an integer-safe parser. |
| Optional fields | Omitted when empty. Send null only when the endpoint says to. |
| Hex values | Use the prefix and length given for the field. Dashboard history may omit 0x. |
Accounts
Omitting accountId on a private order or position list selects your preconf account. An account you name must be your own, or an account shared with you for reading. Orders and withdrawals use their own permissions.
On withdrawal history and status, a readable accountId limits the result to that account. Omitting it returns your own history. Deposit history is available to the wallet owner. Transaction lists may require accountId. Where a user setting uses the owner account, the endpoint says so.
Pagination and filters
Order lists page by order ID. The cursor is exclusive: ascending returns IDs above startId, and descending returns IDs below it. Keep the same filters and direction, and send the last returned ID as the next startId.
| List | Defaults |
|---|---|
| Private whole-block orders | Ascending, no cursor, limit 10, maximum 1000. |
| Private inclusion orders | Descending, no cursor, limit 10, maximum 1000. |
Private all-orders, both markets |
Ascending, no cursor, limit 10, maximum 1000. |
| Public order lists | Ascending, no cursor, limit 10, maximum 1000. |
| Private position lists | Descending, enable=true, limit 10, maximum 1000. The cursor is a slot. |
| Operator block and payment history |
limit 100, maximum 200, offset 0. A non-positive limit uses 100. A negative offset uses 0. |
Omit startId on the first page. Descending with startId=0 returns no orders.
For all-orders, hasNextPage is true when another matching order exists. nextCursor is the last order ID in that page. The last page has hasNextPage false and no nextCursor. Keep filters unchanged between pages, because the list can change.
done=true returns orders with status 10. It does not include every canceled or expired order. A request cannot ask for open orders and done orders together. The public whole-block parameter is onbook. Public inclusion lists and private order lists use onBook.
These order lists return HTTP 400 and error code 23 when limit is 0 or negative, and they cap a larger limit at 1000.
Block and payment history can change when a payment is updated. Keep the same filters, store each record once, and check totals again after you export.
Mutations, retries and idempotency
| Outcome | What to do |
|---|---|
| Read timeout, 429, or 503 | Wait, then retry with backoff. Follow Retry-After when the response includes it. |
| 400, 415, or a validation error | Correct the request before trying again. |
| 401 | Refresh the session once. Sign in again if refresh fails. |
HTTP 200 with success false |
Use errorCode. See Error Codes. |
| Failed cancellation item | Read each data.orders[].code. The response can still have success true. |
| Order timeout | Keep the same clientOrderId and look up the order before submitting again. |
| Withdrawal timeout or partial batch | Read both result lists, then look up the request IDs already sent. |
| Bundle timeout or replacement | Check the slot, account, and replacement UUID before submitting again. |
clientOrderId is 1 to 32 letters or digits (^[a-zA-Z0-9]{1,32}$). A value already in use returns error code 58. Look up the existing order when you receive that code. Withdrawals have no equivalent client request ID.
Some operations treat a missing field as a choice:
- Cancel-all with no
instrumentIdcancels that account’s orders on every instrument in the market. A value cancels one instrument. - Obol deregistration with no
publicKeysremoves every key registered for that operator. A list removes those keys. An empty string does not select this mode. - Bundle submission with no
txscancels the matching bundle. A transaction list submits that bundle. An empty array does not select cancel.
When the service is busy
A busy service returns HTTP 429 with error code 20, or HTTP 503 with error code 20 or 26. The response includes Retry-After and data.retryAfterSeconds, in seconds. Wait at least that long before retrying a read. If you did not receive the result of a create, cancel, withdrawal, or bundle request, look it up before sending it again.
These responses include X-Request-ID and data.requestId.
Authentication
Login accepts query parameters or form fields. The examples use form fields. The full sign-in flow is in Connecting to ETHGas. Each challenge is single-use. Sign the message returned by that call.
POST /api/v1/user/login
Public endpoint. Obtain a challenge to prove control of the EOA address. The name parameter is not supported here; use the profile update endpoint for a display name.
curl --request POST "$ETHGAS_BASE_URL/api/v1/user/login" \
--data-urlencode "addr=$ETHGAS_ADDRESS"
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| addr | YES | string | EOA address, 20-byte hex. |
Response Body
| Name | Type | Description |
|---|---|---|
| status | string |
verify when the challenge is ready. |
| eip712Message | string | JSON-encoded EIP-712 object. Parse this string once before signing the returned typed data unchanged. |
| nonceHash | string | Four-byte nonce hash in hex. Correlates this challenge with verification. |
An invalid address returns application code 100011. Verification rejects a used nonce (100012) or unknown nonce (100013). A successful challenge response is not an authenticated session.
POST /api/v1/user/login/verify
Public endpoint. Submit the signature for the returned challenge. User-Agent is required. The server sets the x_auth_refresh_token refresh cookie; retain it. The refresh token is not a field in the JSON response.
curl --request POST "$ETHGAS_BASE_URL/api/v1/user/login/verify" \
--header 'User-Agent: ethgas-docs-example/1.0' \
--cookie-jar ethgas-cookies.txt \
--data-urlencode "addr=$ETHGAS_ADDRESS" \
--data-urlencode "nonceHash=$ETHGAS_NONCE_HASH" \
--data-urlencode "signature=$ETHGAS_SIGNATURE"
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| addr | YES | string | EOA address used for the challenge. |
| nonceHash | YES | string | Value returned by login. |
| signature | YES | string | Hex EIP-712 signature for that challenge. |
| User-Agent | YES | header string | Preserve the same client context for refresh. |
Response Body
| Name | Type | Description |
|---|---|---|
| user | object | User details, including available accounts. |
| accessToken | object | Token object, not a bearer string. |
| accessToken.token | string | Value for the Authorization Bearer header. |
| accessToken.data | object | Decoded header and payload metadata. |
| accessToken.data.payload.iat | integer | JWT issue time, epoch seconds. |
| accessToken.data.payload.exp | integer | JWT expiry time, epoch seconds. |
Incorrect addresses/signatures/nonces can return HTTP 400 with an application error. Do not log the response token or cookie jar; treat both as credentials.
POST /api/v1/user/login/refresh
No access token is required. Send the refresh cookie from login, or send refreshToken in the form body. If you send both, the cookie is used. Use the same User-Agent as login. A different client or country can make refresh fail. The response contains a new access token. It does not contain a new refresh token.
curl --request POST "$ETHGAS_BASE_URL/api/v1/user/login/refresh" \
--header 'User-Agent: ethgas-docs-example/1.0' \
--cookie ethgas-cookies.txt
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| x_auth_refresh_token | ONE SOURCE | cookie string | Cookie retained from verification. |
| refreshToken | ONE SOURCE | form/query string | Alternative when no refresh cookie is available. Prefer a form body. |
| User-Agent | YES | header string | Required client context. |
Response Body
| Name | Type | Description |
|---|---|---|
| user | object | Current user details. |
| accessToken | object | Same token-object structure as verification; use accessToken.token. |
A missing refresh token returns HTTP 400 and code 100016. An invalid token or a different client returns 100018. An unknown session returns 100019. Sign in again after refresh fails.
POST /api/v1/user/logout
Requires the current access bearer and a refresh credential from cookie or form/query parameter. If both refresh sources are present, they must be identical; conflicting values produce code 100017. The refresh credential must belong to the current user. Successful logout removes the associated login session and clears the refresh cookie.
curl --request POST "$ETHGAS_BASE_URL/api/v1/user/logout" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--cookie ethgas-cookies.txt \
--cookie-jar ethgas-cookies.txt
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| x_auth_refresh_token | ONE SOURCE | cookie string | Refresh credential. |
| refreshToken | ONE SOURCE | form/query string | Alternative refresh credential; must match the cookie if both are sent. |
Response Body
{"success":true,"data":{}}
A missing or invalid refresh token returns an application error. Check success as well as the HTTP status. Logout ends the refresh session. An access token that was already issued remains valid until exp.
User
POST /api/v1/user/update
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/update?displayName=NewDisplayName"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/update"
payload = {
'displayName': 'NewDisplayName'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"user": {
"userId": 73,
"address": "0xcc8f16b4e20feb0e7eb5a4725451db6316afa8f",
"status": 1,
"userType": 1,
"userClass": 1,
"displayName": "XXXXX",
"payoutAddress": "0xde88f16b4e20feb0525289041db6316afa8f",
"locked": false,
"collateralPerSlot": "0",
"onchainPayout": true,
"accounts": [
{
"accountId": 2170,
"userId": 73,
"type": 1,
"name": "Current",
"status": 1,
"updateDate": 1751854737000
},
{
"accountId": 2171,
"userId": 73,
"type": 2,
"name": "InPreconf",
"status": 1,
"updateDate": 1751854737000
}
]
}
}
}
Update user display name.
Fails with USER_LOCKED if the user has locked their account (POST /api/v1/user/lock).
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| displayName | YES | String | Display name |
Response Body
| Name | Type | Description |
|---|---|---|
| user | object | Updated user object |
| └ userId | long | Unique user ID |
| └ address | string | User's wallet address |
| └ status | integer | User status (1 = active) |
| └ userType | integer | User type |
| └ userClass | integer | User class |
| └ displayName | string | User's display name |
| └ payoutAddress | string | User's payout address |
| └ locked | boolean | Whether the user has locked their account |
| └ collateralPerSlot | string | Collateral per slot amount |
| └ onchainPayout | boolean | Whether on-chain payout is enabled |
| └ accounts | object[] | List of user accounts |
| └└ accountId | long | Unique account ID |
| └└ userId | long | User ID associated with the account |
| └└ type | integer | Account type |
| └└ name | string | Account name |
| └└ status | integer | Account status |
| └└ updateDate | long | Last update timestamp in milliseconds |
Error Codes
| Code | Description |
|---|---|
| USER_LOCKED | User account is locked |
POST /api/v1/user/lock
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/lock"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/lock"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Permanently lock the authenticated user. This cannot be undone through the API. After lock, login, trading, deposits, and reads still work. The following user updates are rejected with USER_LOCKED:
POST /api/v1/user/updatePOST /api/v1/user/payoutAddressPOST /api/v1/user/funding/withdrawPOST /api/v1/validator/mode/enablePOST /api/v1/ssv/validator/mode/enablePOST /api/v1/obol/validator/mode/enable- Regular, SSV, and Obol validator payout-address updates
To unlock an account, contact ETHGas. Unlock is not available in the API.
Request
No parameters required.
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
POST /api/v1/user/payoutAddress
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/payoutAddress?payoutAddress=0x1234567890123456789012345678901234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/payoutAddress"
payload = {
'payoutAddress': '0x1234567890123456789012345678901234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Update user payout address.
Fails with USER_LOCKED if the user has locked their account.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| payoutAddress | YES | String | New payout address (hex format) |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Error Codes
| Code | Description |
|---|---|
| USER_LOCKED | User account is locked |
GET /api/v1/user/info
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/info"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/info"
payload = {}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"user": {
"userId": 73,
"address": "0xcc8f16b4e20feb0e7eb5a4725451db6316afa8f",
"status": 1,
"userType": 1,
"userClass": 1,
"displayName": "XXXXX",
"payoutAddress": "0xde88f16b4e20feb0525289041db6316afa8f",
"locked": false,
"collateralPerSlot": "0",
"onchainPayout": true,
"accounts": [
{
"accountId": 2170,
"userId": 73,
"type": 1,
"name": "Current",
"status": 1,
"updateDate": 1751854737000
},
{
"accountId": 2171,
"userId": 73,
"type": 2,
"name": "InPreconf",
"status": 1,
"updateDate": 1751854737000
}
]
}
}
}
Get user information.
Request
No parameters required.
Response Body
| Name | Type | Description |
|---|---|---|
| user | object | User object |
| └ userId | long | Unique user ID |
| └ address | string | User's wallet address |
| └ status | integer | User status (1 = active) |
| └ userType | integer | User type |
| └ userClass | integer | User class |
| └ displayName | string | User's display name |
| └ payoutAddress | string | User's payout address |
| └ locked | boolean | Whether the user has locked their account |
| └ collateralPerSlot | string | Collateral per slot amount |
| └ onchainPayout | boolean | Whether on-chain payout is enabled |
| └ accounts | object[] | List of user accounts |
| └└ accountId | long | Unique account ID |
| └└ userId | long | User ID associated with the account |
| └└ type | integer | Account type |
| └└ name | string | Account name |
| └└ status | integer | Account status |
| └└ updateDate | long | Last update timestamp in milliseconds |
Account
GET /api/v1/user/accounts
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/accounts"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/accounts"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"accounts": [
{
"accountId": 127,
"userId": 31,
"type": 1,
"name": "Current",
"status": 1,
"updateDate": 1672903708000,
"tokens": [
{
"accountId": 127,
"tokenId": 1,
"quantity": "0.01",
"lockedQuantity": "0",
"code": "ETH",
"availableQuantity": "0.01"
}
]
},
{
"accountId": 128,
"userId": 31,
"type": 2,
"name": "Preconf Account",
"status": 1,
"updateDate": 1697445293000,
"tokens": [
{
"accountId": 128,
"tokenId": 1,
"quantity": "9999993311.535880667",
"lockedQuantity": "1.5628",
"code": "ETH",
"availableQuantity": "9999993309.973080667"
}
]
}
]
}
}
Get list of user accounts.
Request
No parameters for this endpoint.
Response Body
| Name | Type | Description |
|---|---|---|
| accounts | arrary of object | List of account objects |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ userId | integer | Unique ID for the user, assigned by ETHGas |
| └ type | integer | Account type: 1 for current account 2 for preconf trading account |
| └ name | string | Account name Default values are "Current" and "Trading" |
| └ status | integer | Account status: All active accounts have status 1 |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) the healthscoare and other risk metrics (asset amount, liability amount, etc) were last calculated |
| └ tokens | object[] | List of tokens in account |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ tokenId | integer | ETHGas Token ID See Token IDs section for list of Token IDs |
| └ quantity | string | Amount of token in account in USD |
| └ lockedQuantity | string | Amount of token in account in USD which is covering pending limit orders (and so cannot be transfered out of account) |
| └ code | string | Token code See Token IDs section for list of token codes |
| └ tokenType | integer | Token type: Currently all tokens at ETHGas are designated as type 1 |
| └ valueType | integer | Value type: 1 for non-stablecoin tokens 2 for stablecoin tokens |
| └ tokenValuationProtocol | integer | Platform the complex token comes from (if relevant): |
| └ availableQuantity | string | Available quantity for using as collateral for buying or for transfering out of the account: Available Quantity = Quantity - Locked Quantity |
GET /api/v1/user/account/{id}
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/account/128"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/account/128"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"account": {
"accountId": 128,
"userId": 31,
"type": 2,
"name": "Trading",
"status": 1,
"updateDate": 1697445293000,
"tokens": [
{
"accountId": 128,
"tokenId": 1,
"quantity": "9999993308.004503191",
"lockedQuantity": "0",
"code": "ETH",
"tokenType": 1,
"valueType": 1,
"tokenValuationProtocol": 0,
"availableQuantity": "9999993308.004503191"
}
]
}
}
}
Get account details for a given account ID.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| id | YES | integer | Account ID |
Response Body
| Name | Type | Description |
|---|---|---|
| account | object | Account object |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ userId | integer | Unique ID for the user, assigned by ETHGas |
| └ type | integer | Account type: 1 for current account 2 for trading account |
| └ name | string | Account name Default values are "Current" and "Trading". |
| └ status | integer | Account status: All active accounts have status 1 |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) the healthscoare and other risk metrics (asset amount, liability amount, etc) were last calculated. |
| └ tokens | object[] | List of tokens in account |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ tokenId | integer | ETHGas Token ID See Token IDs section for list of Token IDs |
| └ quantity | string | Amount of token in account in USD |
| └ lockedQuantity | string | Amount of token in account in USD which is covering pending limit orders (and so cannot be transfered out of account) |
| └ code | string | Token code See Token IDs section for list of token codes |
| └ tokenType | integer | Token type: Currently all tokens at ETHGas are designated as type 1 |
| └ valueType | integer | Value type: 1 for non-stablecoin tokens 2 for stablecoin tokens |
| └ tokenValuationProtocol | integer | Platform the complex token comes from (if relevant): |
| └ availableQuantity | string | Available quantity for using as collateral for buying or for transfering out of the account: Available Quantity = Quantity - Locked Quantity |
GET /api/v1/user/account/{id}/txs
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/account/128/txs"
import requests
account_id = 128
url = "https://prod-mainnet.ethgas.com/api/v1/user/account/{account_id}/txs"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"txs": [
{
"trxId": 507873974,
"accountId": 128,
"tokenId": 1,
"type": 15,
"quantity": "-0.141865",
"balance": "10010502890.372428552",
"createDate": 1697450286000
},
{
"trxId": 507873973,
"accountId": 128,
"tokenId": 1,
"type": 2,
"quantity": "-1418.65",
"balance": "10010502890.514293552",
"createDate": 1697450286000
},
{
"trxId": 507873970,
"accountId": 128,
"tokenId": 1,
"type": 15,
"quantity": "-0.00009848",
"balance": "9999993308.350858416",
"createDate": 1697450286000
},
{
"trxId": 507873969,
"accountId": 128,
"tokenId": 1,
"type": 2,
"quantity": "-0.9848",
"balance": "9999993308.350956896",
"createDate": 1697450286000
},
{
"trxId": 507873966,
"accountId": 128,
"tokenId": 1,
"type": 15,
"quantity": "-0.00008252",
"balance": "9999993309.335674376",
"createDate": 1697450286000
},
{
"trxId": 507873965,
"accountId": 128,
"tokenId": 1,
"type": 2,
"quantity": "0.8252",
"balance": "9999993309.335756896",
"createDate": 1697450286000
}
]
}
}
Get account transactions for a given account ID.
Request
This is an authenticated endpoint. Include Authorization: Bearer {{access_token}}.
| Parameter | Required | Type | Description |
|---|---|---|---|
| id | YES | integer | Account ID |
| type | NO | string | Transaction type (comma-separated for multiple types) |
| startId | NO | integer | Start of transaction ID |
| limit | NO | integer | Max number of transactions to return |
Response Body
| Name | Type | Description |
|---|---|---|
| txs | object[] | List of transaction objects |
| └ trxId | integer | Unique ID for the transaction, assigned by ETHGas |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ tokenId | integer | ETHGas Token ID See Token IDs section for list of Token IDs |
| └ type | integer | Transaction type See Transaction Types section for full list |
| └ quantity | string | Transaction quantity |
| └ balance | string | Balance of account after transaction |
| └ createDate | integer | Transaction datetime stamp (in UNIX time) |
GET /api/v1/user/account/txs
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/account/txs"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/account/txs"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"txs": [
{
"trxId": 507873974,
"accountId": 128,
"tokenId": 1,
"type": 15,
"quantity": "-0.141865",
"balance": "10010502890.372428552",
"createDate": 1697450286000
}
]
}
}
Get account transactions for the current user.
Request
This is an authenticated endpoint. Include Authorization: Bearer {{access_token}}.
| Parameter | Required | Type | Description |
|---|---|---|---|
| type | NO | string | Transaction type (comma-separated for multiple types) |
| startId | NO | integer | Start of transaction ID |
| limit | NO | integer | Max number of transactions to return (default: 20, max: 100) |
Response Body
| Name | Type | Description |
|---|---|---|
| txs | object[] | List of transaction objects |
| └ trxId | integer | Unique ID for the transaction, assigned by ETHGas |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ tokenId | integer | ETHGas Token ID See Token IDs section for list of Token IDs |
| └ type | integer | Transaction type See Transaction Types section for full list |
| └ quantity | string | Transaction quantity |
| └ balance | string | Balance of account after transaction |
| └ createDate | integer | Transaction datetime stamp (in UNIX time) |
GET /api/v1/user/account/trxs
Unified account-related activity for the current user (trade, deposit, withdraw, transfer, slashing categories). Unrecognized category values return a SYSTEM_VALIDATION error.
Request
Authenticated. Query parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
| categories | NO | string | Comma-separated categories (preferred). Same semantics as category when both are used—categories wins if non-blank. |
| category | NO | string | One category. When categories is also set, categories is used. |
| startId | NO | long | Pagination cursor |
| limit | NO | integer | Page size (default 50, max 1000) |
Response Body
| Name | Type | Description |
|---|---|---|
| accountTrxs | object[] | List of transaction/activity records across the requested categories |
POST /api/v1/user/account/transfer/token
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/account/transfer/token?fromAccountId=128&toAccountId=127&tokenId=1&quantity=0.01"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/account/transfer/token"
params = {
"fromAccountId": 128,
"toAccountId": 127,
"tokenId": 1,
"quantity": 0.01
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Transfer token between accounts.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| fromAccountId | YES | integer | Source account ID |
| toAccountId | YES | integer | Destination account ID |
| tokenId | YES | integer | Token ID |
| quantity | YES | number | Quantity |
Response Body
| Name | Type | Description |
|---|
Funding
GET /api/v1/p/funding/contractAddress
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/funding/contractAddress"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/funding/contractAddress"
response = requests.get(url)
print(response.text)
Example response:
{
"success": true,
"data": {
"contractAddress": "0x818EF032D736B1a2ECC8556Fc1bC65aEBD8482c5"
}
}
Get deposit collateral address.
Request
| Parameter | Required | Type | Description |
|---|
Response Body
| Name | Type | Description |
|---|---|---|
| contractAddress | string | deposit collateral address 0x818EF032D736B1a2ECC8556Fc1bC65aEBD8482c5 |
GET /api/v1/user/funding/deposits
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/funding/deposits"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/funding/deposits"
payload = {}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"deposits": [
{
"eventId": 6,
"chainId": 1,
"blockIdx": 123456,
"blockHash": "0xdd5a8e1742e26ce90feb865f1c6a0fdbf2d8cbed086314fc85281ff47aaea5ee",
"transactionIdx": 2,
"transactionHash": "0x866bb046a97243519679183e08e5ce6728d3e1e9976a2535ce8c8887b62997a2",
"logIdx": 2,
"senderAddress": "0xd055335192d920ce2de4a88557f232943a901a9f",
"depositAddress": "0xd055335192d920ce2de4a88557f232943a901a9f",
"status": 10,
"deposits": [
{
"a": "0xdc0b8e3cd3fec447940cb8107957f22e7e320812",
"q": 500000000000000000,
"s": 10
}
],
"actions": [],
"createDate": 1746005076000
}
]
}
}
Get fund deposits history.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| limit | NO | integer | Maximum number of deposits to return |
| startBlockId | NO | integer | Block start ID |
Response Body
| Name | Type | Description |
|---|---|---|
| deposits | object[] | List of deposits |
| └ eventId | long | Unique ID for the deposit event |
| └ chainId | integer | Unique ID for the chain, assigned by ETHGas: Currently only Ethereum (Chain ID 1) is supported. |
| └ blockIdx | long | Block ID |
| └ blockHash | byte[] | Block hash |
| └ transactionIdx | long | Transaction ID |
| └ transactionHash | byte[] | Transaction hash |
| └ logIdx | integer | Log ID |
| └ senderAddress | string | Sender address |
| └ depositAddress | string | Deposit address |
| └ status | integer | Deposit status, success = 10 |
| └ deposits | object[] | Deposits |
| └ actions | string | Actions |
| └ createDate | date | create date |
Deposit history is owner-only and remains scoped to the authenticated user’s wallet. Optional accountId must belong to that user; a shared read grant does not authorize deposit history and returns COMMON_NO_ACCOUNT. Omission reads the current user’s wallet history. Lists default to 20 rows and cap at 1000; send a positive limit.
POST /api/v1/user/funding/withdraw
Code sample:
curl -X POST "$ETHGAS_BASE_URL/api/v1/user/funding/withdraw"
[
{
"accountId": 12,
"tokenId": 1,
"chainId": 1,
"quantity": "0.05"
},
{
"accountId": 12,
"tokenId": 2,
"chainId": 1,
"quantity": "0.001"
}
]
import requests
import json
url = "https://prod-mainnet.ethgas.com/api/v1/user/funding/withdraw"
payload = json.dumps([
{
"accountId": 12,
"tokenId": 1,
"chainId": 1,
"quantity": "0.05"
}
])
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, data=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"submittedRequestIds": [
4
],
"failedRequests": [
{
"accountId": 21,
"tokenId": 1,
"chainId": 32382,
"quantity": "0.001",
"status": 101,
"remark": "Unsupported Chain ID."
}
]
}
}
Request to withdraw funds.
Fails with USER_LOCKED if the user has locked their account.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| requests | YES | object[] | List of withdraw requests |
| └ accountId | YES | integer | Account ID |
| └ chainId | YES | integer | Chain ID |
| └ tokenId | YES | integer | Token ID |
| └ quantity | YES | string | Quantity to be withdrawn |
Response Body
| Name | Type | Description |
|---|---|---|
| submittedRequestIds | integer[] | List of successful submitted request IDs |
| failedRequests | object[] | List of failed submitted requests with reason. |
| └ accountId | integer | Account ID |
| └ chainId | integer | Chain ID |
| └ tokenId | integer | Token ID |
| └ fee | string | Token ID |
| └ quantity | string | Quantity to be withdrawn |
| └ status | integer | Status of submitted withdraw request |
| └ remark | string | Reason of failed request. |
Error Codes
| Code | Description |
|---|---|
| USER_LOCKED | User account is locked |
Withdrawal acceptance and settlement
Send a JSON array. Each item contains accountId, tokenId, chainId, and quantity. ETH is tokenId 1 on the chain for your environment. quantity is a positive decimal string and must be greater than the withdrawal fee. The amount credited is quantity minus the fee.
success true can still include both submittedRequestIds and failedRequests. A submitted request is not yet settled on chain. Check both lists, then call withdrawal status for the accepted IDs. After a timeout, look up the IDs you already sent before submitting the batch again.
The daily limit is a rolling 24-hour total for the token and network.
| Status | Meaning |
|---|---|
| 0 | Engine submitted. |
| 1 | Pending withdrawal. |
| 2 | Submitted to blockchain. |
| 10 | Successful. |
| 11 | Insufficient funds. |
| 12 | Insufficient on-chain balance. |
| 99 | On-chain failure. |
| 100 | Canceled. |
| 101 | Rejected. |
GET /api/v1/p/funding/withdraw/dailyWithdrawLimits
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/funding/withdraw/dailyWithdrawLimits"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/funding/withdraw/dailyWithdrawLimits"
response = requests.get(url)
print(response.text)
Example response:
{
"success": true,
"data": {
"dailyWithdrawLimits": [
{
"tokenId": 1,
"chainId": 1,
"tokenAddress": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"withdrawFee": "0.01",
"dailyWithdrawLimit": "50",
"remainingWithdrawLimit": "49.863"
}
]
}
}
Get list of token's current on-chain daily withdraw limits
Request
| Parameter | Required | Type | Description |
|---|
Response Body
| Name | Type | Description |
|---|---|---|
| Name | Type | Description |
| ----------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| dailyWithdrawLimits | object[] | Block chain details |
| └ tokenId | integer | Unique ID for the blockchain network assigned by ETHGas, assigned by ETHGas: Currently only Ethereum (Chain ID 1) is supported. |
| └ chainId | integer | Unique ID for the chain: Currently only Ethereum (Chain ID 1) is supported. |
| └ tokenAddress | string | Address of ERC-20 token contract (e.g. WETH) |
| └ withdrawFee | string | Withdrawal fee. |
| └ dailyWithdrawLimit | string | Daily withdraw limit of ERC-20 token |
| └ remainingWithdrawLimit | integer | remaining withdraw limit in past 24 hours. |
GET /api/v1/user/funding/withdraw/status
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/funding/withdraw/status?requestIds=123%2c456"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/funding/withdraw/status?requestIds=123,456"
params = {
'requestIds': '123,456'
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"requests": [
{
"requestId": 16,
"userId": 17,
"accountId": 15,
"tokenId": 1,
"chainId": 17000,
"quantity": "0.005",
"fee": "0.001",
"status": 10,
"txHash": "0x4de9ecf18ea11d8d290a01e759f3b150809f70cccb08bb74ceede7a801e2e9a5",
"createDate": 1746161880000,
"updateDate": 1746162105000
},
{
"requestId": 15,
"userId": 17,
"accountId": 15,
"tokenId": 1,
"chainId": 17000,
"quantity": "0.005",
"fee": "0.001",
"status": 10,
"txHash": "0xba85584d93dd7a209838308a767c9848535d0ada4f83c17526147f9c74104edd",
"createDate": 1746160279000,
"updateDate": 1746160538000
}
]
}
}
Get fund withdrawal request status (for given list of request IDs).
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| requestIds | YES | integer[] | List of fund withdrawal request IDs |
Response Body
| Name | Type | Description |
|---|---|---|
| requests | object[] | List of withdraw requests with status |
| └ requestId | integer | Request ID |
| └ userId | integer | User ID |
| └ accountId | integer | Account ID |
| └ chainId | integer | Chain ID |
| └ tokenId | integer | Token ID |
| └ fee | string | Token ID |
| └ quantity | string | Quantity to be withdrawn |
| └ status | integer | Status of submitted withdraw request |
| └ quantity | string | Quantity to be withdrawn |
| └ txHash | string | Transaction hash of submitted withdraw transaction |
| └ createDate | string | Create date |
| └ updateDate | string | Last update date |
Optional accountId (integer) requires ownership/shared-read authorization and filters requested withdrawal IDs strictly to that account. IDs belonging to another account are omitted. Without accountId, only requests belonging to the authenticated user are returned.
GET /api/v1/user/funding/withdraws
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/funding/withdraws"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/funding/withdraws"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"requests": [
{
"requestId": 16,
"userId": 17,
"accountId": 15,
"tokenId": 1,
"chainId": 17000,
"quantity": "0.005",
"fee": "0.001",
"status": 10,
"txHash": "0x4de9ecf18ea11d8d290a01e759f3b150809f70cccb08bb74ceede7a801e2e9a5",
"createDate": 1746161880000,
"updateDate": 1746162105000
},
{
"requestId": 15,
"userId": 17,
"accountId": 15,
"tokenId": 1,
"chainId": 17000,
"quantity": "0.005",
"fee": "0.001",
"status": 10,
"txHash": "0xba85584d93dd7a209838308a767c9848535d0ada4f83c17526147f9c74104edd",
"createDate": 1746160279000,
"updateDate": 1746160538000
}
]
}
}
Get list of fund withdrawals.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| limit | NO | integer | Maximum number of withdrawals to return |
| startId | NO | integer | Fund withdrawal request start ID |
Response Body
| Name | Type | Description |
|---|---|---|
| requests | object[] | List of withdraw requests |
| └ requestId | integer | Request ID |
| └ userId | integer | User ID |
| └ accountId | integer | Account ID |
| └ chainId | integer | Chain ID |
| └ tokenId | integer | Token ID |
| └ fee | string | Token ID |
| └ quantity | string | Quantity to be withdrawn |
| └ status | integer | Status of submitted withdraw request |
| └ quantity | string | Quantity to be withdrawn |
| └ txHash | string | Transaction hash of submitted withdraw transaction |
| └ createDate | string | Create date |
| └ updateDate | string | Last update date |
Optional accountId (integer) filters results strictly to that account after ownership/shared-read authorization. No sibling-account records are included. Omission returns only the current user’s own withdrawal history. Lists default to 20 rows and cap at 1000; send a positive limit.
Network
GET /api/v1/p/network
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/network"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/network"
params = {
'chainId': 1
}
headers = {}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"network": {
"networkId": 1,
"chainId": 11155111,
"name": "Ethereum",
"enable": true,
"visible": true
}
}
}
Get network details for a given blockchain ID.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| chainId | YES | integer | Chain ID |
Response Body
| Name | Type | Description |
|---|---|---|
| network | object | Block chain details |
| └ networkId | integer | Unique ID for the blockchain network assigned by ETHGas, assigned by ETHGas: Currently only Ethereum (Chain ID 1) is supported. |
| └ chainId | integer | Unique ID for the chain: Currently only Ethereum (Chain ID 1) is supported. |
| └ name | string | Name of the blockchain network (e.g. Ethereum) |
| └ enable | boolean | Whether this chain is enabled within ETHGas: This should always return true. |
| └ visible | boolean | Whether this chain is visible on ETHGas: This should always return true. |
Tokens
GET /api/v1/p/tokens
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/tokens"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/tokens"
headers = {}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"tokens": [
{
"tokenId": 1,
"code": "ETH",
"name": "Wrapped ETH",
"tokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"decimals": 18,
"nativeToken": false,
"withdrawFee": "0.01",
"price": "1582.09761118"
}
]
}
}
Get details for all tokens.
Request
No parameters for this endpoint.
Response Body
| Name | Type | Description |
|---|---|---|
| tokens | object[] | List of token objects |
| └ tokenId | integer | ETHGas Token ID See Token IDs section for list of Token IDs |
| └ code | string | Token code See Token IDs section for list of token codes |
| └ name | string | Token code See Token IDs section for list of token names |
| └ tokenAddress | string | Token chain address |
| └ decimals | integer | Number of decimal precision for this token |
| └ withdrawFee | string | Withdrawal fee (in number of tokens) |
| └ price | string | Latest token price |
Fees
GET /api/v1/p/user/fees
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/user/fees"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/user/fees"
headers = {}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"buyFeeRate": "0.01",
"primarySellFeeRate": "0.045",
"secondarySellFeeRate": "0.05"
}
}
Get current trading fees
Request
| Parameter | Required | Type | Description |
|---|
Response Body
| Name | Type | Description |
|---|---|---|
| buyFeeRate | BigDecimal | Percentage fees charged for buy transaction |
| primarySellFeeRate | BigDecimal | Percentage fees charged for first time sell transaction |
| secondarySellFeeRate | BigDecimal | Percentage fees charged for subsequent sell transaction |
Whole Block Markets
GET /api/v1/p/wholeblock/markets
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/wholeblock/markets"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/wholeblock/markets"
headers = {}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"markets": [
{
"marketId": 2000000295209,
"slot": 295209,
"instrumentId": "ETH-WB-295209",
"name": "ETH Whole Block Slot #295209",
"priceStep": "0.00000000001",
"minPrice": "0.00000000001",
"maxPrice": "0.00001",
"bestBid": "0.00000000540",
"availablePreconf": 17257755,
"direction": true,
"price": "0.00000000588",
"midPrice": "0.00000000564",
"status": 1,
"maturityTime": 1751947307000,
"blockTime": 1751947311000,
"finalityTime": 1751948079000,
"ofac": false,
"realtime": false,
"tradingEnabled": true,
"mode": 0,
"multiRelay": true,
"updateDate": 1751947297000
},
{
"marketId": 2000000295211,
"slot": 295211,
"instrumentId": "ETH-WB-295211",
"name": "ETH Whole Block Slot #295211",
"priceStep": "0.00000000001",
"minPrice": "0.00000000001",
"maxPrice": "0.00001",
"availablePreconf": 16587826,
"direction": true,
"price": "0.00000000581",
"midPrice": "0.00000000580",
"status": 1,
"maturityTime": 1751947331000,
"blockTime": 1751947335000,
"finalityTime": 1751948103000,
"ofac": false,
"realtime": true,
"tradingEnabled": true,
"mode": 0,
"multiRelay": false,
"updateDate": 1751947297000
}
]
}
}
Get active all whole block market details.
Request
| Parameter | Required | Type | Description |
|---|
Response Body
| Name | Type | Description |
|---|---|---|
| markets | object[] | List of Whole Block Market objects |
| └ marketId | integer | Whole block market ID |
| └ slot | integer | Slot number of the block |
| └ instrumentId | string | Whole block market instrument ID Use endpoint [GET /api/v1/p/wholeblock/markets] to get a list of all available wholeblock markets' instrument IDs |
| └ name | string | Whole block market display name In format: "ETH Whole Block Slot #<slot>" |
| └ priceStep | string | Minimum increment between valid price levels |
| └ minPrice | string | Minimum price |
| └ maxPrice | string | Maximum price |
| └ bestBid | string | Current best bid price on the market |
| └ availablePreconf | integer | Available preconf quantity for trading |
| └ direction | boolean | The last trading direction (true = buy, false = sell) |
| └ price | string | Latest traded market price for this market |
| └ midPrice | string | Mid price derived from the current market quote |
| └ status | integer | Market status - see the Market Status Codes section for more information |
| └ maturityTime | integer | Datetime (Unix epoch milliseconds) when the market will be closed |
| └ blockTime | integer | Datetime (Unix epoch milliseconds) when the block starts |
| └ finalityTime | integer | Datetime (Unix epoch milliseconds) when the block is being finalized |
| └ ofac | boolean | Whether the market is flagged for OFAC-compliant builder routing |
| └ realtime | boolean | Whether the market is running in realtime mode |
| └ tradingEnabled | boolean | Whether trading is currently enabled for this market |
| └ mode | integer | Mode when the market was created. 0 is max-profit. 1 is light mode. |
| └ multiRelay | boolean | Whether this market is configured to use multi-relay |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) when the market orderbook was last updated |
GET /api/v1/p/wholeblock/market
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/wholeblock/market?slot=295209"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/wholeblock/market"
params = {"slot": 295209}
response = requests.get(url, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"markets": {
"marketId": 2000000295209,
"slot": 295209,
"instrumentId": "ETH-WB-295209",
"name": "ETH Whole Block Slot #295209",
"priceStep": "0.00000000001",
"minPrice": "0.00000000001",
"maxPrice": "0.00001",
"bestBid": "0.00000000540",
"availablePreconf": 17257755,
"direction": true,
"price": "0.00000000588",
"midPrice": "0.00000000564",
"status": 1,
"maturityTime": 1751947307000,
"blockTime": 1751947311000,
"finalityTime": 1751948079000,
"ofac": false,
"realtime": false,
"tradingEnabled": true,
"mode": 0,
"multiRelay": true,
"updateDate": 1751947297000
}
}
}
Get whole block market details for a specific slot.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| slot | YES | integer | Slot number of the block |
Response Body
| Name | Type | Description |
|---|---|---|
| markets | object | Whole Block Market object (same shape as an entry in GET /api/v1/p/wholeblock/markets) |
GET /api/v1/p/wholeblock/positions
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/wholeblock/positions?instrumentId=ETH-WB-9884031&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/wholeblock/positions"
params = {
"instrumentId": "ETH-WB-9884031",
"limit": 10
}
response = requests.get(url, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"positions": [
{
"slot": 296895,
"quantity": "1",
"locked": "0",
"expired": false,
"updateDate": 1751967044730,
"available": "1",
"averagePrice": "0.0000000058"
}
]
}
}
Get whole block positions.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| instrumentId | NO | string | Instrument ID |
| limit | NO | integer | Maximum Number of Positions To Return (default: 10) |
Response Body
| Name | Type | Description |
|---|---|---|
| positions | object[] | List of position object |
| └ slot | integer | Slot number of the block |
| └ quantity | string | Position quantity |
| └ available | string | Position quantity available for trading |
| └ locked | string | Locked quantity |
| └ expired | boolean | Position expired or not |
| └ averagePrice | string | Average price of executed trades |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) when the order was last updated |
GET /api/v1/p/wholeblock/orders
See pagination: omit startId for the first page in either direction. Supplied cursors are exclusive. done=true selects only status 10.
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/wholeblock/orders?instrumentId=ETH-WB-9884031&onbook=false&done=false&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/wholeblock/orders"
params = {
"instrumentId": "ETH-WB-9884031",
"onbook": False,
"done": False,
"limit": 10
}
response = requests.get(url, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"orders": [
{
"orderId": 8522999,
"marketId": 2000000160031,
"side": false,
"orderType": 2,
"quantity": "1",
"fulfilled": "1",
"price": "0.00000000569",
"fees": "0.0091793925",
"status": 10,
"clientOrderId": "b0eeb664",
"passive": false,
"createDate": 1750324420793,
"source": 1,
"updateDate": 1750324423349,
"instrumentId": "ETH-WB-160031"
},
{
"orderId": 8523033,
"marketId": 2000000160031,
"side": true,
"orderType": 2,
"quantity": "1",
"fulfilled": "1",
"price": "0.00000000591",
"fees": "0.002039865",
"status": 10,
"clientOrderId": "b274e878",
"passive": false,
"createDate": 1750324423349,
"source": 1,
"updateDate": 1750324423349,
"instrumentId": "ETH-WB-160031"
}
]
}
}
Get whole block orders.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| instrumentId | YES | string | List whole block Orders for a market |
| onbook | NO | boolean | Pending Orders Only? (default: false) |
| done | NO | boolean | Done Orders Only? (default: false) |
| startId | NO | integer | Exclusive order cursor; omitted for the first page |
| asc | NO | boolean | Sort Order Direction, true=asc, false=desc, Default to true=asc |
| limit | NO | integer | Maximum number of orders to return (default: 10; must be positive; cap: 1000) |
Response Body
| Name | Type | Description |
|---|---|---|
| orders | object[] | List of order object |
| └ orderId | integer | Unique order ID, assigned by ETHGas |
| └ marketId | integer | Market ID for this order |
| └ instrumentId | string | Whole block market instrument ID |
| └ side | boolean | buy order (true) or sell order (false) |
| └ orderType | integer | Market (1), limit (2), or FOK (3) |
| └ quantity | string | Order quantity (1 for whole block orders) |
| └ fulfilled | string | Quantity that has already been executed |
| └ price | string | Price of the order |
| └ fees | string | Fees charged for this order |
| └ status | integer | Order status - see the Order Status Codes section for more information |
| └ errorCode | integer | Error code if order failed (omitted if absent) |
| └ clientOrderId | string | Client order ID: 1–32 ASCII letters/digits, matching ^[a-zA-Z0-9]{1,32}$
|
| └ passive | boolean | Whether the order is a maker order only |
| └ createDate | integer | Datetime (Unix epoch milliseconds) when the order was created |
| └ source | integer | Where the order is originated |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) when the order was last updated |
GET /api/v1/p/wholeblock/trades
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/wholeblock/trades?instrumentId=ETH-WB-9884031&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/wholeblock/trades"
params = {
"instrumentId": "ETH-WB-9884031",
"limit": 10
}
response = requests.get(url, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"trades": [
{
"instrumentId": "ETH-WB-9884031",
"trxId": 11675386,
"side": false,
"price": "0.00000002",
"quantity": "1",
"preconfQuantity": "320000000",
"date": 1730269305359
},
{
"instrumentId": "ETH-WB-9884031",
"trxId": 2146182,
"side": false,
"price": "0.00000000568",
"quantity": "1",
"preconfQuantity": "19005872",
"date": 1750299601863
}
]
}
}
Get whole block trades.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| instrumentId | YES | string | List whole block trades for a market |
| limit | NO | integer | Maximum Number of Trades To Return (default: 10) |
Response Body
| Name | Type | Description |
|---|---|---|
| trades | object[] | List of trades |
| └ instrumentId | string | Whole block market instrument ID |
| └ trxId | integer | Transaction Id |
| └ side | boolean | Order Side. Buy = true, Sell = false |
| └ price | string | Latest traded market price for this market |
| └ quantity | string | Quantity always = 1 |
| └ preconfQuantity | string | Preconf quantity sold with the whole block |
| └ date | integer | Datetime (Unix epoch milliseconds) when the trade was executed |
Inclusion Preconf Markets
GET /api/v1/p/inclusion-preconf/markets
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/inclusion-preconf/markets"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/inclusion-preconf/markets"
headers = {}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"markets": [
{
"marketId": 1000000295045,
"slot": 295045,
"instrumentId": "ETH-PC-295045",
"name": "Eth Preconf Inclusion Slot #295045",
"quantityStep": "1",
"minQuantity": "1",
"maxQuantity": "35850000",
"priceStep": "0.00000000001",
"minPrice": "0.00000000001",
"maxPrice": "0.00001",
"bestBid": "0.00000000015",
"totalPreconf": 35850000,
"availablePreconf": 19678280,
"direction": true,
"price": "0.00000000002",
"midPrice": "0.00000000015",
"status": 1,
"maturityTime": 1751945339000,
"trxSubmitTime": 1751945341000,
"blockTime": 1751945343000,
"finalityTime": 1751946111000,
"totalGas": 16171720,
"validatorType": 0,
"mode": 0,
"updateDate": 1751945326000
},
{
"marketId": 1000002880222,
"slot": 2880222,
"instrumentId": "ETH-PC-2880222",
"name": "Eth Preconf Inclusion Slot #2880222",
"quantityStep": "1",
"minQuantity": "1",
"maxQuantity": "30000000",
"priceStep": "0.00000000001",
"minPrice": "0.00000000001",
"maxPrice": "0.00001",
"collateralPerSlot": "2",
"totalPreconf": 36000000,
"availablePreconf": 36000000,
"direction": true,
"price": "0.00000001256",
"midPrice": "0.00000001256",
"status": 1,
"maturityTime": 1730465060000,
"trxSubmitTime": 1730465062000,
"blockTime": 1730465064000,
"finalityTime": 1730465832000,
"totalGas": 29952852,
"validatorType": 0,
"mode": 0,
"updateDate": 1730465041000
}
]
}
}
Get active all preconf market details.
Request
| Parameter | Required | Type | Description |
|---|
Response Body
| Name | Type | Description |
|---|---|---|
| markets | object[] | List of Market objects |
| └ marketId | integer | Preconf market ID |
| └ slot | integer | Slot number of the block |
| └ instrumentId | string | Inclusion Preconf Market instrument ID Use endpoint [GET /api/v1/p/inclusion-preconf/markets] to get a list of all available inclusion preconf markets' instrument IDs |
| └ name | string | Preconf market name In format: "ETH-PC-xxxxxx" |
| └ quantityStep | string | Minimum increment between different order quantities |
| └ minQuantity | string | Minimum order quantity |
| └ maxQuantity | string | Maximum order quantity |
| └ priceStep | string | Minimum increment between valid price levels |
| └ minPrice | string | Minimum price |
| └ maxPrice | string | Maximum price |
| └ collateralPerSlot | string | ETH reserved by validator as collateral for this slot |
| └ totalPreconf | integer | Total preconf quantity for this slot |
| └ availablePreconf | integer | Available preconf quantity for trading |
| └ direction | boolean | The last trading direction (true = buy, false = sell) |
| └ price | string | Latest traded market price for this market |
| └ midPrice | string | Mid price of bid and ask |
| └ status | integer | Market status - see the Market Status Codes section for more information |
| └ maturityTime | integer | Datetime (Unix epoch milliseconds) when the market will be closed |
| └ trxSubmitTime | integer | Datetime (Unix epoch milliseconds) when the market will be closed for submitting transactions |
| └ blockTime | integer | Datetime (Unix epoch milliseconds) when the block starts |
| └ finalityTime | integer | Datetime (Unix epoch milliseconds) when the block is being finalized |
| └ totalGas | integer | Total gas available for sale in this block |
| └ validatorType | integer | Type of validator (0 for normal validators, 1 for SSV validators) |
| └ mode | integer | Mode when the market was created. 0 is max-profit. 1 is light mode. |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) when the market orderbook was last updated |
GET /api/v1/p/inclusion-preconf/market
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/inclusion-preconf/market?slot=2880221"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/inclusion-preconf/market"
params = {
"slot": 2880221
}
headers = {}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"market": {
"marketId": 1000002880221,
"slot": 2880221,
"instrumentId": "ETH-PC-2880221",
"name": "Eth Preconf Inclusion Slot #2880221",
"quantityStep": "1",
"minQuantity": "1",
"maxQuantity": "30000000",
"priceStep": "0.00000000001",
"minPrice": "0.00000000001",
"maxPrice": "0.00001",
"collateralPerSlot": "3.996",
"totalPreconf": 36000000,
"availablePreconf": 30000000,
"direction": true,
"price": "0.00000001302",
"midPrice": "0.00000001299",
"status": 1,
"maturityTime": 1730465048000,
"trxSubmitTime": 1730465050000,
"blockTime": 1730465052000,
"finalityTime": 1730465820000,
"totalGas": 29982469,
"validatorType": 1,
"mode": 0,
"updateDate": 1730465042000
}
}
}
Get preconfs market details for a given slot
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| slot | YES | integer | Slot number |
Response Body
| Name | Type | Description |
|---|---|---|
| market | object | Market object |
| └ marketId | integer | Preconf market ID |
| └ slot | integer | Slot number of the block |
| └ instrumentId | string | Inclusion Preconf Market instrument ID Use endpoint [GET /api/v1/p/inclusion-preconf/markets] to get a list of all available instrument IDs |
| └ name | string | Preconf market name In format: "ETH-PC-xxxxxx" |
| └ quantityStep | string | Minimum increment between different order quantities |
| └ minQuantity | string | Minimum order quantity |
| └ maxQuantity | string | Maximum order quantity |
| └ priceStep | string | Minimum increment between valid price levels |
| └ minPrice | string | Minimum price |
| └ maxPrice | string | Maximum price |
| └ collateralPerSlot | string | ETH reserved by validator as collateral for this slot |
| └ totalPreconf | integer | Total preconf quantity for this slot |
| └ availablePreconf | integer | Available preconf quantity for trading |
| └ direction | boolean | The last trading direction (true = buy, false = sell) |
| └ price | string | Latest traded market price for this market |
| └ midPrice | string | Mid price of bid and ask |
| └ status | integer | Market status - see the Market Status Codes section for more information |
| └ maturityTime | integer | Datetime (Unix epoch milliseconds) when the market will be closed |
| └ trxSubmitTime | integer | Datetime (Unix epoch milliseconds) when the market will be closed for submitting transactions |
| └ blockTime | integer | Datetime (Unix epoch milliseconds) when the block starts |
| └ finalityTime | integer | Datetime (Unix epoch milliseconds) when the block is being finalized |
| └ totalGas | integer | Total gas available for sale in this block |
| └ validatorType | integer | Type of validator (0 for normal validators, 1 for SSV validators) |
| └ mode | integer | Mode when the market was created. 0 is max-profit. 1 is light mode. |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) when the market orderbook was last updated |
GET /api/v1/p/inclusion-preconf/trades
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/inclusion-preconf/trades?instrumentId=ETH-PC-988403"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/inclusion-preconf/trades"
params = {
"instrumentId": "ETH-PC-988403",
}
headers = {}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"trades": [
{
"trxId": "1231310314",
"instrumentId": "ETH-PC-988403",
"side": false,
"price": "0.0501",
"quantity": "210000",
"date": 1689833397180
},
{
"trxId": "1231310327",
"instrumentId": "ETH-PC-988403",
"side": false,
"price": "0.0493",
"quantity": "400000",
"date": 1689833043675
},
{
"trxId": "1249310327",
"instrumentId": "ETH-PC-988403",
"side": true,
"price": "0.0487",
"quantity": "100000",
"date": 1689832827936
},
{
"trxId": "1252310327",
"instrumentId": "ETH-PC-988403",
"side": false,
"price": "0.0478",
"quantity": "350000",
"date": 1689832426057
},
{
"trxId": "1261310327",
"instrumentId": "ETH-PC-988403",
"side": false,
"price": "0.0339",
"quantity": "21000",
"date": 1689799385952
}
]
}
Get recent preconf trade details for a given preconf instrument ID.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| instrumentId | YES | string | Instrument ID |
| limit | NO | integer | Maximum number of transactions to return |
Response Body
| Name | Type | Description |
|---|---|---|
| trades | object[] | List of trades |
| └ trxId | string | Transaction ID |
| └ instrumentId | string | Instrument ID |
| └ side | integer | Order Side. Buy = 1, Sell = 0 |
| └ price | string | Latest traded market price for this market |
| └ quantity | integer | Quantity of the preconf bought |
| └ date | integer | Datetime (Unix epoch milliseconds) when the trade was executed |
GET /api/v1/p/inclusion-preconf/positions
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/inclusion-preconf/positions?instrumentId=ETH-PC-475423&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/inclusion-preconf/positions"
params = {"instrumentId": "ETH-PC-475423", "limit": 10}
response = requests.get(url, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"positions": []
}
}
Get Preconf positions.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| instrumentId | NO | string | Instrument ID |
| limit | NO | integer | Maximum number of positions to return (default: 10; positive; cap: 1000) |
Response Body
| Name | Type | Description |
|---|---|---|
| positions | object[] | List of positions |
GET /api/v1/p/inclusion-preconf/orders
See pagination: omit startId for the first page in either direction. Supplied cursors are exclusive. done=true selects only status 10.
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/inclusion-preconf/orders?instrumentId=ETH-PC-475423&onBook=false&done=false&startId=0&asc=true&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/inclusion-preconf/orders"
params = {
"instrumentId": "ETH-PC-475423",
"onBook": False,
"done": False,
"startId": 0,
"asc": True,
"limit": 10
}
response = requests.get(url, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"orders": []
}
}
Get Preconf orders.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| instrumentId | YES | string | Instrument ID |
| onBook | NO | boolean | Pending orders only (default: false) |
| done | NO | boolean | Done orders only (default: false) |
| startId | NO | long | Exclusive order cursor; omitted for the first page |
| asc | NO | boolean | Sort direction, true=asc, false=desc (default: true) |
| limit | NO | integer | Maximum number of orders to return (default: 10). Values must be positive; values above 1000 are capped at 1000. |
Response Body
| Name | Type | Description |
|---|---|---|
| orders | object[] | List of orders |
GET /api/v1/p/inclusion-preconf/top-sales
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/inclusion-preconf/top-sales?instrumentId=ETH-PC-475423&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/inclusion-preconf/top-sales"
params = {
"instrumentId": "ETH-PC-475423",
"limit": 10
}
headers = {}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"positions": [
{
"positionId": 123456789,
"instrumentId": "ETH-PC-475423",
"quantity": "1000",
"avgPrice": "0.0000000125",
"status": "ACTIVE"
}
]
}
}
Get Preconf positions by price.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| instrumentId | NO | String | Instrument ID |
| limit | NO | Integer | Maximum number of positions to return (default: 10) |
Response Body
| Name | Type | Description |
|---|---|---|
| positions | object[] | List of positions |
| └ positionId | long | Position ID |
| └ instrumentId | string | Instrument ID |
| └ quantity | string | Position quantity |
| └ avgPrice | string | Average price |
| └ status | string | Position status |
Whole Block Trading
POST /api/v1/wholeblock/order
Requires bearer authentication and an application/json body.
Example request:
{
"accountId": 128,
"instrumentId": "ETH-WB-9884031",
"side": true,
"orderType": 2,
"clientOrderId": "exampleOrder0001",
"passive": false,
"price": "0.00000000569"
}
Send a reviewed request.json containing the JSON body above. Set ETHGAS_BASE_URL and ETHGAS_ACCESS_TOKEN for your environment.
curl --request POST "$ETHGAS_BASE_URL/api/v1/wholeblock/order" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @request.json
import json
import os
import requests
with open("request.json", encoding="utf-8") as request_file:
payload = json.load(request_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/wholeblock/order",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
# Check HTTP status and content type before interpreting the JSON envelope.
print(response.status_code, response.text)
Request Body
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | YES | integer | Trading/preconf account ID. Missing/zero is rejected. |
| instrumentId | CONDITIONAL | string | Market instrument. Canonical selector; discover an active market first. |
| marketId | CONDITIONAL | integer (int64) | Alternative market identifier. Supply one unambiguous market selector; do not send conflicting identifiers. |
| side | YES | boolean | Buy true, sell false. |
| orderType | YES | integer |
1 market, 2 limit, 3 fill-or-kill (FOK). |
| clientOrderId | YES | string | 1–32 ASCII letters/digits; ^[a-zA-Z0-9]{1,32}$. Retain for reconciliation. |
| passive | NO | boolean | Default false; post-only when true. FOK with passive=true is rejected. |
| price | CONDITIONAL | decimal string | ETH per gas. Required and positive for limit/FOK; obey market min/max/step. For market orders, omit for a regular market order; a supplied price is a slippage limit. |
| quantity | NO | decimal string | Server always sets quantity to 1, overriding any supplied value. |
Send price and quantity as decimal strings, within the market minimum, maximum, and step. Omit response fields such as fees, fulfilled, status, and orderId.
Response Body
This response confirms that the order was accepted. It includes orderDate. Order lists use createDate and updateDate, and that is where you read fees and averageTradePrice. If the request sends only instrumentId, marketId can be 0. Read the market from the market list.
| Field in data.order | Type | Description |
|---|---|---|
| orderId | integer (int64) | Assigned order ID. |
| accountId / instrumentId / side / orderType / passive / clientOrderId | request types | Submitted order parameters. |
| marketId | integer (int64) | May remain 0 for instrument-only requests. |
| quantity / fulfilled / price | decimal string | Quantity, executed quantity and submitted price; absent nullable fields may be omitted. |
| status | integer | See Order Status Codes; acknowledgement is not proof of full execution. |
| orderDate | integer | Order timestamp in epoch milliseconds. |
| source | integer |
1 for orders submitted through this REST path. |
| preconfQuantity | integer | Integer gas quantity. |
Example response:
{
"success": true,
"data": {
"order": {
"accountId": 128,
"instrumentId": "ETH-WB-9884031",
"side": true,
"orderType": 2,
"clientOrderId": "exampleOrder0001",
"passive": false,
"price": "0.00000000569",
"orderId": 204415806,
"marketId": 0,
"quantity": "1",
"fulfilled": "0",
"status": 1,
"source": 1,
"orderDate": 1790812800000
}
}
}
Error 58 means this clientOrderId is already in use. Look up the existing order. See Mutations, retries and idempotency.
POST /api/v1/wholeblock/cancel-all-orders
Requires bearer authentication and an application/json body.
Supported cancellation scopes: supply a nonblank instrumentId to cancel orders for one instrument. Omit instrumentId, send null, or send a blank string to cancel orders across all instruments of this market family for the specified account. Both modes are intentional API features.
To cancel every instrument, send your accountId only. The example below selects one instrument.
Example request:
{
"accountId": 128,
"instrumentId": "ETH-WB-9884031"
}
Send a reviewed request.json containing the JSON body above. Set ETHGAS_BASE_URL and ETHGAS_ACCESS_TOKEN for your environment.
curl --request POST "$ETHGAS_BASE_URL/api/v1/wholeblock/cancel-all-orders" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @request.json
import json
import os
import requests
with open("request.json", encoding="utf-8") as request_file:
payload = json.load(request_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/wholeblock/cancel-all-orders",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
# Check HTTP status and content type before interpreting the JSON envelope.
print(response.status_code, response.text)
Request Body
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | YES | integer | Account whose orders are canceled. |
| instrumentId | NO | string | Omitted, null or blank cancels across ALL instruments in this market family. |
Response Body
Normal completion returns data.code=0.
{"success":true,"data":{"code":0}}
A rejected request has success false, with errorCode and errorMsgKey. Missing account is 91. Missing instrument is 92. An invalid ID choice is 93 or 94. An invalid client order ID is 95. A batch above the limit is 96.
POST /api/v1/wholeblock/cancel-batch-orders
Requires bearer authentication and an application/json body.
Supply exactly one ID family. Sending both or neither is rejected. Each batch accepts at most 100 IDs.
Example request:
{
"accountId": 128,
"instrumentId": "ETH-WB-9884031",
"clientOrderIds": [
"exampleOrder0001",
"exampleOrder0002"
]
}
Send a reviewed request.json containing the JSON body above. Set ETHGAS_BASE_URL and ETHGAS_ACCESS_TOKEN for your environment.
curl --request POST "$ETHGAS_BASE_URL/api/v1/wholeblock/cancel-batch-orders" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @request.json
import json
import os
import requests
with open("request.json", encoding="utf-8") as request_file:
payload = json.load(request_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/wholeblock/cancel-batch-orders",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
# Check HTTP status and content type before interpreting the JSON envelope.
print(response.status_code, response.text)
Request Body
Response Body
The outer success indicates the request was handled. Inspect every data.orders[].code: 0 succeeds, 90 means no matching order. Individual failures can appear under success: true.
{
"success": true,
"data": {
"orders": [
{
"code": 0,
"errorMsg": "success",
"accountId": 128,
"orderId": 204415806,
"clientOrderId": "exampleOrder0001"
}
]
}
}
| Field | Type | Description |
|---|---|---|
| orders | object[] | Per-order results. |
| orders[].code | integer | Operation result; see cancellation codes 90–96. |
| orders[].errorMsg | string | Message key (not outer errorMsgKey). |
| orders[].accountId | integer | Account ID. |
| orders[].orderId | integer (int64) | Present when the order was found. |
| orders[].clientOrderId | string | Can be omitted when unavailable. |
A rejected request has success false, with errorCode and errorMsgKey. Missing account is 91. Missing instrument is 92. An invalid ID choice is 93 or 94. An invalid client order ID is 95. A batch above the limit is 96.
POST /api/v1/wholeblock/cancel-order
Requires bearer authentication and an application/json body.
Supply exactly one ID family. Sending both or neither is rejected.
Example request:
{
"accountId": 128,
"instrumentId": "ETH-WB-9884031",
"clientOrderId": "exampleOrder0001"
}
Send a reviewed request.json containing the JSON body above. Set ETHGAS_BASE_URL and ETHGAS_ACCESS_TOKEN for your environment.
curl --request POST "$ETHGAS_BASE_URL/api/v1/wholeblock/cancel-order" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @request.json
import json
import os
import requests
with open("request.json", encoding="utf-8") as request_file:
payload = json.load(request_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/wholeblock/cancel-order",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
# Check HTTP status and content type before interpreting the JSON envelope.
print(response.status_code, response.text)
Request Body
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | YES | integer | Account whose orders are canceled. |
| instrumentId | YES | string | Nonblank instrument ID. |
| clientOrderId | ONE FAMILY | string | ASCII alphanumeric ID(s), 1–32 characters each. Do not send null elements. |
| orderId | ONE FAMILY | integer (int64) | Alternative server-assigned numeric ID(s). Do not use hex strings. |
Response Body
The outer success indicates the request was handled. Inspect every data.orders[].code: 0 succeeds, 90 means no matching order. Individual failures can appear under success: true.
{
"success": true,
"data": {
"orders": [
{
"code": 0,
"errorMsg": "success",
"accountId": 128,
"orderId": 204415806,
"clientOrderId": "exampleOrder0001"
}
]
}
}
| Field | Type | Description |
|---|---|---|
| orders | object[] | Per-order results. |
| orders[].code | integer | Operation result; see cancellation codes 90–96. |
| orders[].errorMsg | string | Message key (not outer errorMsgKey). |
| orders[].accountId | integer | Account ID. |
| orders[].orderId | integer (int64) | Present when the order was found. |
| orders[].clientOrderId | string | Can be omitted when unavailable. |
A rejected request has success false, with errorCode and errorMsgKey. Missing account is 91. Missing instrument is 92. An invalid ID choice is 93 or 94. An invalid client order ID is 95. A batch above the limit is 96.
GET /api/v1/user/wholeblock/all-orders
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/wholeblock/all-orders?onBook=false&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/wholeblock/all-orders"
params = {
"onBook": False,
"limit": 10
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"orders": [
{
"orderId": 204421028,
"marketId": 2000009884031,
"instrumentId": "ETH-WB-9884031",
"accountId": 128,
"side": false,
"orderType": 1,
"quantity": "1",
"fulfilled": "1",
"price": "0.01",
"averageTradePrice": "0.01",
"fees": "0.0001",
"status": 10,
"clientOrderId": "y0xja3Xi",
"passive": false,
"createDate": 1697449610000,
"source": 1,
"updateDate": 1697449609000
}
],
"hasNextPage": false
}
}
Get all user whole block orders for a given user account ID.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | NO | integer | Default: session preconf account; explicit accounts require read access. |
| onBook | NO | boolean | Open orders only; default false. |
| startId | NO | integer (int64) | Exclusive order cursor. Omitted for the first page. |
| asc | NO | boolean | Default true; see pagination limitations. |
| limit | NO | integer | Default 10; positive values; capped at 1000. |
hasNextPage is true when more orders match. Send nextCursor as startId with the same filters and direction. The last page has hasNextPage false and no nextCursor. See Pagination and filters.
Response Body
| Name | Type | Description |
|---|---|---|
| hasNextPage | boolean | True when the query found another matching row beyond this page. |
| nextCursor | integer (int64) | Last returned order ID; present only when hasNextPage is true. |
| orders | object[] | List of order object |
| └ orderId | integer | Unique order ID, assigned by ETHGas |
| └ marketId | integer | Market ID for this order |
| └ instrumentId | string | Whole block market instrument ID |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ side | boolean | buy order (true) or sell order (false) |
| └ orderType | integer | Market (1), limit (2), or FOK (3) |
| └ quantity | string | Order quantity (1 for whole block orders) |
| └ fulfilled | string | Quantity that has already been executed |
| └ price | string | Price of the order |
| └ averageTradePrice | string | Average price of executed trades |
| └ fees | string | Fees charged for this order |
| └ status | integer | Order status - see the Order Status Codes section for more information |
| └ errorCode | integer | Error code if order failed (omitted if absent) |
| └ clientOrderId | string | Client order ID: 1–32 ASCII letters/digits, matching ^[a-zA-Z0-9]{1,32}$
|
| └ passive | boolean | Whether the order is a maker order only |
| └ createDate | integer | Datetime (Unix epoch milliseconds) when the order was created |
| └ source | integer | Where the order is originated |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) when the order was last updated |
GET /api/v1/user/wholeblock/orders
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/wholeblock/orders?accountId=128&instrumentId=ETH-WB-9884031"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/wholeblock/orders"
params = {
"instrumentId": "ETH-WB-9884031"
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"orders": [
{
"orderId": 204421028,
"marketId": 2000009884031,
"instrumentId": "ETH-WB-9884031",
"accountId": 128,
"side": false,
"orderType": 1,
"quantity": "1",
"fulfilled": "1",
"price": "0.01",
"averageTradePrice": "0.01",
"fees": "0.0001",
"status": 10,
"clientOrderId": "y0xja3Xi",
"passive": false,
"createDate": 1697449610000,
"source": 1,
"updateDate": 1697449609000
}
]
}
}
Get user whole block orders for a given account ID (and instrument ID).
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | NO | integer | Default: session preconf account; explicit accounts require read access. |
| instrumentId | NO | string | Optional instrument filter. |
| onBook | NO | boolean | Open orders only; default false. |
| done | NO | boolean | Status 10 only; default false; mutually exclusive with onBook=true. |
| startId | NO | integer (int64) | Exclusive order cursor. Omit for the first page in either direction. |
| asc | NO | boolean | Default true; see pagination limitations. |
| limit | NO | integer | Default 10; positive values; capped at 1000. |
Response Body
| Name | Type | Description |
|---|---|---|
| orders | object[] | List of order object |
| └ orderId | integer | Unique order ID, assigned by ETHGas |
| └ marketId | integer | Market ID for this order |
| └ instrumentId | string | Whole block market instrument ID Use endpoint [GET /api/v1/wholeblock/markets] to get a list of all available wholeblock markets' instrument IDs |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ side | boolean | buy order (true) or sell order (false) |
| └ orderType | integer | Market (1), limit (2), or FOK (3) If an order is sent with both a price specified and an orderType of 1, then a maximum slippage order is created |
| └ quantity | string | Order quantity (1 for whole block orders) |
| └ fulfilled | string | Quantity that has already been executed |
| └ price | string | Price of the order |
| └ averageTradePrice | string | Average price of executed trades |
| └ fees | string | Fees charged for this order |
| └ status | integer | Order status - see the Order Status Codes section for more information |
| └ errorCode | integer | Error code if order failed (omitted if absent) |
| └ clientOrderId | string | Client order ID: 1–32 ASCII letters/digits, matching ^[a-zA-Z0-9]{1,32}$
|
| └ passive | boolean | (Post-only) Whether the order is a maker order only (i.e. can only be lifted, but cannot lift/take any orders from the orderbook itself - in other words, can only add liquidity) If set to false, there are no such restrictions and the order can immediately lift (i.e. take) existing orders in the orderbook if it is crossing the bid/sell price spread |
| └ createDate | integer | Datetime (Unix epoch milliseconds) when the order was created |
| └ source | integer | Where the order is originated 1: User interface 5: TWAP |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) when the order was last updated |
| └ trades | object[] | List of executed trades for this order |
| └ side | boolean | Order side - buy (true) or sell (false) |
| └ rate | string | Price executed |
| └ quantity | string | Quantity executed |
| └ date | integer | Datetime (Unix epoch milliseconds) executed |
GET /api/v1/user/wholeblock/positions
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/wholeblock/positions?instrumentId=ETH-WB-9884031&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/wholeblock/positions"
params = {
"instrumentId": "ETH-WB-9884031",
"limit": 10
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"positions": [
{
"positionId": 204421028,
"instrumentId": "ETH-WB-9884031",
"accountId": 128,
"side": false,
"orderType": 1,
"quantity": "1",
"fulfilled": "1",
"status": 10,
"clientOrderId": "y0xja3Xi",
"passive": false,
"orderDate": 1697449610000,
"source": 1,
"updateDate": 1697449609000,
"averageTradePrice": "0.047",
"trades": [
{
"side": false,
"price": "0.047",
"quantity": "1",
"date": 1697449609000
}
]
}
]
}
}
Get user wholeblock positions for a given account ID (and instrument ID).
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | NO | integer | Default: session preconf account; explicit accounts require read access. |
| instrumentId | NO | string | Optional instrument filter. |
| startId | NO | integer (int64) | Slot cursor; omitted for the first page. |
| enable | NO | boolean | Active positions only; default true. |
| asc | NO | boolean | Default false (descending). |
| limit | NO | integer | Default 10; positive values; capped at 1000. |
Response Body
| Name | Type | Description |
|---|---|---|
| positions | object[] | List of position object |
| └ positionId | integer | Unique position ID, assigned by ETHGas |
| └ instrumentId | string | Whole block market instrument ID Use endpoint [GET /api/v1/wholeblock/markets] to get a list of all available wholeblock markets' instrument IDs |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ quantity | string | Order quantity |
| └ status | integer | Order status - see the Order Status Codes section for more information |
| └ passive | boolean | (Post-only) Whether the order is a maker order only (i.e. can only be lifted, but cannot lift/take any orders from the orderbook itself - in other words, can only add liquidity) If set to false, there are no such restrictions and the order can immediately lift (i.e. take) existing orders in the orderbook if it is crossing the bid/sell price spread |
| └ createDate | integer | Datetime (Unix epoch milliseconds) when the position was updated |
| └ source | integer | Where the order is originated 1: User interface 5: TWAP |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) something last occurred to the order |
| └ trades | object[] | List of executed trades for this order |
| └ side | boolean | Order side - buy (true) or sell (false) |
| └ rate | string | Price executed |
| └ quantity | string | Quantity executed |
| └ date | integer | Datetime (Unix epoch milliseconds) executed |
GET /api/v1/user/wholeblock/txs
Get the user transactions for wholeblock market
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/wholeblock/txs?instrumentId=ETH-WB-63999&limit=100"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/wholeblock/txs"
params = {
"instrumentId": "ETH-WB-63999",
"limit": 10
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"txs": [
{ "buyerAccountId": 14,
"sellerAccountId": 2049,
"instrumentId": "ETH-WB-63999",
"trxId": 11675386,
"side": false,
"price": "0.00000002",
"quantity": "1",
"preconfQuantity": "320000000",
"date": 1730269305359
},
{ "buyerAccountId": 2015,
"sellerAccountId": 14,
"instrumentId": "ETH-WB-63999",
"trxId": 11675385,
"side": true,
"price": "0.00000002",
"quantity": "1",
"preconfQuantity": "350000000",
"date": 1730269208878
}
]
}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | YES | integer | Readable account ID. |
| instrumentId | NO | string | Optional instrument filter. |
| orderId | NO | integer (int64) | If supplied, selects the order-specific branch; instrumentId, startId and limit do not control that branch. |
| startId | NO | integer (int64) | Transaction cursor for the general list branch. |
| limit | NO | integer | Default 20; positive values; capped at 1000 for the general list branch. |
Response Body
| Name | Type | Description |
|---|---|---|
| txs | object[] | List of trades |
| └ instrumentId | string | Whole block market instrument ID Use endpoint GET /api/v1/p/wholeblock/markets to get a list of all available whole block markets' instrument IDs |
| └ trxId | integer | Transaction Id |
| └ buyerAccountId | integer | Buyer Account Id |
| └ sellerAccountId | integer | Seller Account Id |
| └ side | integer | Order Side. Buy = 1, Sell = 0 |
| └ price | string | Latest traded market price for this market |
| └ quantity | integer | Quantity always = 1 |
| └ preconfQuantity | integer | Preconf quantity sold with the whole block |
| └ date | integer | Datetime (Unix epoch milliseconds) when the market orderbook was last updated |
Inclusion Preconf Trading
POST /api/v1/inclusion-preconf/cancel-all-orders
Requires bearer authentication and an application/json body.
Supported cancellation scopes: supply a nonblank instrumentId to cancel orders for one instrument. Omit instrumentId, send null, or send a blank string to cancel orders across all instruments of this market family for the specified account. Both modes are intentional API features.
To cancel every instrument, send your accountId only. The example below selects one instrument.
Example request:
{
"accountId": 128,
"instrumentId": "ETH-PC-9884031"
}
Send a reviewed request.json containing the JSON body above. Set ETHGAS_BASE_URL and ETHGAS_ACCESS_TOKEN for your environment.
curl --request POST "$ETHGAS_BASE_URL/api/v1/inclusion-preconf/cancel-all-orders" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @request.json
import json
import os
import requests
with open("request.json", encoding="utf-8") as request_file:
payload = json.load(request_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/inclusion-preconf/cancel-all-orders",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
# Check HTTP status and content type before interpreting the JSON envelope.
print(response.status_code, response.text)
Request Body
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | YES | integer | Account whose orders are canceled. |
| instrumentId | NO | string | Omitted, null or blank cancels across ALL instruments in this market family. |
Response Body
Normal completion returns data.code=0.
{"success":true,"data":{"code":0}}
A rejected request has success false, with errorCode and errorMsgKey. Missing account is 91. Missing instrument is 92. An invalid ID choice is 93 or 94. An invalid client order ID is 95. A batch above the limit is 96.
POST /api/v1/inclusion-preconf/cancel-batch-orders
Requires bearer authentication and an application/json body.
Supply exactly one ID family. Sending both or neither is rejected. Each batch accepts at most 100 IDs.
Example request:
{
"accountId": 128,
"instrumentId": "ETH-PC-9884031",
"clientOrderIds": [
"exampleOrder0001",
"exampleOrder0002"
]
}
Send a reviewed request.json containing the JSON body above. Set ETHGAS_BASE_URL and ETHGAS_ACCESS_TOKEN for your environment.
curl --request POST "$ETHGAS_BASE_URL/api/v1/inclusion-preconf/cancel-batch-orders" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @request.json
import json
import os
import requests
with open("request.json", encoding="utf-8") as request_file:
payload = json.load(request_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/inclusion-preconf/cancel-batch-orders",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
# Check HTTP status and content type before interpreting the JSON envelope.
print(response.status_code, response.text)
Request Body
Response Body
The outer success indicates the request was handled. Inspect every data.orders[].code: 0 succeeds, 90 means no matching order. Individual failures can appear under success: true.
{
"success": true,
"data": {
"orders": [
{
"code": 0,
"errorMsg": "success",
"accountId": 128,
"orderId": 204415806,
"clientOrderId": "exampleOrder0001"
}
]
}
}
| Field | Type | Description |
|---|---|---|
| orders | object[] | Per-order results. |
| orders[].code | integer | Operation result; see cancellation codes 90–96. |
| orders[].errorMsg | string | Message key (not outer errorMsgKey). |
| orders[].accountId | integer | Account ID. |
| orders[].orderId | integer (int64) | Present when the order was found. |
| orders[].clientOrderId | string | Can be omitted when unavailable. |
A rejected request has success false, with errorCode and errorMsgKey. Missing account is 91. Missing instrument is 92. An invalid ID choice is 93 or 94. An invalid client order ID is 95. A batch above the limit is 96.
POST /api/v1/inclusion-preconf/cancel-order
Requires bearer authentication and an application/json body.
Supply exactly one ID family. Sending both or neither is rejected.
Example request:
{
"accountId": 128,
"instrumentId": "ETH-PC-9884031",
"clientOrderId": "exampleOrder0001"
}
Send a reviewed request.json containing the JSON body above. Set ETHGAS_BASE_URL and ETHGAS_ACCESS_TOKEN for your environment.
curl --request POST "$ETHGAS_BASE_URL/api/v1/inclusion-preconf/cancel-order" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @request.json
import json
import os
import requests
with open("request.json", encoding="utf-8") as request_file:
payload = json.load(request_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/inclusion-preconf/cancel-order",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
# Check HTTP status and content type before interpreting the JSON envelope.
print(response.status_code, response.text)
Request Body
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | YES | integer | Account whose orders are canceled. |
| instrumentId | YES | string | Nonblank instrument ID. |
| clientOrderId | ONE FAMILY | string | ASCII alphanumeric ID(s), 1–32 characters each. Do not send null elements. |
| orderId | ONE FAMILY | integer (int64) | Alternative server-assigned numeric ID(s). Do not use hex strings. |
Response Body
The outer success indicates the request was handled. Inspect every data.orders[].code: 0 succeeds, 90 means no matching order. Individual failures can appear under success: true.
{
"success": true,
"data": {
"orders": [
{
"code": 0,
"errorMsg": "success",
"accountId": 128,
"orderId": 204415806,
"clientOrderId": "exampleOrder0001"
}
]
}
}
| Field | Type | Description |
|---|---|---|
| orders | object[] | Per-order results. |
| orders[].code | integer | Operation result; see cancellation codes 90–96. |
| orders[].errorMsg | string | Message key (not outer errorMsgKey). |
| orders[].accountId | integer | Account ID. |
| orders[].orderId | integer (int64) | Present when the order was found. |
| orders[].clientOrderId | string | Can be omitted when unavailable. |
A rejected request has success false, with errorCode and errorMsgKey. Missing account is 91. Missing instrument is 92. An invalid ID choice is 93 or 94. An invalid client order ID is 95. A batch above the limit is 96.
POST /api/v1/inclusion-preconf/order
Requires bearer authentication and an application/json body.
Example request:
{
"accountId": 128,
"instrumentId": "ETH-PC-9884031",
"side": true,
"orderType": 2,
"clientOrderId": "exampleOrder0001",
"passive": false,
"price": "0.00000000569",
"quantity": "21000"
}
Send a reviewed request.json containing the JSON body above. Set ETHGAS_BASE_URL and ETHGAS_ACCESS_TOKEN for your environment.
curl --request POST "$ETHGAS_BASE_URL/api/v1/inclusion-preconf/order" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @request.json
import json
import os
import requests
with open("request.json", encoding="utf-8") as request_file:
payload = json.load(request_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/inclusion-preconf/order",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
# Check HTTP status and content type before interpreting the JSON envelope.
print(response.status_code, response.text)
Request Body
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | YES | integer | Trading/preconf account ID. Missing/zero is rejected. |
| instrumentId | CONDITIONAL | string | Market instrument. Canonical selector; discover an active market first. |
| marketId | CONDITIONAL | integer (int64) | Alternative market identifier. Supply one unambiguous market selector; do not send conflicting identifiers. |
| side | YES | boolean | Buy true, sell false. |
| orderType | YES | integer |
1 market, 2 limit, 3 fill-or-kill (FOK). |
| clientOrderId | YES | string | 1–32 ASCII letters/digits; ^[a-zA-Z0-9]{1,32}$. Retain for reconciliation. |
| passive | NO | boolean | Default false; post-only when true. FOK with passive=true is rejected. |
| price | CONDITIONAL | decimal string | ETH per gas. Required and positive for limit/FOK; obey market min/max/step. For market orders, omit for a regular market order; a supplied price is a slippage limit. |
| quantity | YES | decimal string | Positive gas quantity; obey market min/max/step. |
Send price and quantity as decimal strings, within the market minimum, maximum, and step. Omit response fields such as fees, fulfilled, status, and orderId.
Response Body
This response confirms that the order was accepted. It includes orderDate. Order lists use createDate and updateDate, and that is where you read fees and averageTradePrice. If the request sends only instrumentId, marketId can be 0. Read the market from the market list.
| Field in data.order | Type | Description |
|---|---|---|
| orderId | integer (int64) | Assigned order ID. |
| accountId / instrumentId / side / orderType / passive / clientOrderId | request types | Submitted order parameters. |
| marketId | integer (int64) | May remain 0 for instrument-only requests. |
| quantity / fulfilled / price | decimal string | Quantity, executed quantity and submitted price; absent nullable fields may be omitted. |
| status | integer | See Order Status Codes; acknowledgement is not proof of full execution. |
| orderDate | integer | Order timestamp in epoch milliseconds. |
| source | integer |
1 for orders submitted through this REST path. |
| preconfQuantity | integer | Integer gas quantity. |
Example response:
{
"success": true,
"data": {
"order": {
"accountId": 128,
"instrumentId": "ETH-PC-9884031",
"side": true,
"orderType": 2,
"clientOrderId": "exampleOrder0001",
"passive": false,
"price": "0.00000000569",
"quantity": "21000",
"orderId": 204415806,
"marketId": 0,
"fulfilled": "0",
"status": 1,
"source": 1,
"orderDate": 1790812800000
}
}
}
Error 58 means this clientOrderId is already in use. Look up the existing order. See Mutations, retries and idempotency.
GET /api/v1/user/inclusion-preconf/orders
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/inclusion-preconf/orders?accountId=128&instrumentId=ETH-PC-9884031"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/inclusion-preconf/orders"
params = {
"accountId": 128,
"instrumentId": "ETH-PC-9884031"
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"orders": [
{
"orderId": 204421028,
"marketId": 1000009884031,
"accountId": 128,
"instrumentId": "ETH-PC-9884031",
"side": false,
"orderType": 1,
"quantity": "994.66",
"fulfilled": "994.66",
"price": "0.00000000535",
"fees": "0",
"status": 10,
"clientOrderId": "y0xja3Xi",
"passive": false,
"createDate": 1697449610000,
"source": 1,
"updateDate": 1697449609000
},
{
"orderId": 204421029,
"marketId": 1000009884031,
"accountId": 126,
"instrumentId": "ETH-PC-9884031",
"side": false,
"orderType": 1,
"quantity": "20000",
"fulfilled": "20000",
"price": "0.00000000535",
"fees": "0.0000000000013",
"status": 10,
"clientOrderId": "abdc2werf",
"passive": false,
"createDate": 1697449630000,
"source": 1,
"updateDate": 1697449659000
}
]
}
}
Get user preconfs orders for a given account ID (and instrument ID).
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | NO | integer | Default: session preconf account; explicit accounts require read access. |
| instrumentId | NO | string | Optional instrument filter. |
| onBook | NO | boolean | Open orders only; default false. |
| done | NO | boolean | Status 10 only; default false; mutually exclusive with onBook=true. |
| startId | NO | integer (int64) | Exclusive order cursor. Omitted for the first page. |
| asc | NO | boolean | Default false; see pagination limitations. |
| limit | NO | integer | Default 10; positive values; capped at 1000. |
Response Body
| Name | Type | Description |
|---|---|---|
| orders | object[] | List of order object |
| └ orderId | integer | Unique order ID, assigned by ETHGas |
| └ marketId | integer | ETHGas marketId |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ instrumentId | string | Inclusion Preconf market instrument ID Use endpoint [GET /api/v1/inclusion-preconf/markets] to get a list of all available inclusion preconf markets' instrument IDs |
| └ side | boolean | buy order (true) or sell order (false) |
| └ orderType | integer | Market (1), limit (2), or FOK (3) If an order is sent with both a price specified and an orderType of 1, then a maximum slippage order is created |
| └ quantity | string | Order quantity |
| └ fulfilled | string | Quantity executed |
| └ status | integer | Order status - see the Order Status Codes section for more information |
| └ clientOrderId | string | Client order ID: 1–32 ASCII letters/digits, matching ^[a-zA-Z0-9]{1,32}$
|
| └ passive | boolean | (Post-only) Whether the order is a maker order only (i.e. can only be lifted, but cannot lift/take any orders from the orderbook itself - in other words, can only add liquidity) If set to false, there are no such restrictions and the order can immediately lift (i.e. take) existing orders in the orderbook if it is crossing the bid/sell price spread |
| └ createDate | integer | Datetime (Unix epoch milliseconds) when the order was placed |
| └ source | integer | Where the order is originated 1: User interface 5: TWAP |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) something last occurred to the order |
GET /api/v1/user/inclusion-preconf/all-orders
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/inclusion-preconf/all-orders?limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/inclusion-preconf/all-orders"
params = {
"limit": 10
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"orders": [
{
"orderId": 123456789,
"clientOrderId": "order123",
"instrumentId": "ETH-PC-475423",
"side": true,
"orderType": 1,
"quantity": "1000",
"price": "0.0000000125",
"status": "ACTIVE"
}
],
"hasNextPage": false
}
}
Get all user preconf orders for a given user account ID.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | NO | integer | Default: session preconf account; explicit accounts require read access. |
| onBook | NO | boolean | Open orders only; default false. |
| startId | NO | integer (int64) | Exclusive order cursor. Omitted for the first page. |
| asc | NO | boolean | Default true; see pagination limitations. |
| limit | NO | integer | Default 10; positive values; capped at 1000. |
hasNextPage is true when more orders match. Send nextCursor as startId with the same filters and direction. The last page has hasNextPage false and no nextCursor. See Pagination and filters.
Response Body
| Name | Type | Description |
|---|---|---|
| orders | object[] | List of orders |
| └ orderId | long | System order ID |
| └ clientOrderId | string | Client order ID |
| └ instrumentId | string | Instrument ID |
| └ side | boolean | Order side (true = buy, false = sell) |
| └ orderType | integer | Order type |
| └ quantity | string | Order quantity |
| └ price | string | Order price |
| └ status | string | Order status |
| hasNextPage | boolean | True when the query found another matching row beyond this page |
| nextCursor | integer (int64) | Last returned order ID; present only when hasNextPage is true |
GET /api/v1/user/inclusion-preconf/positions
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/inclusion-preconf/positions?instrumentId=ETH-PC-9884031&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/inclusion-preconf/positions"
params = {
"instrumentId": "ETH-PC-9884031",
"limit": 10
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"positions": [
{
"positionId": 204421028,
"instrumentId": "ETH-PC-9884031",
"accountId": 128,
"side": false,
"orderType": 1,
"quantity": "994.66",
"fulfilled": "994.66",
"status": 10,
"clientOrderId": "y0xja3Xi",
"passive": false,
"orderDate": 1697449610000,
"source": 1,
"updateDate": 1697449609000,
"averageTradePrice": "0.047",
"trades": [
{
"side": false,
"price": "0.047",
"quantity": "994.66",
"date": 1697449609000
}
]
},
{
"positionId": 204421027,
"instrumentId": "ETH-PC-9884031",
"accountId": 128,
"side": true,
"orderType": 1,
"quantity": "922.58",
"fulfilled": "922.58",
"status": 10,
"clientOrderId": "f5onoOtR",
"passive": false,
"orderDate": 1697449610000,
"source": 1,
"updateDate": 1697449609000,
"averageTradePrice": "0.0338",
"trades": [
{
"side": true,
"price": "0.0338",
"quantity": "922.58",
"date": 1697449609000
}
]
}
]
}
}
Get user preconfs positions for a given account ID (and instrument ID).
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | NO | integer | Default: session preconf account; explicit accounts require read access. |
| instrumentId | NO | string | Optional instrument filter. |
| startId | NO | integer (int64) | Slot cursor; omitted for the first page. |
| enable | NO | boolean | Active positions only; default true. |
| asc | NO | boolean | Default false (descending). |
| limit | NO | integer | Default 10; positive values; capped at 1000. |
Response Body
| Name | Type | Description |
|---|---|---|
| positions | object[] | List of position object |
| └ positionId | integer | Unique position ID, assigned by ETHGas |
| └ instrumentId | string | Inclusion Preconf market instrument ID Use endpoint [GET /api/v1/inclusion-preconf/markets] to get a list of all available inclusion preconf markets' instrument IDs |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ quantity | string | Order quantity |
| └ status | integer | Order status - see the Order Status Codes section for more information |
| └ passive | boolean | (Post-only) Whether the order is a maker order only (i.e. can only be lifted, but cannot lift/take any orders from the orderbook itself - in other words, can only add liquidity) If set to false, there are no such restrictions and the order can immediately lift (i.e. take) existing orders in the orderbook if it is crossing the bid/sell price spread |
| └ createDate | integer | Datetime (Unix epoch milliseconds) when the position was updated |
| └ source | integer | Where the order is originated 1: User interface 5: TWAP |
| └ updateDate | integer | Datetime (Unix epoch milliseconds) something last occurred to the order |
GET /api/v1/user/inclusion-preconf/txs
Get the user transactions for inclusion preconfs
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/inclusion-preconf/txs?instrumentId=ETH-PC-9884031&limit=100"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/inclusion-preconf/txs"
params = {
"instrumentId": "ETH-PC-9884031",
"limit": 100
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"txs": [
{ "buyerAccountId": 14,
"sellerAccountId": 2049,
"instrumentId": "ETH-WB-63999",
"trxId": 11675386,
"side": false,
"price": "0.00000002",
"quantity": "0",
"date": 1730269305359
},
{ "buyerAccountId": 14,
"sellerAccountId": 2015,
"instrumentId": "ETH-WB-63999",
"trxId": 11675385,
"side": false,
"price": "0.00000002",
"quantity": "0",
"date": 1730269208878
},
{
"buyerAccountId": 20,
"sellerAccountId": 14,
"instrumentId": "ETH-WB-63999",
"trxId": 11675384,
"side": false,
"price": "0.00000002",
"quantity": "0",
"date": 1730269152774
},
{ "buyerAccountId": 2079,
"sellerAccountId": 14,
"instrumentId": "ETH-WB-63999",
"trxId": 11675383,
"side": false,
"price": "0.00000002",
"quantity": "0",
"date": 1730269084507
}
]
}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| accountId | YES | integer | Readable account ID. |
| instrumentId | NO | string | Optional instrument filter. |
| orderId | NO | integer (int64) | If supplied, selects the order-specific branch; instrumentId, startId and limit do not control that branch. |
| startId | NO | integer (int64) | Transaction cursor for the general list branch. |
| limit | NO | integer | Default 20; positive values; capped at 1000 for the general list branch. |
Response Body
| Name | Type | Description |
|---|---|---|
| txs | object[] | List of trades |
| └ instrumentId | string | Preconf Market instrument ID Use endpoint [GET /api/v1/p/inclusion-preconf/markets] to get a list of all available inclusion preconf markets' instrument IDs |
| └ trxId | integer | Transaction Id |
| └ buyerAccountId | integer | Buyer Account Id |
| └ sellerAccountId | integer | Seller Account Id |
| └ side | integer | Order Side. Buy = 1, Sell = 0 |
| └ price | string | Latest traded market price for this market |
| └ quantity | integer | Quantity always = 1 |
| └ date | intger | Datetime (Unix epoch milliseconds) when the market orderbook was last updated |
POST /api/v1/user/inclusion-preconf/market/update
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/inclusion-preconf/market/update?instrumentId=ETH-PC-475423&reservedQty=1000"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/inclusion-preconf/market/update"
payload = {
'instrumentId': 'ETH-PC-475423',
'reservedQty': 1000
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Block owner reserve Inclusion Preconfs.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| instrumentId | YES | String | Instrument ID |
| reservedQty | YES | Integer | Reserved quantity |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Bundle Submission
POST /api/v1/user/bundle/send
Requires bearer authentication and an application/json body. The account is the session's preconf account. Ordering applies to the whole bundle, not individual transactions.
Send a non-empty txs array to submit a bundle. Omit txs, or send null, to cancel the bundle for that slot, account, and replacementUuid. If no bundle matches, the response is error 193. An empty array submits a bundle and does not cancel one.
To cancel, send slot and replacementUuid with txs omitted or set to null.
Sign each transaction for the selected chain and slot. Use your own nonce and replacement UUID.
curl --request POST "$ETHGAS_BASE_URL/api/v1/user/bundle/send" \
--header "Authorization: Bearer $ETHGAS_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data-binary @bundle.json
import json
import os
import requests
with open("bundle.json", encoding="utf-8") as bundle_file:
payload = json.load(bundle_file)
response = requests.post(
os.environ["ETHGAS_BASE_URL"].rstrip("/") + "/api/v1/user/bundle/send",
headers={"Authorization": "Bearer " + os.environ["ETHGAS_ACCESS_TOKEN"]},
json=payload,
timeout=30,
)
print(response.status_code, response.text)
Request Body
| Parameter | Required | Type | Description |
|---|---|---|---|
| slot | YES | integer | Target Ethereum slot. |
| replacementUuid | YES | string | Bundle/replacement identifier; retain for reconciliation. |
| bundleType | NO | integer | Bundle type. Omit or send 0 for a regular bundle (1). |
| ordering | NO | integer | Default 0; positive values normalize to 1 (top), negative values to -1 (bottom). |
| chunkIndex | NO | integer | Default 0, range 0–255. Reconcile chunk/replacement state before retrying. |
| txs | YES FOR SUBMISSION | object[] | At most 256 transactions per chunk. Omitted/null has cancellation behavior described above. |
| txs[].tx | YES | hex string | Signed raw transaction; use the target chain and correct nonce. |
| txs[].canRevert | NO | boolean | Missing/null is false. With true, invalid/undecodable transactions can be skipped during preprocessing, in addition to revert permission. |
The server sets createdDate, txs[].nonce, and txs[].trxDataId. Nonce is read from the signed transaction.
Response Body
data echoes the accepted bundle, including server fields. Acceptance is not on-chain inclusion. Use the bundle retrieval endpoints to confirm what was included.
| Field in data | Type | Description |
|---|---|---|
| slot | integer | Target slot. |
| replacementUuid | string | Resolved bundle identifier. |
| bundleType | integer | Resolved bundle type. |
| ordering | integer | Resolved placement. |
| chunkIndex | integer | Present when supplied in the request; omission defaults to chunk 0 for submission. |
| createdDate | integer | Engine timestamp in epoch milliseconds. |
| txs | object[] | Echoed transaction requests when present; may include decoded nonce and storage ID. Omitted for null-list cancellation. |
190 means the market has expired. 191 means preconf balance is too low. 192 means the preconf is too large. 193 means the bundle is missing. 194 means the bundle or chunk is invalid. Message keys use the spelling bundleSumission. See Error Codes. If the result is unknown, see Mutations, retries and idempotency.
Slot Bundles
GET /api/v1/slot/bundles
Retrieve bundles for a given slot.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
slot |
YES | integer | Slot ID to retrieve bundles. |
Code Sample
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/slot/bundles?slot=123"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/slot/bundles"
params = {
'slot': 123
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Response Body
| Field | Type | Description |
|---|---|---|
slot |
integer | Slot ID of the retrieved bundles. |
emptySpace |
integer | Empty preconf reserved by preconf owner. |
isSold |
boolean | The block or preconf has been sold or not. |
builders |
list | List of builder address for that slot. |
isOfac |
boolean | Whether the slot has OFAC (Office of Foreign Assets Control) restrictions. |
feeRecipient |
string | Address of the priority fee receipient (only present when market is expired). |
bundles |
array | List of bundles associated with the slot. |
| └ replacementUuid | string | Unique identifier for the bundle |
| └ bidPrice | number | Average bid price for the bundle |
| └ bundleType | integer | Type of the bundle (optional) |
| └ ordering | integer | Ordering of the bundle (optional, only present for owner bundles) |
| └ txs | list | List of transactions |
| └ tx | string | Signed Transaction (hex encoded) |
| └ txHash | string | Transaction hash (hex encoded) |
| └ canRevert | boolean | revertable: true, non-revertable : false |
Example response:
{
"slot": 123,
"emptySpace": 0,
"isSold": true,
"builders": [
"0x313233313331330000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"0xa1885d66bef164889a2e35845c3b626545d7b0e513efe335e97c3a45e534013fa3bc38c3b7e6143695aecc4872ac52c4"
],
"isOfac": false,
"feeRecipient": "0xasdfadflj2lwejf...",
"bundles": [
{
"txs": [
{
"tx": "0x02f86b0180843b9aca00852ecc889a0082520894c87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"txHash": "0x87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"canRevert": false
},
{
"tx": "0x02f86b0180843b9aca00852ecc889a0082520894c87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"txHash": "0x87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"canRevert": false
}
],
"replacementUuid": "ab592371-84d6-459e-95e7-5edad485f282",
"bidPrice": 1.2635975e-08
},
{
"txs": [
{
"tx": "0x02f86b0180843b9aca00852ecc889a0082520894c87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"canRevert": false,
"createDate": 1730366973413
}
],
"replacementUuid": "45727106-d37e-4194-93bc-8650bc135c53fg",
"bidPrice": 1e-11
},
{
"txs": [
{
"tx": "0x02f86b0180843b9aca00852ecc889a0082520894c87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"canRevert": false,
"createDate": 1730366973440
}
],
"replacementUuid": "19780112-d37e-4194-93bc-8650bc135c53",
"bidPrice": 1e-11,
"ordering": 2
}
]
}
GET /api/v1/slot/account/bundles
Retrieve the bundles submitted for a given slot for your inclusion preconf account.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
slot |
YES | integer | Slot ID to retrieve bundles. |
Code Sample
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/slot/account/bundles?slot=123"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/slot/account/bundles"
params = {
'slot': 123
}
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Response Body
| Field | Type | Description |
|---|---|---|
slot |
integer | Slot ID of the retrieved bundles. |
bundles |
array | List of bundles associated with the slot. |
| └ replacementUuid | string | Unique identifier for the bundle |
| └ bidPrice | number | Bid price for the bundle |
| └ bundleType | integer | Type of the bundle (optional) |
| └ ordering | integer | Ordering of the bundle (optional, only present for owner bundles) |
| └ txs | list | List of transactions |
| └ tx | string | Signed Transaction (hex encoded) |
| └ txHash | string | Transaction hash (hex encoded) |
| └ canRevert | boolean | revertable: true, non-revertable : false |
Example response:
{
"slot": 123,
"bundles": [
{
"txs": [
{
"tx": "0x02f86b0180843b9aca00852ecc889a0082520894c87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"txHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"canRevert": false
},
{
"tx": "0x02f86b0180843b9aca00852ecc889a0082520894c87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"txHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
"canRevert": false
}
],
"replacementUuid": "ab592371-84d6-459e-95e7-5edad485f282",
"bidPrice": 1.2635975E-8
},
{
"txs": [
{
"tx": "0x02f86b0180843b9aca00852ecc889a0082520894c87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"txHash": "0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321",
"canRevert": false
}
],
"replacementUuid": "45727106-d37e-4194-93bc-8650bc135c53fg",
"bidPrice": 1.0E-11
},
{
"txs": [
{
"tx": "0x02f86b0180843b9aca00852ecc889a0082520894c87037874aed04e51c29f582394217a0a2b89d808080c080a0a463985c616dd8ee17d7ef9112af4e6e06a27b071525b42182fe7b0b5c8b4925a00af5ca177ffef2ff28449292505d41be578bebb77110dfc09361d2fb56998260",
"txHash": "0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba",
"canRevert": false
}
],
"replacementUuid": "19780112-d37e-4194-93bc-8650bc135c53",
"bidPrice": 1.0E-11,
"ordering": 1
}
]
}
POST /api/v1/slot/forceEmptyBlockSpace
Preconf owner set unused inclusion preconf gas to be empty for a given slot. It should be set after the inclusion preconf is being bought.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
slot |
YES | integer | Slot ID to update |
enable |
YES | boolean |
true to force empty gas space in the slot |
Code Sample
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/slot/forceEmptyBlockSpace?slot=123&enable=true"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/slot/forceEmptyBlockSpace"
params = {
'slot': 123,
'enable': True
}
headers = {'Authorization': 'Bearer {{access_token}}'}
response = requests.post(url, params=params, headers=headers)
print(response.text)
Response Body
| Field | Type | Description |
|---|---|---|
success |
boolean | Whether the request succeeded |
Example response:
{
"success": true,
"data": { "success": true }
}
Builder
POST /api/v1/builder/register
Register builder
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
publicKeys |
YES | string | Comma separated list of builder bls public key in hex. |
signatures |
YES | string | Comma separated list of bls signatures in hex. |
ofac |
NO | boolean | OFAC flag for the builders (default: false) |
Code Sample
POST /api/v1/builder/register?publicKeys=0x12345...,0x234134...&signatures=2asdfjghadg,xghlktdhj&ofac=false HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/builder/register"
payload = {
'publicKeys': '0x123456789abcdef...,0x234134...',
'signatures': '2asdfjghadg,xghlktdhj',
'ofac': False
}
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"results": [
{
"publicKey": "0xa25addc4fc16f72ca667177d7a5533d4287b3574f0127ffc227095e90b0b1fd0dd48c421e04e613d2298fe4dac83a2a5",
"result": {
"result": 0,
"description": "Success"
}
},
{
"publicKey": "0xaea551245bd0512de5222834db5f3bc9cba1a04a2e8f5de0d4fea843c9fee1af31bb9373ba6b9da08a0820f695c6ab6e",
"result": {
"result": 0,
"description": "Success"
}
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
results |
object[] | Results of builder public key registrations |
└publicKey
|
string | Public key in the registration. |
└result
|
object | Builder Registration Result |
└└result
|
integer | Builder Registration Result Code |
└└description
|
string | Builder Registration Result Description |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY | Invalid builder public key format |
| BUILDERS_MAX | Maximum 100 builders allowed per request |
| BUILDER_SIGNATURE_SIZE_NOT_MATCH_PUBLIC_KEY | Number of signatures must match number of public keys |
Note: Please refer to look up table to check the builder registration result enum
GET /api/v1/builder/signingMessage
Get the required signing message which will be used to sign the BLS signature by using builder's BLS key.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| N/A | N/A | N/A | No parameters required. |
Code Sample
GET /api/v1/builder/signingMessage HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/builder/signingMessage"
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"message": {
"eoaAddress": "0xd065335192d920ce2de4a88557f232943a901a9f"
}
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
message |
object | Signing message. |
└eoaAddress
|
string | EOA address of current user |
POST /api/v1/builder/deregister
Builder deregistering their public keys from Ethgas
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
publicKeys |
YES | string | Comma separated list of builder bls public keys in hex. |
Code Sample
POST /api/v1/builder/deregister?publicKeys=0x12342330def...,0x4a93d70def... HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/builder/deregister"
payload = {
'publicKeys': '0x12342330def...,0x4a93d70def...'
}
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true
}
Response Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Whether API call is successful or not |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY | Invalid builder public key format |
| BUILDERS_MAX | Maximum 100 builders allowed per request |
GET /api/v1/p/builders
Retrieve a list of builders and fallback builder key.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| ofac | NO | boolean | Filter by OFAC status (default: false) |
Code Sample
GET /api/v1/p/builders HTTP/1.1
Host: prod-mainnet.ethgas.com
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/builders"
headers = {
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"builders": {
"whitelistedBuilders": {
"btcs": [
"0x123456789abcdef...",
"0xfb3456789abcdef..."
]
},
"unnamedBuilders": [
"0x123456789abcdef...",
"0xfb3456789abcdef..."
],
"fallbackBuilder": "0xlhadunabcdef..."
}
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
builders |
object | List of builder objects. |
| └ whitelistedBuilders | object | List of whitelisted builders which can be accessed by builder name. |
| └ unnamedBuilders | List | List of public key of unnamed builder in hex. |
| └ fallbackBuilder | string | Public key of the ETHGAS fallback builder in hex. |
GET /api/v1/p/builder/entity
Retrieve builder entities and the builder keys mapped to each entity.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| N/A | N/A | N/A | No parameters required. |
Code Sample
GET /api/v1/p/builder/entity HTTP/1.1
Host: prod-mainnet.ethgas.com
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/builder/entity"
headers = {
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"builderEntities": [
{
"builderEntityId": 1,
"name": "ETHGAS Builder",
"builderKeys": [
"0x123456789abcdef...",
"0xfb3456789abcdef..."
]
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
builderEntities |
object[] | List of builder entities. |
└ builderEntityId
|
integer | Builder entity ID. |
└ name
|
string | Builder entity name. |
└ builderKeys
|
string[] | Builder BLS public keys mapped to this entity. |
GET /api/v1/user/builder
Retrieve a list of builder public keys submitted by a user
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| N/A | N/A | N/A | No parameters required. |
Code Sample
GET /api/v1/user/builder HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/builder"
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"builders": [
"0xa25addc4fc16f72ca667177d7a5533d4287b3574f0127ffc227095e90b0b1fd0dd48c421e04e613d2298fe4dac83a2a5",
"0xa6745dd64a0a393497d5a7d4904b613aa386f47eb2e3617cf791f059291f2812683305a4bd562d63ec15990b67795e2a",
"0xaea551245bd0512de5222834db5f3bc9cba1a04a2e8f5de0d4fea843c9fee1af31bb9373ba6b9da08a0820f695c6ab6e"
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
builders |
string[] | List of builder bls keys. |
POST /api/v1/user/delegate/builder
Delegate or revoke builder delegation by supplying either builder entity IDs or explicit BLS public keys. Builder account IDs stay internal.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
builderEntityIds |
No | string | A list of comma separated builder entity IDs. Must not be provided with publicKeys. |
publicKeys |
No | string | A list of comma separated bls builder public keys in hex. Must not be provided with builderEntityIds. |
enable |
Yes | boolean | Delegate or revoke builder delegation. |
Code Sample
POST /api/v1/user/delegate/builder?builderEntityIds=1,2&enable=true HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/delegate/builder"
payload = {
'builderEntityIds': '1,2',
'enable': True
}
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true
}
Response Fields
| Field | Type | Description |
|---|---|---|
success |
bool | Indicates request status. |
Error Codes
| Code | Description |
|---|---|
| BUILDER_DELEGATION_TARGET_REQUIRED | Either builderEntityIds or publicKeys must be provided |
| BUILDER_DELEGATION_TARGET_CONFLICT | builderEntityIds and publicKeys cannot be provided together |
| BUILDER_DELEGATION_ENTITY_ID_INVALID | builderEntityIds contains an invalid builder entity ID |
Note: User needs to delegate a new builder entity 2 seconds before the market close in order to be effective in that epoch. If a market owner has no explicit builder entity or key delegation, the slot uses all builder accounts mapped to a builder entity.
POST /api/v1/builder/update/ofac
Update OFAC flag for existing builder
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
publicKeys |
NO | string | Comma separated list of builder bls public keys in hex. If not provided, updates all builders for the user |
ofac |
YES | boolean | OFAC flag for the builders (default: false) |
Code Sample
POST /api/v1/builder/update/ofac?publicKeys=0x12345...,0x2df345...&ofac=true HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/builder/update/ofac"
payload = {
'publicKeys': '0x123456789abcdef...,0x2df345...',
'ofac': True
}
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true
}
Response Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Whether API call is successful or not |
GET /api/v1/user/delegate/builder
Get delegated builder keys and delegated builder entities for the current user. The response expands entity-based delegation to current builder keys and includes explicitly delegated public keys.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| N/A | N/A | N/A | No parameters required. |
Code Sample
GET /api/v1/user/delegate/builder HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/delegate/builder"
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"delegatedBuilders": [
"0x123456789abcdef...",
"0xfb3456789abcdef..."
],
"delegatedBuilderEntities": [
{
"builderEntityId": 1,
"builderName": "ETHGAS Builder",
"delegatedBuilders": [
"0xa25addc4fc16f72ca667177d7a5533d4287b3574f0127ffc227095e90b0b1fd0dd48c421e04e613d2298fe4dac83a2a5"
]
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
delegatedBuilders |
string[] | Builder keys directly delegated through builder key delegation. |
delegatedBuilderEntities |
object[] | Builder entities delegated by the current user. |
└ builderEntityId
|
integer | Builder entity ID. |
└ builderName
|
string | Builder entity name. |
└ delegatedBuilders
|
string[] | Builder keys resolved from the delegated builder entity. |
GET /api/v1/p/builder/{slot}
Retrieve a list of builders by slot ID.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
slot |
YES | integer | Slot ID to retrieve the builder. |
Code Sample
GET /api/v1/p/builder/123 HTTP/1.1
Host: prod-mainnet.ethgas.com
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/builder/123"
headers = {
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success" : true,
"data": {
"slot": 123,
"builders": [
"0x123456789abcdef...",
"0x156256789ad4fef..."
],
"fallbackBuilder": "0xdsfa56789abcdef...",
"ofac": false
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
slot |
integer | Slot number of the block. |
builders |
string[] | List of available builder keys for the queried slot. |
| fallbackBuilder | string | Public key of the fallback builder in hexadecimal format |
| ofac | boolean | OFAC status for the slot |
GET /api/v1/builder/delegation
To retrieve a list of user address of those who have delegated to current users' builder keys.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| N/A | N/A | N/A | No parameters required. |
Code Sample
GET /api/v1/builder/delegation HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/builder/delegation"
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"builderDelegations": {
"0xefefdffaddfeefef000...": ["0xabadba...", "0x2asdfadv..."],
"0xdfg2345dfg0efefdffa...": ["0x58de13...", "0x2ab05ed1..."]
}
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
builderDelegation |
object | Mapping of builder delegations from corresponding builder key registered by the user |
| └ | string | Corresponding builder key registered by the user |
| └└ | string[] | EOA address who delegated to the builder key |
POST /api/v1/builder/bundle/reject/{slot}
Reject bundles for a specific slot
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
slot |
YES | integer | Slot ID to reject bundles for |
Request Body:
json
{
"rejections": [
{
"uuid": "bundle-uuid-1",
"rejectCode": 1,
"txHashList": ["0x123...", "0x456..."],
"reason": "Bundle rejection reason"
}
]
}
Code Sample
POST /api/v1/builder/bundle/reject/123 HTTP/1.1
Host: prod-mainnet.ethgas.com
Authorization: Bearer {{access_token}}
Content-Type: application/json
{
"rejections": [
{
"uuid": "bundle-uuid-1",
"rejectCode": 1,
"txHashList": ["0x123...", "0x456..."],
"reason": "Bundle rejection reason"
}
]
}
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/builder/bundle/reject/123"
payload = {
"rejections": [
{
"uuid": "bundle-uuid-1",
"rejectCode": 1,
"txHashList": ["0x123...", "0x456..."],
"reason": "Bundle rejection reason"
}
]
}
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, json=payload)
print(response.text)
Example response:
{
"success": true
}
Response Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Whether API call is successful or not |
Error Codes
| Code | Description |
|---|---|
| INVALID_SLOT | Invalid slot ID (must be >= 0) |
| BUNDLE_REJECTION_EMPTY | Rejections list cannot be empty |
GET /api/v1/p/builder/bundle/reject/{slot}/{builderAccountId}
Get bundle rejection information for a specific slot and account
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
slot |
YES | integer | Slot ID to retrieve rejections |
builderAccountId |
YES | integer | Builder account ID |
Code Sample
GET /api/v1/p/builder/bundle/reject/123/456 HTTP/1.1
Host: prod-mainnet.ethgas.com
Content-Type: application/json
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/builder/bundle/reject/123/456"
headers = {
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"rejections": [
{
"uuid": "bundle-uuid-1",
"rejectCode": 1,
"txHashList": ["0x123...", "0x456..."],
"reason": "Bundle rejection reason"
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
rejections |
object[] | List of bundle rejections |
| └ uuid | string | Bundle UUID |
| └ rejectCode | integer | Rejection code |
| └ txHashList | string[] | List of transaction hashes |
| └ reason | string | Rejection reason |
Error Codes
| Code | Description |
|---|---|
| INVALID_SLOT | Invalid slot ID (must be > 0) |
| INVALID_ACCOUNT_ID | Invalid account ID (must be > 0) |
Validator
GET /api/v1/user/validators
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/validators"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/validators"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"validators": [
{
"publicKey": "0x800946ad4fb5f4a0d1f46914cbcdc8f072b462ba8fb2495038897b5f5eac38730d87d0ad00b7bc88e745f4d6d7f1f630",
"ofac": true,
"validatorPayoutAddress": "0x123463a4b065722e99115d6c222f267d9cabb524"
},
{
"publicKey": "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b",
"ofac": false
}
]
}
}
Get list of user validators.
Request
No parameters for this endpoint.
Response Body
| Name | Type | Description |
|---|---|---|
| validators | array of object | List of validator objects |
| └ publicKey | string | Validator public key in hexadecimal format (48 bytes) |
| └ ofac | boolean | OFAC compliance status for this validator |
| └ validatorPayoutAddress | string | Per-validator payout address in hexadecimal format, or null when not set |
GET /api/v1/p/pools
Code sample:
curl -X GET "$ETHGAS_BASE_URL/api/v1/p/pools"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/pools"
response = requests.get(url)
print(response.text)
Example response:
{
"success": true,
"data": {
"poolEntities": [
{ "poolEntityId": 1, "name": "Example Pool" }
]
}
}
Get list of pool entities.
Request
No parameters for this endpoint.
Response Body
| Name | Type | Description |
|---|---|---|
| poolEntities | object[] | List of pool entities |
| └ poolEntityId | integer | Pool entity ID |
| └ name | string | Pool name |
POST /api/v1/p/validator/checkIsOfac
Check whether one or more validator public keys are flagged as OFAC.
Code sample:
curl -X POST "$ETHGAS_BASE_URL/api/v1/p/validator/checkIsOfac?publicKeys=0xabc...,0xdef..."
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/validator/checkIsOfac"
params = {"publicKeys": "0xabc...,0xdef..."}
response = requests.post(url, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"ofacValidator": [
"0xabc..."
]
}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | YES | string | Comma-separated validator public keys (hex, max 100) |
Response Body
| Name | Type | Description |
|---|---|---|
| ofacValidator | string[] | Subset of publicKeys that are OFAC-flagged |
POST /api/v1/validator/register
Validator registering their public key into Ethgas
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
publicKey |
YES | byte | Public key of the validator in hexadecimal. |
Code Sample
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/validator/register?publicKey=0x123423abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef..."
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/register"
payload = {
'publicKey': '0x123423abcdef1234567890abcdef1234567890a...'
}
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"available": true,
"verified": false,
"message": {
"address": "0x1234567890abcdef1234567890abcdef12345678..."
}
}
Response Body
| Field | Type | Description |
|---|---|---|
available |
bool | Indicates whether the request succeeded. |
verified |
bool | Indicates if the validator is verified (present when available is true). |
message |
string | Verification message for validator to sign. |
POST /api/v1/validator/verify
Verify validator public key by verifying with the signed message
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
publicKey |
YES | string | Public key of the validator in hexadecimal. |
signature |
YES | string | Signature in hexadecimal. |
Code Sample
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/validator/verify?publicKey=0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef&signature=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/verify"
payload = {
'publicKey': '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
'signature': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'
}
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"result": 0,
"description": "Success"
}
Response Body
| Field | Type | Description |
|---|---|---|
result |
int | Ordinal value representing the outcome of the verification. |
description |
String | Human-readable message detailing the verification result. |
POST /api/v1/validator/deregister
Validator deregistering their public key from Ethgas
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
publicKeys |
YES | byte | Comma separated public keys of the validator in hexadecimal. |
Code Sample
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/validator/deregister?publicKey=0x123423abcdef1234567890abcdef1234567890,0x3459871234567890abcdef1234567890abcdef1234567890..."
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/deregister"
payload = {
'publicKey': '0x123423abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef,0x2345876124567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'
}
headers = {
'Authorization': 'Bearer {{access_token}}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true
}
Response Body
| Field | Type | Description |
|---|---|---|
success |
boolean | Whether API call is successful or not |
GET /api/v1/validator/fees
Retrieve the list of fee payouts for a given validator key.
Code samples
curl -X GET "https://prod-mainnet.ethgas.com/api/v1/validator/fees?publicKey=0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" \
-H "Authorization: Bearer {{access_token}}"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/fees"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
params = {"publicKey": "0x" + "11" * 48}
response = requests.get(url, params=params, headers=headers)
print(response.json())
Example response:
{
"success": true,
"data": {
"fees": [
{
"slot": 123456,
"accountId": 1234,
"publicKey": "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b",
"validatorPayoutAddress": "0x123463a4b065722e99115d6c222f267d9cabb524",
"quantity": "0.002850675",
"txHash": "0x7f1911fc93c5886b29ff39d044d2d17f471795f3d15bf5cd8d093e3a92ee248e",
"amount": "0.00285067499895",
"gasFee": "0.00000000000105",
"updateDate": 1766024399000,
"batchPayoutSlots": []
}
]
}
}
Get list of validator fees.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKey | NO | string | public key for validators |
| startSlot | NO | integer | start slot number |
| limit | NO | integer | Max number of records to return |
| asc | NO | boolean | true for asc order, default to false for desc order |
Response Body
| Name | Type | Description |
|---|---|---|
| fees | arrary of object | List of validator fee objects |
| └ slot | integer | Slot number of the block |
| └ accountId | integer | Unique ID for each of the user's current & trading accounts assigned by ETHGas |
| └ publicKey | string | Public key of the validator in hexadecimal. |
| └ validatorPayoutAddress | string | Address of the fee recipient in hexadecimal. |
| └ txHash | string | Transaction hash of payout transaction |
| └ quantity | string | Payout quantity of the slot in Eth |
| └ amount | string | Payout amount in payout transaction in Eth. |
| └ gasFee | string | Gas fee charged in payout transaction |
| └ updateDate | integer | Last updated timestamp |
| └ batchPayoutSlots | integer[] | Included previous slots . |
Notes
- Payout amount will include extra payouts which were not paid in previous slot, validator will receive more than payout quantity in payout transaction.
- Gas fee is calculated based on base fee of last block of incoming slot.
POST /api/v1/validator/onchain/payout
Enable or disable on-chain fee payouts for the authenticated user’s validator.
Code samples
curl -X POST "https://prod-mainnet.ethgas.com/api/v1/validator/onchain/payout?enable=0" \
-H "Authorization: Bearer {{access_token}}"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/onchain/payout"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
params = {"enable": 0}
response = requests.post(url, params=params, headers=headers)
print(response.json())
Example response:
{
"success": true,
"data": {}
}
Enable or disable on-chain fee payout for user’s validators.
Request
| Name | Type | Description |
|---|---|---|
| enable | boolean | Whether onchain payout is enabled for the user's validators. Default = true |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Whether API call is successful or not |
| data | object | Response body (empty on success) |
GET /api/v1/validator/mode
Retrieve the trading mode for the authenticated user's preconf account.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/validator/mode"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/mode"
headers = {
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers)
print(response.text)
Example response:
{
"success": true,
"data": {
"mode": 0
}
}
Request
No parameters for this endpoint.
Response Body
| Name | Type | Description |
|---|---|---|
| mode | integer | Account trading mode. 0 = max-profit, 1 = light mode |
Notes
- Light mode applies only to multi-relay slots. On those slots, markets are still created but trading and force-sell are disabled; any MEV-Boost payment to the Ethgas pool is repaid to the validator.
- Markets already created keep the mode they had at creation.
POST /api/v1/validator/mode/enable
Enable light mode for the authenticated user's preconf account. This endpoint can only enable light mode; it cannot disable it or switch back to max-profit.
Optional publicKeys also enable light mode on matching validators owned by the user (regular, SSV, and Obol keys). Keys the user does not own are left unchanged. At most 100 keys may be sent in one request. Fails with USER_LOCKED if the user has locked their account.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/validator/mode/enable?publicKeys=0xabc...,0xdef..."
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/mode/enable"
headers = {"Authorization": "Bearer {{access_token}}"}
params = {"publicKeys": "0xabc...,0xdef..."}
response = requests.post(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"mode": 1
}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | NO | string | Comma-separated validator public keys (hex, with or without 0x, max 100). If omitted, only the account setting is enabled |
Response Body
| Name | Type | Description |
|---|---|---|
| mode | integer | Account trading mode after the update. Always 1 (light mode) on success |
Error Codes
| Code | Description |
|---|---|
| COMMON_NO_ACCOUNT | Authenticated user has no in-preconf account |
| INVALID_PUBLIC_KEY | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
| USER_LOCKED | User account is locked |
Notes
- There is no
moderequest parameter. The API always enables light mode (1). - Markets already created keep the mode they had at creation.
POST /api/v1/validator/update/ofac
Update OFAC flag for the authenticated user’s validators.
If publicKeys is omitted, it updates all validators for the user.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/validator/update/ofac?publicKeys=0xabc...,0xdef...&ofac=true"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/update/ofac"
headers = {"Authorization": "Bearer {{access_token}}"}
params = {"publicKeys": "0xabc...,0xdef...", "ofac": True}
response = requests.post(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | YES | string | Explicit comma-separated validator keys, max 100. Missing/blank keys are rejected; update-all is not supported. |
| ofac | NO | boolean | OFAC flag (default: false) |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Whether API call is successful or not |
| data | object | Response body (empty on success) |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
POST /api/v1/validator/verify/batch
Verify multiple validator BLS signatures in one request.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/validator/verify/batch?publicKeys=0xabc...,0xdef...&signatures=0xsig1...,0xsig2..."
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/verify/batch"
headers = {"Authorization": "Bearer {{access_token}}"}
params = {
"publicKeys": "0xabc...,0xdef...",
"signatures": "0xsig1...,0xsig2..."
}
response = requests.post(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"0xabc...": { "result": 0, "description": "Success" },
"0xdef...": { "result": 2, "description": "Invalid signature" }
}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | YES | string | Comma-separated validator public keys (hex, max 100) |
| signatures | YES | string | Comma-separated BLS signatures (hex), must match publicKeys count |
Response Body
| Name | Type | Description |
|---|---|---|
| data | object | Map of publicKey to verification result |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY | Invalid validator public key format |
| INVALID_SIGNATURE | Invalid signature format |
| VALIDATOR_SIGNATURE_SIZE_NOT_MATCH_PUBLIC_KEY |
publicKeys and signatures size mismatch |
| VALIDATOR_SIGNATURE_MAX | Too many signatures (max 100) |
POST /api/v1/validator/update/validatorPayoutAddress
publicKeys is required for both setting and clearing payout addresses. Supply 1–100 comma-separated keys, each exactly 48 bytes (96 hex digits, optional 0x prefix). Missing/blank keys, invalid hex, incorrect lengths and empty list elements return INVALID_PUBLIC_KEY; more than 100 keys returns VALIDATORS_MAX. These are application validation failures, not retryable server errors.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/validator/update/validatorPayoutAddress?publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890&validatorPayoutAddress=0x1234567890abcdef1234567890abcdef12345678"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/validator/update/validatorPayoutAddress"
payload = {
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
'validatorPayoutAddress': '0x1234567890abcdef1234567890abcdef12345678'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/validator/update/validatorPayoutAddress?publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890&disable=true"
Example response:
{
"success": true,
"data": {}
}
Update validator payout address for a targeted set of regular validators. Only validators registered and owned by the authenticated user are updated; unregistered or non-owned keys are silently ignored.
Fails with USER_LOCKED if the user has locked their account.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | YES | String | Comma-separated list of validator public keys (hex format, max 100). Required; update-all is not supported |
| validatorPayoutAddress | NO | String | Ethereum address to set as the payout address for matched validators |
| disable | NO | Boolean | Set to true to clear validatorPayoutAddress for matched validators |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY |
publicKeys is missing, blank, malformed, or contains an invalid key |
| VALIDATORS_MAX | More than 100 keys supplied |
| INVALID_ADDRESS |
validatorPayoutAddress is invalid, or the request provides neither validatorPayoutAddress nor disable=true, or both at the same time |
| USER_LOCKED | User account is locked |
SSV Validator
POST /api/v1/user/ssv/operator/register
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/ssv/operator/register?ownerAddress=0x1234567890123456789012345678901234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/register"
payload = {
'ownerAddress': '0x1234567890123456789012345678901234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"available": true,
"messageToSign": "Register SSV operator: 0x1234567890123456789012345678901234567890"
}
}
Request verification for SSV operator registration.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| ownerAddress | YES | String | SSV operator owner address (hex format) |
Response Body
| Name | Type | Description |
|---|---|---|
| available | boolean | Whether the operator address is available for registration |
| messageToSign | string | Message to sign for verification |
Error Codes
| Code | Description |
|---|---|
| SSV_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
POST /api/v1/user/ssv/operator/deregister
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/ssv/operator/deregister?ownerAddress=0x1234567890123456789012345678901234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/deregister"
payload = {
'ownerAddress': '0x1234567890123456789012345678901234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Deregister an SSV operator.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| ownerAddress | YES | String | SSV operator owner address (hex format) |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Error Codes
| Code | Description |
|---|---|
| SSV_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| SSV_OPERATOR_NOT_REGISTERED | Operator is not registered |
POST /api/v1/user/ssv/operator/verify
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/ssv/operator/verify?ownerAddress=0x1234567890123456789012345678901234567890&signature=0x1234567890abcdef&autoImport=1&sync=1"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/verify"
payload = {
'ownerAddress': '0x1234567890123456789012345678901234567890',
'signature': '0x1234567890abcdef',
'autoImport': '1',
'sync': '1'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response (with sync=1):
{
"success": true,
"data": {
"validators": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
}
Example response (with sync=0):
{
"success": true,
"data": {}
}
Verify SSV operator signature and complete registration.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| ownerAddress | YES | String | SSV operator owner address (hex format) |
| signature | YES | String | Signature of the message to sign (hex format) |
| autoImport | NO | Boolean | Whether to automatically import validators (default: false) |
| sync | NO | Boolean | Whether to return validator list in response (default: false) |
Response Body
| Name | Type | Description |
|---|---|---|
| validators | string[] | List of validator public keys (only returned when sync=true) |
Error Codes
| Code | Description |
|---|---|
| SSV_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| SSV_OPERATOR_INVALID_SIGNATURE | Invalid signature format or verification failed |
POST /api/v1/user/ssv/operator/verifyByTx
Verify SSV operator registration using an on-chain transaction hash.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/ssv/operator/verifyByTx?ownerAddress=0x1234567890123456789012345678901234567890&txHash=0xabc...&autoImport=1&sync=1"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/verifyByTx"
headers = {"Authorization": "Bearer {{access_token}}"}
params = {
"ownerAddress": "0x1234567890123456789012345678901234567890",
"txHash": "0xabc...",
"autoImport": True,
"sync": True
}
response = requests.post(url, headers=headers, params=params)
print(response.text)
Example response (with sync=1):
{
"success": true,
"data": {
"validators": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
}
Example response (with sync=0):
{
"success": true,
"data": {}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| ownerAddress | YES | String | SSV operator owner address (hex format) |
| txHash | YES | String | Transaction hash (hex) |
| autoImport | NO | Boolean | Whether to automatically import validators (default: false) |
| sync | NO | Boolean | Whether to return validator list in response (default: false) |
Response Body
| Name | Type | Description |
|---|---|---|
| validators | string[] | List of validator public keys (only returned when sync=true) |
Error Codes
| Code | Description |
|---|---|
| SSV_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| SSV_OPERATOR_NOT_REGISTERED | Operator is not registered |
| SSV_OPERATOR_INVALID_TX | Transaction hash is invalid |
| SSV_OPERATOR_TX_NOT_FOUND | Transaction not found |
GET /api/v1/user/ssv/operators
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/ssv/operators"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operators"
payload = {}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"ssvOperators": [
{
"ownerId": 1,
"userId": 73,
"ownerAddress": "0x1234567890123456789012345678901234567890"
}
]
}
}
List all SSV operators for the current user.
Request
No parameters required.
Response Body
| Name | Type | Description |
|---|---|---|
| ssvOperators | object[] | List of SSV operator objects |
| └ ownerId | integer | Unique owner ID |
| └ userId | integer | User ID associated with the operator |
| └ ownerAddress | string | Operator owner address (hex format) |
POST /api/v1/user/ssv/operator/validator/register
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/ssv/operator/validator/register?ownerAddress=0x1234567890123456789012345678901234567890&publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890,0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/validator/register"
payload = {
'ownerAddress': '0x1234567890123456789012345678901234567890',
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890,0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"validators": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
}
Register validators with an SSV operator. If no publicKeys are provided, it will refresh the validator list from the SSV network.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| ownerAddress | YES | String | SSV operator owner address (hex format) |
| publicKeys | NO | String | Comma-separated list of validator public keys (hex format, max 100). If not provided, refreshes validator list from SSV network |
Response Body
| Name | Type | Description |
|---|---|---|
| validators | string[] | List of successfully added validator public keys |
Error Codes
| Code | Description |
|---|---|
| SSV_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| SSV_OPERATOR_NOT_REGISTERED | Operator is not registered |
| SSV_VALIDATORS_REQUIRED | At least one validator public key is required |
| SSV_VALIDATORS_INVALID | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
POST /api/v1/user/ssv/operator/validator/deregister
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/ssv/operator/validator/deregister?ownerAddress=0x1234567890123456789012345678901234567890&publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/validator/deregister"
payload = {
'ownerAddress': '0x1234567890123456789012345678901234567890',
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"removed": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
}
Deregister validators from an SSV operator. If no publicKeys are provided, it will remove all validators for the operator.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| ownerAddress | YES | String | SSV operator owner address (hex format) |
| publicKeys | NO | String | Comma-separated list of validator public keys (hex format, max 100). If not provided, removes all validators for the operator |
Response Body
| Name | Type | Description |
|---|---|---|
| removed | string[] | List of successfully removed validator public keys |
Error Codes
| Code | Description |
|---|---|
| SSV_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| SSV_OPERATOR_NOT_REGISTERED | Operator is not registered |
| SSV_VALIDATORS_REQUIRED | At least one validator public key is required |
| SSV_VALIDATORS_INVALID | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
GET /api/v1/user/ssv/operator/validators
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/ssv/operator/validators?ownerAddress=0x1234567890123456789012345678901234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/validators"
payload = {
'ownerAddress': '0x1234567890123456789012345678901234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"validators": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
}
List validators for a specific SSV operator.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| ownerAddress | YES | String | SSV operator owner address (hex format) |
Response Body
| Name | Type | Description |
|---|---|---|
| validators | string[] | List of validator public keys (hex format) |
Error Codes
| Code | Description |
|---|---|
| SSV_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| SSV_OPERATOR_NOT_REGISTERED | Operator is not registered |
POST /api/v1/ssv/validator/mode/enable
Enable light mode for the authenticated user's preconf account. This endpoint can only enable light mode; it cannot disable it or switch back to max-profit.
Optional publicKeys also enable light mode on matching SSV validators owned by the user. Regular and Obol keys are not updated here (use POST /api/v1/validator/mode/enable or POST /api/v1/obol/validator/mode/enable). Keys the user does not own are left unchanged. At most 100 keys may be sent in one request. Fails with USER_LOCKED if the user has locked their account.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/ssv/validator/mode/enable?publicKeys=0xabc...,0xdef..."
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/ssv/validator/mode/enable"
headers = {"Authorization": "Bearer {{access_token}}"}
params = {"publicKeys": "0xabc...,0xdef..."}
response = requests.post(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"mode": 1
}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | NO | string | Comma-separated SSV validator public keys (hex, with or without 0x, max 100). If omitted, only the account setting is enabled |
Response Body
| Name | Type | Description |
|---|---|---|
| mode | integer | Account trading mode after the update. Always 1 (light mode) on success |
Error Codes
| Code | Description |
|---|---|
| COMMON_NO_ACCOUNT | Authenticated user has no in-preconf account |
| INVALID_PUBLIC_KEY | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
| USER_LOCKED | User account is locked |
Notes
- There is no
moderequest parameter. The API always enables light mode (1). - Markets already created keep the mode they had at creation.
POST /api/v1/user/ssv/operator/validator/update/ofac
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/ssv/operator/validator/update/ofac?publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890&ofac=true"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/validator/update/ofac"
payload = {
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
'ofac': 'true'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Update OFAC flag for SSV validators.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | YES | string | Explicit comma-separated validator keys, max 100. Missing/blank keys are rejected; update-all is not supported. |
| ofac | NO | Boolean | OFAC compliance flag (default: false) |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
POST /api/v1/user/ssv/operator/validator/update/validatorPayoutAddress
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/user/ssv/operator/validator/update/validatorPayoutAddress?publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890&validatorPayoutAddress=0x1234567890abcdef1234567890abcdef12345678"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/ssv/operator/validator/update/validatorPayoutAddress"
payload = {
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
'validatorPayoutAddress': '0x1234567890abcdef1234567890abcdef12345678'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/user/ssv/operator/validator/update/validatorPayoutAddress?publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890&disable=true"
Example response:
{
"success": true,
"data": {}
}
Update validator payout address for a targeted set of SSV validators. Only validators registered and owned by the authenticated user are updated; unregistered or non-owned keys are silently ignored.
Fails with USER_LOCKED if the user has locked their account.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | YES | String | Comma-separated list of SSV validator public keys (hex format, max 100). Required; update-all is not supported |
| validatorPayoutAddress | NO | String | Ethereum address to set as the payout address for matched validators |
| disable | NO | Boolean | Set to true to clear validatorPayoutAddress for matched validators |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY |
publicKeys is missing, blank, malformed, or contains an invalid key |
| VALIDATORS_MAX | More than 100 keys supplied |
| INVALID_ADDRESS |
validatorPayoutAddress is invalid, or the request provides neither validatorPayoutAddress nor disable=true, or both at the same time |
| USER_LOCKED | User account is locked |
Obol Validator
POST /api/v1/user/obol/operator/register
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/obol/operator/register?operatorAddress=0x1234567890123456789012345678901234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/register"
payload = {
'operatorAddress': '0x1234567890123456789012345678901234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"available": true,
"messageToSign": "Register Obol operator: 0x1234567890123456789012345678901234567890"
}
}
Request verification for Obol operator registration.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| operatorAddress | YES | String | Obol operator address (hex format) |
Response Body
| Name | Type | Description |
|---|---|---|
| available | boolean | Whether the operator address is available for registration |
| messageToSign | string | Message to sign for verification |
Error Codes
| Code | Description |
|---|---|
| OBOL_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
POST /api/v1/user/obol/operator/deregister
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/obol/operator/deregister?operatorAddress=0x1234567890123456789012345678901234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/deregister"
payload = {
'operatorAddress': '0x1234567890123456789012345678901234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Deregister an Obol operator.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| operatorAddress | YES | String | Obol operator address (hex format) |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Error Codes
| Code | Description |
|---|---|
| OBOL_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
POST /api/v1/user/obol/operator/verify
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/obol/operator/verify?operatorAddress=0x1234567890123456789012345678901234567890&signature=0x1234567890abcdef&autoImport=1"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/verify"
payload = {
'operatorAddress': '0x1234567890123456789012345678901234567890',
'signature': '0x1234567890abcdef',
'autoImport': '1'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"operator": {
"operatorId": 1,
"userId": 73,
"address": "0x1234567890123456789012345678901234567890",
"ofac": false,
"accountId": 2170,
"collateralPerSlot": "10.5"
}
}
}
Verify Obol operator signature and complete registration.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| operatorAddress | YES | String | Obol operator address (hex format) |
| signature | YES | String | Signature of the message to sign (hex format) |
| autoImport | NO | Boolean | Whether to automatically import cluster definitions (default: false) |
Response Body
| Name | Type | Description |
|---|---|---|
| operator | object | Registered operator object |
| └ operatorId | integer | Unique operator ID |
| └ userId | integer | User ID associated with the operator |
| └ address | string | Operator address (hex format) |
| └ ofac | boolean | OFAC compliance status |
| └ accountId | integer | Associated account ID |
| └ collateralPerSlot | string | Collateral per slot amount |
| └ validatorKey | string | Validator key (if any) |
| └ clusterId | integer | Cluster ID (if any) |
Error Codes
| Code | Description |
|---|---|
| OBOL_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| OBOL_OPERATOR_INVALID_SIGNATURE | Invalid signature format or verification failed |
POST /api/v1/user/obol/operator/refresh
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/obol/operator/refresh?operatorAddress=0x1234567890123456789012345678901234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/refresh"
payload = {
'operatorAddress': '0x1234567890123456789012345678901234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"clusters": {
"0xabcdef1234567890": {
"clusterId": 1,
"config": "0x1234567890abcdef",
"operators": ["0x1234567890123456789012345678901234567890"],
"distributedValidatorKeys": ["0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"]
}
}
}
}
Refresh Obol operator cluster definitions.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| operatorAddress | YES | String | Obol operator address (hex format) |
Response Body
| Name | Type | Description |
|---|---|---|
| clusters | object | Map of cluster definitions |
| └ [clusterKey] | object | Cluster definition object |
| └└ clusterId | integer | Unique cluster ID |
| └└ config | string | Cluster configuration (hex format) |
| └└ operators | string[] | List of operator addresses |
| └└ distributedValidatorKeys | string[] | List of distributed validator keys |
Error Codes
| Code | Description |
|---|---|
| OBOL_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
GET /api/v1/user/obol/operators
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/obol/operators"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operators"
payload = {}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"operators": [
{
"operatorId": 1,
"userId": 73,
"address": "0x1234567890123456789012345678901234567890",
"ofac": false,
"accountId": 2170,
"collateralPerSlot": "10.5",
"clusterId": 1
}
]
}
}
List all Obol operators for the current user.
Request
No parameters required.
Response Body
| Name | Type | Description |
|---|---|---|
| operators | object[] | List of operator objects |
| └ operatorId | integer | Unique operator ID |
| └ userId | integer | User ID associated with the operator |
| └ address | string | Operator address (hex format) |
| └ ofac | boolean | OFAC compliance status |
| └ accountId | integer | Associated account ID |
| └ collateralPerSlot | string | Collateral per slot amount |
| └ validatorKey | string | Validator key (if any) |
| └ clusterId | integer | Cluster ID (if any) |
GET /api/v1/user/obol/operator/validators
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X GET "$ETHGAS_BASE_URL/api/v1/user/obol/operator/validators?operatorAddress=0x1234567890123456789012345678901234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/validators"
payload = {
'operatorAddress': '0x1234567890123456789012345678901234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.get(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"validators": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
}
List validators for a specific Obol operator.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| operatorAddress | YES | String | Obol operator address (hex format) |
Response Body
| Name | Type | Description |
|---|---|---|
| validators | string[] | List of validator public keys (hex format) |
Error Codes
| Code | Description |
|---|---|
| OBOL_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
POST /api/v1/user/obol/operator/validator/register
Supported registration scopes: supply publicKeys to register selected keys, or omit it to import all available keys under the operator. Both modes are intentional API features. An empty string is not the same as omission.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/obol/operator/validator/register?operatorAddress=0x1234567890123456789012345678901234567890&publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890,0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/validator/register"
payload = {
'operatorAddress': '0x1234567890123456789012345678901234567890',
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890,0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"added": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
}
Register validators with an Obol operator.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| operatorAddress | YES | String | Obol operator address (hex format) |
| publicKeys | NO | string | Comma-separated keys, max 100 when supplied. Omission imports all available keys for this operator. |
Response Body
| Name | Type | Description |
|---|---|---|
| added | string[] | List of successfully added validator public keys |
Error Codes
| Code | Description |
|---|---|
| OBOL_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| OBOL_VALIDATORS_REQUIRED | At least one validator public key is required |
| OBOL_VALIDATORS_INVALID | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
POST /api/v1/user/obol/operator/validator/deregister
Supported deregistration scopes: supply publicKeys to deregister selected keys, or omit it to deregister all registered keys under the operator. Both modes are intentional API features. For all keys, send operatorAddress without a publicKeys parameter. An empty string is not the same as omission.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/obol/operator/validator/deregister?operatorAddress=0x1234567890123456789012345678901234567890&publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/validator/deregister"
payload = {
'operatorAddress': '0x1234567890123456789012345678901234567890',
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {
"removed": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
}
Deregister validators from an Obol operator.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| operatorAddress | YES | String | Obol operator address (hex format) |
| publicKeys | NO | string | Comma-separated keys, max 100 when supplied. Omission removes all registered keys for this operator. |
Response Body
| Name | Type | Description |
|---|---|---|
| removed | string[] | List of successfully removed validator public keys |
Error Codes
| Code | Description |
|---|---|
| OBOL_OPERATOR_INVALID_ADDRESS | Invalid operator address format |
| OBOL_VALIDATORS_REQUIRED | At least one validator public key is required |
| OBOL_VALIDATORS_INVALID | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
POST /api/v1/obol/validator/mode/enable
Enable light mode for the authenticated user's preconf account. This endpoint can only enable light mode; it cannot disable it or switch back to max-profit.
Optional publicKeys also enable light mode on matching Obol validators owned by the user. Regular and SSV keys are not updated here (use POST /api/v1/validator/mode/enable or POST /api/v1/ssv/validator/mode/enable). Keys the user does not own are left unchanged. At most 100 keys may be sent in one request. Fails with USER_LOCKED if the user has locked their account.
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/obol/validator/mode/enable?publicKeys=0xabc...,0xdef..."
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/obol/validator/mode/enable"
headers = {"Authorization": "Bearer {{access_token}}"}
params = {"publicKeys": "0xabc...,0xdef..."}
response = requests.post(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"mode": 1
}
}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | NO | string | Comma-separated Obol validator public keys (hex, with or without 0x, max 100). If omitted, only the account setting is enabled |
Response Body
| Name | Type | Description |
|---|---|---|
| mode | integer | Account trading mode after the update. Always 1 (light mode) on success |
Error Codes
| Code | Description |
|---|---|
| COMMON_NO_ACCOUNT | Authenticated user has no in-preconf account |
| INVALID_PUBLIC_KEY | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
| USER_LOCKED | User account is locked |
Notes
- There is no
moderequest parameter. The API always enables light mode (1). - Markets already created keep the mode they had at creation.
POST /api/v1/user/obol/operator/validator/update/ofac
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "$ETHGAS_BASE_URL/api/v1/user/obol/operator/validator/update/ofac?publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890&ofac=true"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/validator/update/ofac"
payload = {
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
'ofac': 'true'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
Example response:
{
"success": true,
"data": {}
}
Update OFAC flag for Obol validators.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | YES | string | Explicit comma-separated validator keys, max 100. Missing/blank keys are rejected; update-all is not supported. |
| ofac | YES | Boolean | OFAC compliance flag |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY | Invalid validator public key format |
| VALIDATORS_MAX | Maximum 100 validators allowed per request |
POST /api/v1/user/obol/operator/validator/update/validatorPayoutAddress
Code sample:
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/user/obol/operator/validator/update/validatorPayoutAddress?publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890&validatorPayoutAddress=0x1234567890abcdef1234567890abcdef12345678"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/user/obol/operator/validator/update/validatorPayoutAddress"
payload = {
'publicKeys': '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
'validatorPayoutAddress': '0x1234567890abcdef1234567890abcdef12345678'
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{access_token}}'
}
response = requests.post(url, headers=headers, params=payload)
print(response.text)
curl -H "Authorization: Bearer {{access_token}}" -X POST "/api/v1/user/obol/operator/validator/update/validatorPayoutAddress?publicKeys=0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890&disable=true"
Example response:
{
"success": true,
"data": {}
}
Update validator payout address for a targeted set of Obol validators. Only validators registered and owned by the authenticated user are updated; unregistered or non-owned keys are silently ignored.
Fails with USER_LOCKED if the user has locked their account.
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| publicKeys | YES | String | Comma-separated list of Obol validator public keys (hex format, max 100). Required; update-all is not supported |
| validatorPayoutAddress | NO | String | Ethereum address to set as the payout address for matched validators |
| disable | NO | Boolean | Set to true to clear validatorPayoutAddress for matched validators |
Response Body
| Name | Type | Description |
|---|---|---|
| success | boolean | Operation success status |
Error Codes
| Code | Description |
|---|---|
| INVALID_PUBLIC_KEY |
publicKeys is missing, blank, malformed, or contains an invalid key |
| VALIDATORS_MAX | More than 100 keys supplied |
| INVALID_ADDRESS |
validatorPayoutAddress is invalid, or the request provides neither validatorPayoutAddress nor disable=true, or both at the same time |
| USER_LOCKED | User account is locked |
Dashboard
Block and payment history can change when a payout is sent again. Use the same filters on every page. Payment history returns the latest successful payment for each original slot. slotTime and paymentTime are UTC ISO-8601. Amounts are decimal strings. Hex values may omit 0x.
Dashboard routes are public. They are under /api/v1/p/ and do not require a token.
Timestamps (startTime, endTime) must be ISO-8601 strings (e.g. 2026-01-13T00:00:00Z). Invalid timestamps return SYSTEM_VALIDATION.
Validator usage guide
Common questions and where to find the answer:
| I want to... | Use |
|---|---|
| See my recent block proposals and their status |
GET /api/v1/p/dashboard/operator/blockHistory (pass validatorUserId or operatorName — whichever you have on hand, not both) |
| See my payout/payment history ordered by paying slot |
GET /api/v1/p/dashboard/operator/paymentHistory (pass validatorUserId or operatorName — whichever you have on hand, not both) |
Tip: any endpoint that takes startTime/endTime will default sensibly if you omit them (usually "today" or "the last 180 days") — you don't need to compute a range just to get a quick look at current standing.
GET /api/v1/p/dashboard/operator/blockHistory
Code sample:
curl -X GET "https://prod-mainnet.ethgas.com/api/v1/p/dashboard/operator/blockHistory?validatorUserId=73&limit=10"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/dashboard/operator/blockHistory"
params = {
"validatorUserId": 73,
"limit": 10
}
headers = {
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"data": [
{
"dvtType": "SSV",
"blockTime": "2026-07-10T08:15:24Z",
"slot": 9876543,
"blockNum": 20456789,
"slashingResponse": "Valid",
"blockStatus": "Proposed",
"poolName": "Not available",
"dvt": 1,
"builderName": "titanbuilder",
"wholeBlockValue": "0.05123456",
"blockReward": "0.04123456",
"gasUsed": 12500000,
"txNum": 185,
"collateral": "1.00000000",
"builderSubmissionTime": 350,
"pendingPayout": "0.00000000",
"txIncluded": true,
"txHash": "0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123ab",
"txValue": "0.04000000",
"repaymentPending": false,
"multiRelay": false,
"realtime": false,
"validatorUserId": 73,
"operatorName": "MyOperator",
"wholeBlockMarketStatus": 0,
"payoutStatus": 10,
"validatorPayoutAddress": "0x1234567890123456789012345678901234567890",
"validatorSigningTime": 120
}
]
}
}
Get operator block history (public; no session required).
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| validatorUserId | NO | integer | Validator user ID |
| operatorName | NO | string | Operator name |
| slots | NO | string | Comma-separated slot numbers |
| startTime | NO | string | ISO-8601 start time |
| endTime | NO | string | ISO-8601 end time |
| limit | NO | integer | Max records (default: 100) |
| offset | NO | integer | Pagination offset (default: 0) |
| repaymentPending | NO | boolean | Filter (implementation-specific) |
| pendingPayoutOnly | NO | boolean | Filter (implementation-specific) |
| underReview | NO | boolean | Filter (implementation-specific) |
| missedOnly | NO | boolean | Filter (implementation-specific) |
| publicKeys | NO | string | Comma-separated validator pubkeys (hex; 0x optional) |
Response Body
| Name | Type | Description |
|---|---|---|
| data | object[] | List of block history entries |
| └ dvtType | string | DVT type (e.g. SSV, Obol), if applicable |
| └ blockTime | string | Block time (ISO-8601) |
| └ slot | integer | Slot number |
| └ blockNum | integer | Block number |
| └ slashingResponse | string | Block slashing status in market — see values below |
| └ blockStatus | string | Status shown to validators — see values below |
| └ poolName | string | Pool name, or Not available
|
| └ dvt | integer | DVT flag |
| └ builderName | string | Builder name, or Not available
|
| └ wholeBlockValue | string | Whole block value (ETH) |
| └ blockReward | string | Block reward (ETH) |
| └ gasUsed | integer | Gas used in the block |
| └ txNum | integer | Number of transactions in the block |
| └ collateral | string | Collateral amount |
| └ builderSubmissionTime | integer | Builder submission time (ms) |
| └ pendingPayout | string | Pending payout amount |
| └ slotsRepaid | string | Slots this payout was repaid across, if any |
| └ txIncluded | boolean | Whether the payout tx has been included |
| └ txHash | string | Payout transaction hash |
| └ txValue | string | Payout transaction value |
| └ repaymentPending | boolean | Whether repayment is pending |
| └ repaidInSlot | integer | Slot in which repayment occurred, if any |
| └ multiRelay | boolean | Whether this is a multi-relay block |
| └ realtime | boolean | Whether this row is a realtime (unsettled) entry |
| └ validatorUserId | integer | Validator user ID |
| └ operatorName | string | Operator name |
| └ wholeBlockMarketStatus | integer | Whole-block market status code |
| └ payoutStatus | integer | Payout status code |
| └ validatorPayoutAddress | string | Validator payout address (hex) |
| └ validatorSigningTime | integer | Validator signing time (ms) |
| └ resendPayoutSlots | string | Slots on which the payout was resent, if any |
blockStatus values:
| Value | Meaning |
|---|---|
Pending |
Block outcome not yet finalized |
Missed |
Validator missed the slot |
Proposed |
Block was successfully proposed |
Note: blockStatus (shown to validators) is a simplified 3-value status. slashingResponse (block slashing status in market) is a separate, more granular field with its own values: Missed, Vanilla Block, Invalid, Valid, Not Sold.
GET /api/v1/p/dashboard/operator/paymentHistory
Code sample:
curl -X GET "https://prod-mainnet.ethgas.com/api/v1/p/dashboard/operator/paymentHistory?validatorUserId=73&limit=10"
Resolve by operator name (matches display_name or verified_name):
curl -X GET "https://prod-mainnet.ethgas.com/api/v1/p/dashboard/operator/paymentHistory?operatorName=MyOperator&limit=10"
Filter payouts by paying-slot range (inclusive on both bounds):
curl -X GET "https://prod-mainnet.ethgas.com/api/v1/p/dashboard/operator/paymentHistory?validatorUserId=73&fromPaymentSlot=14755922&toPaymentSlot=14756468&limit=100"
Filter by original/paid slot(s), same comma-separated form as blockHistory slots:
curl -X GET "https://prod-mainnet.ethgas.com/api/v1/p/dashboard/operator/paymentHistory?validatorUserId=73&slots=14755922,14756468&limit=100"
import requests
url = "https://prod-mainnet.ethgas.com/api/v1/p/dashboard/operator/paymentHistory"
params = {
"validatorUserId": 73,
"limit": 10
}
headers = {
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
Example response:
{
"success": true,
"data": {
"data": [
{
"slot": 14755922,
"slotTime": "2026-07-10T08:15:24.000Z",
"paymentSlot": 14756468,
"paymentTime": "2026-07-10T12:33:59.000Z",
"txHash": "B79D11F2746CE7C7D00049C75B929A316C4B3D342280402AC2395D9BA375AC5A",
"txValue": "0.0220845434462",
"validatorUserId": 73,
"operatorName": "MyOperator",
"validatorPayoutAddress": "1234567890123456789012345678901234567890"
},
{
"slot": 14756468,
"slotTime": "2026-07-10T12:33:59.000Z",
"paymentSlot": 14756468,
"paymentTime": "2026-07-10T12:33:59.000Z",
"txHash": "B79D11F2746CE7C7D00049C75B929A316C4B3D342280402AC2395D9BA375AC5A",
"txValue": "0.0220845434462",
"validatorUserId": 73,
"operatorName": "MyOperator",
"validatorPayoutAddress": "1234567890123456789012345678901234567890"
}
]
}
}
Get paid payout history for a validator (public; no session required), ordered by paying slot then original slot (newest first by default). Pass validatorUserId and/or operatorName (filter matches user.display_name or user.verified_name). Response operatorName is COALESCE(verified_name, display_name) (same selection as blockHistory). Includes direct pays and resend/repay legs (including missed original slots that were repaid later). Sourced from validator_payout / validator_payout_eth_tx (not the ethereum sync materialization).
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| validatorUserId | NO | integer | Validator user ID |
| operatorName | NO | string | Filter by operator display_name or verified_name (same value matches either) |
| startTime | NO | string | ISO-8601 lower bound on payment slot time (paymentTime) |
| endTime | NO | string | ISO-8601 upper bound on payment slot time (paymentTime) |
| fromPaymentSlot | NO | integer | Inclusive lower bound on paying slot (paymentSlot) |
| toPaymentSlot | NO | integer | Inclusive upper bound on paying slot (paymentSlot) |
| slots | NO | string | Comma-separated original/paid slot numbers (slot), same form as blockHistory |
| limit | NO | integer | Max records (default: 100) |
| offset | NO | integer | Pagination offset (default: 0) |
| asc | NO | boolean | Sort ascending by paying slot, then original slot (default: false = newest first) |
| txHash | NO | string | Filter to payments covered by this payout tx hash (32-byte hex; 0x prefix optional). A batch resend can return multiple rows. |
Response Body
| Name | Type | Description |
|---|---|---|
| data | object[] | List of payment history entries |
| └ slot | integer | Original proposal slot |
| └ slotTime | string | Consensus time of the original slot (ISO-8601) |
| └ paymentSlot | integer | Paying slot: original slot for a direct pay, or the later resend paying slot |
| └ paymentTime | string | Consensus time of paymentSlot (ISO-8601) |
| └ txHash | string | On-chain paying payout tx hash (hex, no 0x prefix) |
| └ txValue | string | Paying tx ETH amount |
| └ validatorUserId | integer | Validator user ID |
| └ operatorName | string | Operator name (COALESCE(verified_name, display_name), same as blockHistory) |
| └ validatorPayoutAddress | string | Validator payout address for the original market/slot (hex, no 0x prefix) |
WEBSOCKET
Path
/ws
Stream public and private market data. Use the WebSocket base URL for your environment. Mainnet is wss://prod-mainnet.ethgas.com/ws. Hoodi is wss://hoodi.app.ethgas.com/ws.
# A sample python script to connect to our webserver to subscribe to different channels.
import json
import websocket
from websocket import WebSocket
__ws_url = "wss://prod-mainnet.ethgas.com/ws"
def on_open(ws: WebSocket):
message = {
"op": "subscribe",
"args": [
{
"channel": "orderBookUpdate",
"marketType": "wholeBlock"
}
]
}
ws.send(json.dumps(message))
def on_message(ws: WebSocket, message: str):
print(f"Received message: {message}")
def on_error(ws: WebSocket, error: Exception):
print(f"Error: {error}")
def on_close(ws: WebSocket, close_status_code: int, close_msg: str):
print("WebSocket closed")
if __name__ == "__main__":
ws_app = websocket.WebSocketApp(
__ws_url,
on_open=on_open,
on_message=on_message,
on_close=on_close,
on_error=on_error,
)
ws_app.run_forever()
Message Structure
Request
| Field | Required | Type | Description |
|---|---|---|---|
| op | YES | string | operation type |
| args | YES | object[] | list of operation arguments |
Operation Types
- subscribe
- unsubscribe
- query
- login
Response
Command responses (login, subscribe, unsubscribe, error) use:
| Field | Type | Description |
|---|---|---|
| event | string | Response event type |
| arg | object | Response payload for the command |
| code | integer | Result code |
| msg | string | Result message |
| connId | string | Connection ID |
Stream responses use:
| Field | Type | Description |
|---|---|---|
| e | string | Event type |
| E | integer | Event timestamp |
| s | string | Instrument ID |
| a | string | Action type, when applicable |
| P | object | Data of corresponding event type |
Query responses use:
| Field | Type | Description |
|---|---|---|
| q | string | Query type |
| s | string | Instrument ID, when applicable |
| P | object | Query payload |
Commands
subscribe
Subscribe to one or multiple topics
{
"op": "subscribe",
"args": [
{
"channel": "preconfMarketUpdate",
"marketType": "inclusionPreconf"
},
{
"channel": "candlestickUpdate",
"marketType": "wholeBlock"
},
{
"channel": "recentTradeUpdate",
"marketType": "inclusionPreconf"
},
{
"channel": "orderBookUpdate",
"marketType": "inclusionPreconf"
},
{
"channel": "tickerUpdate",
"marketType": "inclusionPreconf"
},
{
"channel": "inclusionPreconfSaleUpdate"
},
{
"channel": "blockBuilderUpdate"
}
]
}
unsubscribe
Unsubscribe from one or multiple topics
{
"op": "unsubscribe",
"args": [
{
"channel": "preconfMarketUpdate",
"marketType": "inclusionPreconf"
},
{
"channel": "candlestickUpdate",
"marketType": "wholeBlock"
},
{
"channel": "recentTradeUpdate",
"marketType": "inclusionPreconf"
},
{
"channel": "orderBookUpdate",
"marketType": "inclusionPreconf"
},
{
"channel": "tickerUpdate",
"marketType": "inclusionPreconf"
},
{
"channel": "inclusionPreconfSaleUpdate"
},
{
"channel": "blockBuilderUpdate"
}
]
}
query
Query data from a topic
Example
{
"op": "query",
"args": [
{
"queryType": "currentSlot"
},
{
"queryType": "preconfMarkets",
"marketType": "inclusionPreconf"
},
{
"queryType": "orderBook",
"marketType": "wholeBlock"
}
]
}
login
Login to the websocket server for acessing private channel/query
Example Request
{
"op": "login",
"args": [
{
"accessToken": "<access-or-refresh-token>"
}
]
}
Example Response
{
"event": "login",
"code": 0,
"msg": "",
"connId": "25f9ee2c"
}
Channel
Within a channel, you can subscribe to topics needed to receive real time updates.
Public Channel
Preconf Market Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "preconfMarketUpdate",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"e": "preconfMarketUpdate",
"E": 1744684899022,
"s": "ETH-PC-603410",
"a": "NewEpoch",
"P": {
"m": 1000000603410,
"T": "inclusionPreconf",
"s": 603410,
"i": "ETH-PC-603410",
"n": "Eth Preconf Inclusion Slot #603410",
"M": 1744685494000,
"f": 1744686266000,
"b": 1744685498000,
"q": "1",
"mQ": "1",
"MQ": "36000000",
"PS": "0.00000000001",
"mP": "0.00000000001",
"MP": "0.00001",
"C": "3.99996",
"A": 36000000,
"r": 0,
"S": 0,
"e": 1,
"a": 1744685496000,
"c": 1744684899000,
"u": 1744684899000,
"tp": 36000000,
"mode": 0
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | channel name, e.g. preconfMarketUpdate` |
└ marketType
|
string | Market type, e.g., inclusionPreconf`. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g.preconfMarketUpdate
|
E |
integer | Event time in milliseconds. |
s |
string | Instrument ID of the market, e.g. ETH-PC-42093. |
a |
string | Action type, e.g. NewEpoch
|
P |
object | Payload data containing market details. |
└ m
|
integer | Market ID. |
└ T
|
string | Market type, e.g. inclusionPreconf
|
└ s
|
integer | Slot ID. |
└ i
|
string | Instrument ID. |
└ n
|
string | Market name, e.g. Eth Preconf Inclusion Slot #42093. |
└ M
|
integer | Market expiry time in milliseconds. |
└ a
|
integer | Bundle submission deadline in milliseconds. (Optional) |
└ f
|
integer | Block finality time in milliseconds. |
└ b
|
integer | Block time in milliseconds. |
└ mQ
|
string | Minimum order quantity allowed in the market. (Optional) |
└ MQ
|
string | Maximum order quantity allowed in the market. (Optional) |
└ q
|
string | Precision step of order quantity. (Optional) |
└ PS
|
string | Precision step of order price. |
└ mP
|
string | Minimum price allowed in the market. |
└ MP
|
string | Maximum price allowed in the market. |
└ p
|
string | Last traded price of the market |
└ PC
|
float | Price change percentage. |
└ d
|
boolean | Market direction. |
└ BB
|
string | Best bid price. |
└ BA
|
string | Best ask price. |
└ o
|
string | Mid price. |
└ C
|
string | Collateral per slot in ETH. |
└ A
|
integer | Available preconf for sale. |
└ r
|
integer | Block owner reserved preconf not for sale. |
└ S
|
integer | Block owner submitted preconf not for sale. |
└ e
|
integer | Market status. |
└ c
|
integer | Market Creation time in milliseconds. |
└ u
|
integer | Last market update time in milliseconds. |
└ O
|
boolean | OFAC filtering enabled flag. |
└ R
|
boolean | Realtime market flag. |
└ te
|
boolean | Trading enabled flag. |
└ mode
|
integer | Market trading mode. 0 = max-profit, 1 = light mode. |
└ MT
|
boolean | Multi-relay market flag. |
└ tp
|
integer | Total amount of preconf allowed to sell in the market |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
- Precision Values: Prices and quantities are represented with high precision for accurate calculations.
-
Market Status: The
efield is the market status code (see Market Status Codes). -
Optional Fields:
O,R,te,mode, andMTare included when the corresponding market configuration is available.
Candlestick Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "candlestickUpdate",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"e": "candlestickUpdate",
"E": 1736742241012,
"s": "ETH-PC-117",
"P": {
"I": "ETH-PC-117",
"m": 1000000000117,
"t": 1736742240000,
"i": 1000,
"o": "0",
"h": "0",
"l": "0",
"c": "0",
"v": "0",
"F": true
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., candlestickUpdate`. |
└ marketType
|
string | Market type, e.g., inclusionPreconf`. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g. candlestickUpdate. |
E |
integer | Event timestamp in milliseconds. |
s |
string | Instrument ID of the market, e.g., ETH-PC-117`. |
P |
object | Payload data containing market price history details. |
└ I
|
string | Instrument ID, e.g., ETH-PC-117`. |
└ m
|
integer | Market ID. |
└ t
|
integer | Timestamp of the price data in milliseconds. |
└ i
|
integer | Interval of the candlestick in milliseconds. |
└ o
|
string | Open price during the interval. |
└ h
|
string | High price during the interval. |
└ l
|
string | Low price during the interval. |
└ c
|
string | Close price during the interval. |
└ v
|
string | Volume during the interval. |
└ F
|
boolean | Indicates if the data is final (true) or incomplete (false). |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
- Precision Values: Prices and volumes are represented with high precision for accurate calculations.
-
Finalized Data: The
Ffield indicates whether the price history data is finalized or still being updated.
Recent Trades Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "recentTradeUpdate",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"e": "recentTradeUpdate",
"E": 1739528277074,
"s": "ETH-PC-173649",
"P": {
"i": "ETH-PC-173649",
"p": "0.00000000006",
"q": "1702005",
"s": true,
"d": 1739528277070,
"t": 683198
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., recentTradeUpdate
|
└ marketType
|
string | Market type, e.g., inclusionPreconf. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., recentTradeUpdate. |
E |
integer | Event timestamp in milliseconds. |
s |
string | Instrument ID. |
P |
object | Payload data containing recent trades details. |
└ i
|
string | Instrument ID . |
└ p
|
string | Traded price of the trade |
└ q
|
string | Traded quantity of the trade |
└ s
|
integer | Trading side of taker |
└ d
|
integer | Timestamp of the trade in milliseconds. |
└ t
|
integer | Trade index. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Trades Index: The
tfield shows current index of the trade. It is independent in each websocket connection.
Order Book Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "orderBookUpdate",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"e": "orderBookUpdate",
"E": 1736751224943,
"s": "ETH-PC-863",
"P": {
"a": [],
"b": [
{
"p": "0.00000000005",
"q": "5861476"
}
],
"I": "ETH-PC-863",
"t": 1736751224941
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., orderBookUpdate. |
└ marketType
|
string | Market type, e.g., inclusionPreconf. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., orderBookUpdate. |
E |
integer | Event timestamp in milliseconds. |
s |
string | Instrument ID of the market, e.g., ETH-PC-863. |
P |
object | Payload data containing order book details. |
└ a
|
array | List of ask orders (empty in the example). |
└ b
|
array | List of bid orders. |
└└ p
|
string | Price of the bid order. |
└└ q
|
string | Quantity of the bid order. |
└ I
|
string | Instrument ID, e.g., ETH-PC-863. |
└ t
|
integer | Timestamp of the order book update in milliseconds. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Order Details: The
afield contains ask orders, and thebfield contains bid orders, each with a price (p) and quantity (q). -
Instrument ID: The
Ifield represents the specific market instrument being updated.
Ticker Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "tickerUpdate",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"e": "tickerUpdate",
"E": 1743667424734,
"s": "ETH-PC-518598",
"P": {
"d": false,
"p": "0.00000000002",
"b": "0.00000000002",
"M": "0.00000000002",
"A": 18855242,
"g": 17144758,
"P": 1.0,
"u": 1743667299000
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., tickerUpdate. |
└ marketType
|
string | Market type, e.g., inclusionPreconf. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., tickerUpdate. |
E |
integer | Event timestamp in milliseconds. |
s |
string | Instrument ID of the market, e.g., ETH-PC-856. |
P |
object | Payload data containing market information. |
└ d
|
boolean | Market direction (true for buy, false for sell). |
└ p
|
string | Last traded price. |
└ b
|
string | Best bid price. |
└ a
|
string | Best ask price. |
└ M
|
string | Mid price in orderbook. |
└ A
|
string | Available preconf gas amount in the slot. |
└ g
|
string | Total gas purchased in the market. (optional) |
└ P
|
string | Percentage price change in the market. |
└ u
|
integer | Timestamp of the last update in milliseconds. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Price Details: Includes last trade price (
p), best bid (b), ask (a) prices, and mid (M) prices.
Inclusion Preconf Top Sales
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "inclusionPreconfSaleUpdate"
}
]
}
Example Response
{
"e": "inclusionPreconfSaleUpdate",
"E": 1739765044256,
"P": {
"s": 193373,
"g": "11288799",
"S": [
{
"p": "0.0000000001",
"q": "11078799"
}
]
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., inclusionPreconfSaleUpdate. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., inclusionPreconfSaleUpdate. |
E |
integer | Event timestamp in milliseconds. |
P |
object | Payload data containing block builder update details. |
└ s
|
integer | slot |
└ g
|
string | gas purchased |
└ S
|
array | array of top 10 preconf sales |
└└ p
|
string | purchased gas price |
└└ q
|
string | gas unit |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Slot ID: The
sfield represents the current slot being updated.
Block Builder Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "blockBuilderUpdate"
}
]
}
Example Response
{
"e": "blockBuilderUpdate",
"E": 1739527942002,
"a": "MarketExpiry",
"P": {
"s": 173614,
"p": [
"0x00000000000000000000000000000000caf14edec47d16536506af7a6d69eac6b1a66a042205f7ca768655a481038ae5"
],
"f": "0xa1885d66bef164889a2e35845c3b626545d7b0e513efe335e97c3a45e534013fa3bc38c3b7e6143695aecc4872ac52c4"
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., blockBuilderUpdate. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., blockBuilderUpdate
|
E |
integer | Event timestamp in milliseconds. |
a |
string | Action type, e.g. MarketExpiry
|
P |
object | Payload data containing block builder update details. |
└ s
|
integer | slot ID. |
└ p
|
array | Builder public keys of corresponding slot |
└ f
|
string | Fallback builder public key |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Slot ID: The
sfield represents the current slot being updated.
Private Channel
Account Order Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "accountOrderUpdate",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"e": "accountOrderUpdate",
"E": 1742288403296,
"s": "ETH-PC-403684",
"P": {
"o": 173639360,
"c": "613ec528",
"a": 2049,
"C": 53,
"t": 2,
"i": "ETH-PC-403684",
"m": 1000000403684,
"p": "0.00000000001",
"q": "3181683",
"F": "3181683",
"fp": "0.00003181683",
"f": "0.0000028635147",
"s": false,
"P": false,
"S": 10,
"d": 1742288403289,
"u": 1742288403289
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., accountOrderUpdate. |
└ marketType
|
string | Market type, e.g., inclusionPreconf. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., accountOrderUpdate
|
E |
integer | Event timestamp in milliseconds. |
P |
array | Array of order objects. |
└ o
|
integer | Order ID, e.g., 1234. |
└ c
|
string | Client Order ID, e.g., 43f4159e. |
└ a
|
integer | Account ID. |
└ C
|
integer | User ID who created this order. |
└ t
|
boolean | Order Type. |
└ i
|
string | Instrument ID. |
└ m
|
integer | Market Id. |
└ p
|
string | Order price. |
└ q
|
string | Order total quantity. |
└ F
|
string | Order filled quantity . |
└ fp
|
string | Order filled price * quantity. |
└ f
|
fee | Order fee. |
└ s
|
boolean | Order side. |
└ P
|
boolean | Flag for post-only order. |
└ S
|
integer | Order Status. |
└ d
|
integer | Timestamp of order creation time. |
└ u
|
integer | Timestamp of last update time. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
Account Transaction Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "accountTransactionUpdate",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"e": "accountTransactionUpdate",
"E": 1742288580882,
"s": "ETH-PC-403699",
"P": {
"t": 146600149,
"i": "ETH-PC-403699",
"o": 173651088,
"a": 2049,
"s": true,
"p": "0.00000000001",
"q": "1248972",
"f": "0.0000011240748",
"d": 1742288580863
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., accountTransactionUpdate. |
└ marketType
|
string | Market type, e.g., inclusionPreconf. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., accountTransactionUpdate
|
E |
integer | Event timestamp in milliseconds. |
P |
object | Payload data containing block builder update details. |
s |
string | Instrument ID, e.g., ETH-PC-403699. |
└ t
|
integer | Transaction ID, e.g., 123456. |
└ i
|
string | Instrument ID, e.g., ETH-PC-403699. |
└ o
|
integer | Order ID of the trade executed, e.g., 123456. |
└ a
|
integer | Account ID of the trade executed, e.g., 123. |
└ s
|
boolean | Traded Side, e.g., true. |
└ p
|
string | Traded price, e.g., 0.00000000001. |
└ q
|
string | Traded quantity, e.g., 1248972. |
└ f
|
string | Trading fee, e.g., 0.0000011240748. |
└ d
|
timestamp | Timestamp of the trade execution, e.g., 1742288580863. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
Account Position Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "accountPositionUpdate",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"e": "accountPositionUpdate",
"E": 1742288402217,
"P": {
"a": 2049,
"s": 403684,
"m": 1,
"q": "20427356",
"l": "0",
"p": "0",
"e": false,
"b": false,
"c": 1742288355000,
"u": 1742288402000,
"A": "20427356"
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., accountPositionUpdate. |
└ marketType
|
string | Market type, e.g., inclusionPreconf. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., accountPositionUpdate
|
E |
integer | Event timestamp in milliseconds. |
P |
object | Payload data containing account position update details. |
└ a
|
integer | Account Id. |
└ s
|
integer | Slot number of the position. |
└ m
|
integer | Market type of the position. |
└ q
|
string | Position's total quantity. |
└ l
|
string | Position's locked quantity |
└ p
|
string | Position purchased price. |
└ e
|
boolean | Expired flag. |
└ b
|
boolean | Builder fill enable flag. |
└ c
|
integer | Position create timestamp. |
└ u
|
integer | Position last updated timestamp. |
└ A
|
integer | Position's available quantity. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
Preconf Bundle Update
Example Request
{
"op": "subscribe",
"args": [
{
"channel": "preconfBundleUpdate"
}
]
}
Example Response
{
"e": "preconfBundleUpdate",
"E": 1743674748083,
"P": {
"s": 519181,
"e": 1260000,
"bu": [
{
"u": "456a8e9d-ce47-421d-8135-9ed9680ab57e",
"B": 1,
"o": 1,
"txs": [
{
"r": false,
"tx": "0x02f88b827e7e8302bcff8084773594008303345094f37512b7c630890c500b02724671cf3ae5607563843b9aca009b45746847617320496e636c7573696f6e20507265636f6e66732e20c001a007797cf3e30a7d45ef43ab9b76d309b76db5f3704cb4936890245b374bad5925a00ad6fa6556dd1448beaf39fc6c5faa097eaf615144905f7d60fb72b15ded30e4",
"h": "0x653304b826eca4f48510d29e8ac2a9fcad6ecf3ef3bc3ca3a837718f3d6fa368"
},
{
"r": false,
"tx": "0x02f88b827e7e8302bd008084773594008303345094f37512b7c630890c500b02724671cf3ae5607563843b9aca009b45746847617320496e636c7573696f6e20507265636f6e66732e20c080a03b1a7ca0651410d37aedef11740e4e902a9bcb106bcb3bb1f98f18d9ed2bda25a02fabfa492e172ac244cb809d0d035c75ed4b04e5f7e92258781e7cd55daabef9",
"h": "0x3076010ac7607ae41a9dacb14b55bba5a91ca4aad1189ed90e5adac638f7d43c"
}
],
"p": "0.00000000597"
}
],
"r": "0x8f02425b5f3c522b7ef8ea124162645f0397c478"
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. subscribe
|
args |
object | Arguments |
└ channel
|
string | Channel name, e.g., preconfBundleUpdate. |
Response Body
| Name | Type | Description |
|---|---|---|
e |
string | Event type, e.g., preconfBundleUpdate
|
E |
integer | Event timestamp in milliseconds. |
P |
object | Payload data containing block builder update details. |
└ s
|
integer | slot ID. |
└ e
|
integer | Empty block space in the slot (For block owner only.) |
└ bu
|
array | Array of preconf bundles in the slot. |
└└ u
|
string | UUID of the bundle. |
└└ p
|
string | Gas price of the bundle. |
└└ txs
|
array | Array of transaction in the bundle |
└└└ r
|
boolean | Whether this ethereum tranasaction can be reverted. |
└└└ tx
|
string | Raw ethereum transaction data in the bundle |
└└└ h
|
string | Transaction hash of transaction data |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Slot ID: The
sfield represents the current slot being updated.
Query
In a websocket session, you can query public or private data using the query command.
Public Query
Preconf Markets Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "preconfMarkets",
"marketType": "inclusionPreconf"
}
]
}
Example Response
{
"q": "preconfMarkets",
"s": "ETH-PC-603391",
"P": {
"m": 1000000603391,
"T": "inclusionPreconf",
"s": 603391,
"i": "ETH-PC-603391",
"n": "Eth Preconf Inclusion Slot #603391",
"M": 1744685266000,
"f": 1744686038000,
"b": 1744685270000,
"q": "1",
"mQ": "1",
"MQ": "36000000",
"PS": "0.00000000001",
"mP": "0.00000000001",
"MP": "0.00001",
"d": false,
"BB": "0.00000000001",
"o": "0.00000000001",
"C": "3.99996",
"A": 36000000,
"r": 0,
"S": 0,
"e": 1,
"a": 1744685268000,
"c": 1744684515000,
"u": 1744684845000,
"tp": 36000000
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., preconfMarkets. |
└ marketType
|
string | Market type, e.g., inclusionPreconf. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., preconfMarkets. |
s |
string | Instrument ID of the market, e.g., ETH-PC-1151. |
P |
object | Payload data containing market information. |
└ m
|
integer | Market ID. |
└ T
|
string | Market type, e.g. inclusionPreconf
|
└ s
|
integer | Slot ID. |
└ i
|
string | Instrument ID. |
└ n
|
string | Market name, e.g. Eth Preconf Inclusion Slot #42093. |
└ M
|
integer | Market expiry time in milliseconds. |
└ a
|
integer | Bundle submission deadline in milliseconds. (Optional) |
└ f
|
integer | Block finality time in milliseconds. |
└ b
|
integer | Block time in milliseconds. |
└ mQ
|
string | Minimum order quantity allowed in the market. (Optional) |
└ MQ
|
string | Maximum order quantity allowed in the market. (Optional) |
└ q
|
string | Precision step of order quantity. (Optional) |
└ PS
|
string | Precision step of order price. |
└ mP
|
string | Minimum price allowed in the market. |
└ MP
|
string | Maximum price allowed in the market. |
└ p
|
string | Last traded price of the market |
└ PC
|
float | Price change percentage. |
└ d
|
boolean | Market direction. |
└ BB
|
string | Best bid price. |
└ BA
|
string | Best ask price. |
└ o
|
string | Mid price. |
└ C
|
string | Collateral per slot in ETH. |
└ A
|
integer | Available preconf for sale. |
└ r
|
integer | Block owner reserved preconf not for sale. |
└ S
|
integer | Block owner submitted preconf not for sale. |
└ e
|
integer | Market status. |
└ c
|
integer | Market Creation time in milliseconds. |
└ u
|
integer | Last market update time in milliseconds. |
└ tp
|
integer | Total amount of preconf allowed to sell in the market |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
- Precision Values: Prices and quantities are represented with high precision for accurate calculations.
-
Market Status: The
efield is the market status code (see Market Status Codes).
Order Books Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "orderBook",
"marketType": "wholeBlock"
}
]
}
Example Response
{
"q": "orderBook",
"s": "ETH-WB-1535",
"P": {
"a": [],
"b": [
{
"q": "1",
"p": "0.00000000567"
},
{
"q": "2",
"p": "0.00000000566"
}
],
"t": 1736759161542,
"I": "ETH-WB-1535"
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., orderBook. |
└ marketType
|
string | Market type, e.g., wholeBlock. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., orderBook. |
s |
string | Instrument ID of the market, e.g., ETH-WB-1535. |
P |
object | Payload data containing order book information. |
└ a
|
array | List of ask orders (empty in the example). |
└ b
|
array | List of bid orders. |
└└ q
|
string | Quantity of the bid order. |
└└ p
|
string | Price of the bid order. |
└ t
|
integer | Timestamp of the order book query in milliseconds. |
└ I
|
string | Instrument ID, e.g., ETH-WB-1535. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Order Details: The
afield contains ask orders, and thebfield contains bid orders, each with a price (p) and quantity (q). -
Instrument ID: The
Ifield represents the specific market instrument being queried.
Current Slot Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "currentSlot"
}
]
}
Example Response
{
"q": "currentSlot",
"P": {
"t": 1736759362264,
"s": 1497,
"r": 1736
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., currentSlot. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., currentSlot. |
P |
object | Payload data containing slot information. |
└ t
|
integer | Timestamp of the current slot in milliseconds. |
└ s
|
integer | Current slot ID. |
└ r
|
integer | Remaining time to next slot in milliseconds. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
- Slot ID: Slot can only be queried for the incoming 2 epochs (max 64 slots).
-
Remaining Time: The
rfield shows the remaining time until the next slot in milliseconds.
Candlesticks Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "candlesticks",
"interval": 1000,
"instrumentId": "ETH-PC-1567"
}
]
}
Example Response
{
"q": "candlesticks",
"s": "ETH-PC-1567",
"P": [
{
"I": "ETH-PC-1567",
"m": 1000000001567,
"t": 1736759832000,
"i": 1000,
"o": "0.00000000009",
"h": "0.00000000009",
"l": "0.00000000009",
"c": "0.00000000009",
"v": "0",
"F": false
},
{
"I": "ETH-PC-1567",
"m": 1000000001567,
"t": 1736759831000,
"i": 1000,
"o": "0.00000000009",
"h": "0.00000000009",
"l": "0.00000000009",
"c": "0.00000000009",
"v": "0",
"F": true
},
{
"I": "ETH-PC-1567",
"m": 1000000001567,
"t": 1736759830000,
"i": 1000,
"o": "0.00000000008",
"h": "0.00000000009",
"l": "0.00000000008",
"c": "0.00000000009",
"v": "2912472",
"F": true
}
]
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., candlesticks. |
└ interval
|
integer | Interval for price history in milliseconds, e.g., 1000. |
└ instrumentId
|
string | Instrument ID to query price history, e.g., ETH-PC-1567. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., candlesticks. |
s |
string | Instrument ID of the queried market, e.g., ETH-PC-1567. |
P |
array | Array of market price history objects. |
└ I
|
string | Instrument ID, e.g., ETH-PC-1567. |
└ m
|
integer | Market ID. |
└ t
|
integer | Timestamp of the price data in milliseconds. |
└ i
|
integer | Interval of the data. |
└ o
|
string | Open price during the interval. |
└ h
|
string | High price during the interval. |
└ l
|
string | Low price during the interval. |
└ c
|
string | Close price during the interval. |
└ v
|
string | Volume during the interval. |
└ F
|
boolean | Indicates if the data is final (true) or incomplete (false). |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Price Details: Includes open (
o), high (h), low (l), and close (c) prices along with volume (v). -
Finalized Data: The
Ffield indicates whether the price history data is finalized or still being updated.
Recent Trades Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "recentTrades",
"instrumentId": "ETH-PC-1567",
"limit": 10
}
]
}
Example Response
{
"q": "recentTrades",
"s": "ETH-PC-1567",
"P": [
{
"i": "ETH-PC-1567",
"p": "0.00000000021",
"q": "1534591",
"s": true,
"d": 1736760078290,
"t": 89130
},
{
"i": "ETH-PC-1567",
"p": "0.00000000021",
"q": "270409",
"s": false,
"d": 1736760078369,
"t": 89216
}
],
"l": 10
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., recentTrades. |
└ instrumentId
|
string | Instrument ID, e.g., ETH-PC-1567. |
└ limit
|
integer | (Optional) Maximum number of trades to return (default is 100). |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., recentTrades. |
s |
string | Instrument ID of the queried market, e.g., ETH-PC-1567. |
l |
integer | The limit applied to the query. |
P |
array | Array of recent trade objects. |
└ i
|
string | Instrument ID, e.g., ETH-PC-1567. |
└ p
|
string | Price at which the trade occurred. |
└ q
|
string | Traded quantity . |
└ s
|
boolean | Trade side (true for buy, false for sell). |
└ d
|
integer | Timestamp of the trade in milliseconds. |
└ t
|
integer | Trade ID. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Trade Details: Each trade object includes price (
p), quantity (q), and trade side (s). -
Limit Parameter: The
limitfield in the request allows you to restrict the number of returned trades, with a default of100.
Inclusion Preconf Top Sales Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "inclusionPreconfTopSales",
"slot": 403973
}
]
}
Example Response
{
"q": "inclusionPreconfTopSales",
"P": {
"s": 403973,
"g": 18662236,
"S": [
{
"p": "0.00000000009",
"q": "12662236"
}
]
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., inclusionPreconfTopSales. |
└ slot
|
integer | (Optional) Slot to query. Uses next slot if omitted. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., inclusionPreconfTopSales. |
P |
object | Payload data containing inclusion preconf top sales information. |
└ s
|
integer | Slot ID. |
└ g
|
integer | Total gas purchased in this slot. |
└ S
|
array | Array of top gas sales. |
└└ p
|
string | Purchased price in average |
└└ q
|
string | Purchased gas quantity |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Slot: If
slotis omitted, the server uses the next slot.
Current Block Builder Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "currentBlockBuilder",
"slot": 123456
}
]
}
If you want the next slot's builder, omit the slot field:
{
"op": "query",
"args": [
{
"queryType": "currentBlockBuilder"
}
]
}
Example Response
{
"q": "currentBlockBuilder",
"P": {
"s": 402361,
"p": [
"0xA25ADDC4FC16F72CA667177D7A5533D4287B3574F0127FFC227095E90B0B1FD0DD48C421E04E613D2298FE4DAC83A2A5"
],
"f": "0xa1885d66bef164889a2e35845c3b626545d7b0e513efe335e97c3a45e534013fa3bc38c3b7e6143695aecc4872ac52c4"
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., currentBlockBuilder. |
└ slot
|
integer | Slot, e.g., 123456. Optional. Use next slot if not specified. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., currentBlockBuilder. |
P |
object | Payload data containing block builder information. |
└ s
|
integer | slot. |
└ p
|
array | Block builder public keys. Optional if market owner does not delegate a builder |
└ f
|
string | Fallback builder public key. |
Notes
- Slot ID: Slot can only be queried for the incoming 2 epochs (max 64 slots).
Private Query
Open Orders Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "openOrders",
"accountId": 1234,
"instrumentId": "ETH-PC-123456",
"startId": 0,
"limit": 100
}
]
}
Example Response
{
"q": "openOrders",
"s": "ETH-PC-194361",
"P": [
{
"o": 61702036,
"c": "43f4159e",
"a": 2049,
"C": 53,
"t": 2,
"i": "ETH-PC-194361",
"m": 1000000194361,
"p": "0.00000000001",
"q": "1907125",
"F": "1907125",
"fp": "0.00001907125",
"f": "0.0000017164125",
"s": false,
"P": false,
"S": 10,
"d": 1739776227777,
"u": 1739776227777
},
{
"o": 61702196,
"c": "454057b4",
"a": 2049,
"C": 53,
"t": 2,
"i": "ETH-PC-194361",
"m": 1000000194361,
"p": "0.00000000001",
"q": "1864896",
"F": "1864896",
"fp": "0.00001864896",
"f": "0.0000016784064",
"s": false,
"P": false,
"S": 10,
"d": 1739776229952,
"u": 1739776229952
}
],
"a": 2049
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., openOrders. |
└ accountId
|
integer | Account ID. Required unless using the authenticated account. |
└ instrumentId
|
string | Instrument ID, e.g., ETH-PC-1567. |
└ startId
|
integer | (Optional) starting order ID in the query. |
└ limit
|
integer | (Optional) Maximum number of orders to return. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., openOrders. |
s |
string | Instrument ID of the queried market, e.g., ETH-PC-1567. |
a |
integer | Account ID, e.g., 1234. |
P |
array | Array of order objects. |
└ o
|
integer | Order ID, e.g., 1234. |
└ c
|
string | Client Order ID, e.g., 43f4159e. |
└ a
|
integer | Account ID. |
└ C
|
integer | User ID who created this order. |
└ t
|
integer | Order Type. |
└ i
|
string | Instrument ID. |
└ m
|
integer | Market Id. |
└ p
|
string | Order price. |
└ q
|
string | Order total quantity. |
└ F
|
string | Order filled quantity . |
└ fp
|
string | Order filled price * quantity. |
└ f
|
fee | Order fee. |
└ s
|
boolean | Order side. |
└ P
|
boolean | Flag for post-only order. |
└ S
|
integer | Order Status. |
└ d
|
integer | Timestamp of order creation time. |
└ u
|
integer | Timestamp of last update time. |
Notes
- Timestamp Fields: All timestamps are in milliseconds since the Unix epoch.
-
Order Details: Each order object includes price (
p), quantity (q), side (s), and status (S). -
Limit Parameter: The
limitfield in the request allows you to restrict the number of returned orders.
Account Positions Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "accountPositions",
"marketType": "inclusionPreconf",
"accountId": 1234
}
]
}
Example Response
{
"q": "accountPositions",
"a": 2049,
"P": [
{
"a": 2049,
"s": 403776,
"m": 1,
"q": "0",
"l": "0",
"p": "0",
"e": false,
"b": false,
"c": 1742289507000,
"u": 1742289508000,
"A": "0"
},
{
"a": 2049,
"s": 403780,
"m": 1,
"q": "0",
"l": "0",
"p": "0",
"e": false,
"b": false,
"c": 1742289507000,
"u": 1742289508000,
"A": "0"
}
]
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., accountPositions. |
└ marketType
|
string | Market type, e.g., inclusionPreconf. |
└ accountId
|
integer | Account ID, e.g., 1234. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., accountPositions. |
a |
integer | Account ID of the queried positions. |
P |
array | Payload data containing position information. |
└ a
|
integer | Account Id. |
└ s
|
integer | Slot number of the position. |
└ m
|
integer | Market type of the position. |
└ q
|
string | Position's total quantity. |
└ l
|
string | Position's locked quantity |
└ p
|
string | Position purchased price. |
└ e
|
boolean | Expired flag. |
└ b
|
boolean | Builder fill enable flag. |
└ c
|
integer | Position create timestamp. |
└ u
|
integer | Position last updated timestamp. |
└ A
|
integer | Position's available quantity. |
Preconf Bundles Query
Example Request
{
"op": "query",
"args": [
{
"queryType": "preconfBundles",
"slot": 123456
}
]
}
Example Response
{
"q": "preconfBundles",
"P": {
"s": 194265,
"bu": [
{
"u": "c439371a-7095-4de6-82ce-6bf4fc6fd693",
"txs": [
{
"r": false,
"tx": "0x02f88a827e7e82088b808477359400830334509412643b525cc34282ba84298d32bf2d094448f1c4843b9aca009b45746847617320496e636c7573696f6e20507265636f6e66732e20c080a03b39cc9c4a92f32f8d4bc88546e2655378d4e87468ba74b0d20164ed9c346838a01bdbe85274f17b2c87e4689996089affd2d7d8c542616ef7020f5975bf4ddb52",
"h": "0xeb1bca2f601eb124563286455544cc87a1b04b28bd5bed6fb28be81417c4a0de"
}
],
"p": "0.00000000013"
}
]
}
}
Request
| Name | Type | Description |
|---|---|---|
op |
string | e.g. query
|
args |
object | Arguments |
└ queryType
|
string | Query type, e.g., preconfBundles. |
└ slot
|
integer | Slot, e.g., 1234. Optional. Use next slot if not specified. |
Response Body
| Name | Type | Description |
|---|---|---|
q |
string | Query type, e.g., preconfBundles. |
P |
array | Payload data containing block builder information. |
└ s
|
integer | Slot ID. |
└ bu
|
array | Array of preconf bundles in the slot. |
└└ u
|
string | UUID of the bundle. |
└└ p
|
string | Gas price of the bundle. |
└└ txs
|
array | Array of transaction in the bundle |
└└└ r
|
boolean | Whether this ethereum tranasaction can be reverted. |
└└└ tx
|
string | Raw ethereum transaction data in the bundle |
└└└ h
|
string | Transaction hash of transaction data |
LOOKUP TABLES
Error Codes
A failed request includes the fields below. See HTTP status when the body is not JSON.
-
success: boolean -
errorCode: integer, present whensuccessis false -
errorMsgKey: message key, present whensuccessis false -
data: object, empty or omitted
Common errors (errorCode 0-7)
| errorCode | errorMsgKey | Meaning |
|---|---|---|
| 0 | success | Success |
| 1 | error.permissionDeny | Permission denied |
| 2 | error.account.notExist | Account does not exist |
| 3 | error.market.notExist | Market does not exist |
| 4 | error.market.expired | Market expired |
| 5 | error.account.inactive | Account inactive |
| 6 | error.market.tradingDisabled | Market trading disabled |
| 7 | error.user.locked | User account is locked |
System errors (errorCode 20-26)
| errorCode | errorMsgKey | Meaning |
|---|---|---|
| 20 | error.system.busy | System busy |
| 21 | error.system.internal | Internal/unknown error |
| 22 | error.system.timeout | Timeout |
| 23 | error.system.validation | Validation error |
| 24 | error.httpMethod.unsupported | Unsupported HTTP method |
| 25 | error.contentType.unsupported | Unsupported content type |
| 26 | error.system.unavailable | Service unavailable |
Trading errors
Create order (errorCode 50-74)
| errorCode | errorMsgKey |
|---|---|
| 50 | error.price.required |
| 51 | error.price.min |
| 52 | error.price.max |
| 53 | error.price.step |
| 54 | error.quantity.required |
| 55 | error.quantity.min |
| 56 | error.quantity.max |
| 57 | error.quantity.step |
| 58 | error.clientOrderId.duplicate |
| 59 | error.orderLimit |
| 60 | error.insufficientFund |
| 61 | error.position.insufficient |
| 62 | error.collateral.insufficient |
| 63 | error.liquidity.insufficient |
| 64 | error.clientOrderId.required |
| 65 | error.clientOrderId.format |
| 66 | error.accountId.required |
| 67 | error.orderType.invalid |
| 68 | error.orderType.fok.passive |
| 69 | error.quantity.nonPositive |
| 70 | error.market.required |
| 71 | error.price.nonPositive |
| 72 | error.side.required |
| 73 | error.accountId.notPreconfAccount |
| 74 | error.market.botTradingOnly |
Cancel order (errorCode 90-96)
| errorCode | errorMsgKey |
|---|---|
| 90 | error.order.notExist |
| 91 | error.accountId.required |
| 92 | error.instrumentId.required |
| 93 | error.orderId.required |
| 94 | error.orderId.notBoth |
| 95 | error.clientOrderId.invalid |
| 96 | error.batchSize.max |
Bundle submission (errorCode 190-194)
These message keys use the spelling bundleSumission. Match that string in your client.
| errorCode | errorMsgKey |
|---|---|
| 190 | error.bundleSumission.market.expired |
| 191 | error.bundleSumission.preconf.insufficient |
| 192 | error.bundleSumission.preconf.max |
| 193 | error.bundleSumission.bundle.empty |
| 194 | error.bundleSumission.bundle.invalid |
Account transfer (errorCode 250-253)
| errorCode | errorMsgKey |
|---|---|
| 250 | error.insufficientFund |
| 251 | error.token.unsupported |
| 252 | error.fromAccountId.equals.toAccountId |
| 253 | error.invalid.accountId |
Owner update market (errorCode 430)
| errorCode | errorMsgKey |
|---|---|
| 430 | error.reservedPreconf.position.insufficient |
Withdraw (errorCode 310-317)
| errorCode | errorMsgKey |
|---|---|
| 310 | error.quantity.min |
| 311 | error.chain.unsupported |
| 312 | error.token.unsupported |
| 313 | error.insufficientFund |
| 314 | error.token.daily.withdraw.capacity.exceeded |
| 315 | error.withdraw.requests.empty |
| 316 | error.withdraw.requestIds.empty |
| 317 | error.withdraw.fee.update.quantity.invalid |
API-level errors (errorCode >= 100000)
| errorCode | errorMsgKey |
|---|---|
| 100000 | error.pendingOrDone |
| 100001 | error.quantity.nonPositive |
| 100002 | error.publicKey.invalid |
| 100003 | error.signature.invalid |
| 100004 | error.collateralPerSlot.negative |
| 100005 | error.builder.notExists |
| 100006 | error.validators.max |
| 100007 | error.collateralPerSlot.max |
| 100008 | error.builders.max |
| 100009 | error.slot.invalid |
| 100010 | error.login.signature.invalid |
| 100011 | error.login.address.invalid |
| 100012 | error.login.error.nonce.used |
| 100013 | error.login.error.nonce.notExists |
| 100014 | error.login.user.notExists |
| 100015 | error.login.user.exists |
| 100016 | error.login.refreshToken.required |
| 100017 | error.login.refreshToken.conflict |
| 100018 | error.login.refreshToken.invalid |
| 100019 | error.login.session.notFound |
| 100020 | error.validator.signature.invalid |
| 100021 | error.validator.registered |
| 100022 | error.validator.signature.sizeNotMatch |
| 100023 | error.validator.signature.max |
| 100024 | error.builder.signature.sizeNotMatch |
| 100025 | error.builder.signature.max |
| 100026 | error.account.id.invalid |
| 100027 | error.bundle.rejection.empty |
| 100030 | error.ssv.validators.required |
| 100032 | error.ssv.validators.invalid |
| 100040 | error.ssv.operator.signature.invalid |
| 100041 | error.ssv.operator.registered |
| 100042 | error.ssv.operator.address.invalid |
| 100043 | error.ssv.operator.notRegistered |
| 100044 | error.ssv.operator.verification.tx.invalid |
| 100045 | error.ssv.operator.verification.tx.notFound |
| 100050 | error.obol.validators.required |
| 100052 | error.obol.validators.invalid |
| 100060 | error.obol.operator.signature.invalid |
| 100061 | error.obol.operator.registered |
| 100062 | error.obol.operator.address.invalid |
| 100063 | error.obol.operator.notRegistered |
| 100064 | error.obol.operator.invalid |
| 100070 | error.address.invalid |
| 100071 | error.timeRange.invalid |
| 100072 | error.comment.invalid |
| 100073 | error.validator.mode.invalid |
Additional request validation codes
| errorCode | errorMsgKey | Meaning |
|---|---|---|
| 318 | error.withdraw.request.invalid | Missing or null withdrawal item/required field. |
| 100080 | error.builder.delegation.target.required | Missing delegation target. |
| 100081 | error.builder.delegation.target.conflict | Conflicting delegation targets. |
| 100082 | error.builder.delegation.entityId.invalid | Invalid builder entity identifier. |
Markets
Market Status Codes
| Status Code | Status | Description |
|---|---|---|
| 0 | NOT_STARTED | Pending to be started |
| 1 | ENABLE | Market enabled |
| 2 | EXPIRED | Market expired |
| 3 | TRX_SUBMISSION_ENDED | Transaction submission time ended |
| 4 | FINALIZED | Market finalized |
Orders
Order Sides
| Boolean | Side |
|---|---|
| 0 (False) | Sell |
| 1 (True) | Buy |
Order Status Codes
| Status Code | Status | Description |
|---|---|---|
| 0 | STATUS_PENDING | Pending (i.e. Not yet sent to market) |
| 1 | STATUS_ONBOOK | On Book (i.e. Live order in market) |
| 10 | STATUS_DONE | Done (i.e. Fully executed) |
| 11 | STATUS_MANUALLY_CANCELLED | Manually cancelled |
| 12 | STATUS_AUTO_CANCELLED | Auto cancelled |
| 13 | STATUS_PARTIALLY_FILLED | Partially Filled |
| 14 | STATUS_EXPIRED | Market expired |
| 99 | STATUS_ERROR | Error |
Order Types
| Type Code | Meaning |
|---|---|
| 1 | Market Order |
| 2 | Limit Order |
| 3 | Fill-Or-Kill Order |
Response Codes
See HTTP status. Check success as well as the HTTP status. Batch endpoints also return a code for each item.
Token IDs
These are the tokens currently supported on Ethgas.
| Code | Name | Token ID | Quantity Step | Minimum Quantity |
|---|---|---|---|---|
| ETH | ETH | 1 | 0.00001 | 0.001 |
Transaction Types
| Code | Meaning |
|---|---|
| 1 | Buy |
| 2 | Sell |
| 3 | Borrow |
| 4 | Lend |
| 5 | Interest |
| 6 | Transfer In (Between accounts) |
| 7 | Transfer Out (Between accounts) |
| 8 | External Transfer In (Deposit) |
| 9 | External Transfer Out (Withdrawal) |
| 10 | Trade |
| 14 | Withdrawal Fee |
| 15 | Transaction Fee |
Market Types
| Code | Market |
|---|---|
| 1 | Inclusion Preconf Market |
| 2 | Whole Block Market |
Action Types
Action Type returned in some websocket messages.
| Type |
|---|
| NewEpoch |
| MarketExpiry |
| Snapshot |
| BlockBuilderChanged |
| BundleSubmissionDeadline |
Builder
Builder Registration Result
| Code | Reason |
|---|---|
| 0 | OK |
| 1 | NOT_FOUND |
| 2 | SIGNATURE_INVALID |
| 3 | ALREADY_REGISTERED |