Account API reference

The OpenScan.AI Account API serves per-user explorer features: API keys, address watchlists with notifications, private tags, and custom ABIs. Every endpoint takes JSON in, returns JSON out, and authenticates with an Authorization: Bearer header. Pick a language on the right — every sample on this page updates to match.

Base URL
https://xdcscan.io/account/api/v1
Version
v1
Auth
Authorization: Bearer

Authentication

Every request must include the Authorization: Bearer YOUR_API_KEY header. Create and manage keys in your xdcscan.io account under Account → API Keys.

Authentication errors return 401 Unauthorized with { "message": "Invalid API key" }.

GET /account/api/v1/user/info HTTP/1.1
Host: xdcscan.io
Authorization: Bearer YOUR_API_KEY

# 401 response when the key is missing or invalid:
{ "message": "Invalid API key" }
GET /account/api/v1/user/info HTTP/1.1
Host: xdcscan.io
Authorization: Bearer YOUR_API_KEY

# 401 response when the key is missing or invalid:
{ "message": "Invalid API key" }

Response envelope

Every JSON response is wrapped in a top-level data field. For list endpoints, data carries both the array and a pagination object.

# Single resource:
{ "data": { "...": "..." } }

# List resource:
{ "data": { "items": [ ... ], "pagination": { ... } } }
# Single resource:
{ "data": { "...": "..." } }

# List resource:
{ "data": { "items": [ ... ], "pagination": { ... } } }

Errors

The API uses standard HTTP status codes. All error responses share the same JSON shape.

HTTPCode stringDescription
400BadRequestThe request body or query parameters are invalid. Check message for details.
401UnauthorizedThe API key is missing, expired, or invalid.
404NotFoundThe resource does not exist or is not owned by the authenticated account.
429TooManyRequestsRequest rate exceeded. Wait before retrying.
500InternalServerErrorUnexpected server error. Retry with exponential backoff.
# Error response schema:
{ "message": "string" }
# Error response schema:
{ "message": "string" }

API Versioning

Account API endpoints are prefixed with a version number (/account/api/v1/). The public REST API at /api/v2 is versioned independently — an upgrade to one does not affect the other.

VersionStatusEndpoints
v1StableAPI keys, user info, watchlists, tags, custom ABIs

Future breaking changes are introduced as a new version prefix; prior versions remain available for a deprecation period announced on the OpenScanAI GitHub organization.

Pagination

List endpoints such as GET /user/watchlist use offset-based pagination via skip and limit. The response includes a pagination object with total, skip, limit, and hasMore so you can drive a paging loop without guessing when to stop.

ParameterTypeDefaultMinimumDescription
skipinteger00Number of records to skip (offset)
limitinteger1001Maximum records to return per page
# Stream every page sequentially:
SKIP=0
LIMIT=100
while :; do
  curl -s "https://xdcscan.io/account/api/v1/user/watchlist?skip=$SKIP&limit=$LIMIT" \
    -H "Authorization: Bearer $OPENSCAN_API_KEY" > page.json
  jq -e '.data.pagination.hasMore' page.json > /dev/null || break
  SKIP=$((SKIP + LIMIT))
done
# Stream every page sequentially:
SKIP=0
LIMIT=100
while :; do
  curl -s "https://xdcscan.io/account/api/v1/user/watchlist?skip=$SKIP&limit=$LIMIT" \
    -H "Authorization: Bearer $OPENSCAN_API_KEY" > page.json
  jq -e '.data.pagination.hasMore' page.json > /dev/null || break
  SKIP=$((SKIP + LIMIT))
done

GET /user/info

Retrieve the authenticated account's profile. The fastest way to verify a key works.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY

Response 200 OK

Field Description
data.name string
Display name
data.email string
Account email address
data.nickname string
Public nickname shown in the explorer
data.registered_at string
ISO-8601 registration time
curl https://xdcscan.io/account/api/v1/user/info \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"
curl https://xdcscan.io/account/api/v1/user/info \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"

GET /user/api-keys

List API keys for the authenticated account. Key secrets are never returned after creation.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY

Response 200 OK

Field Description
data[].id string (uuid)
API key ID — used to revoke the key
data[].name string
Label given at creation
data[].created_at string
ISO-8601 creation time
data[].last_used_at string
ISO-8601 time of last authenticated request, or null
curl https://xdcscan.io/account/api/v1/user/api-keys \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"
curl https://xdcscan.io/account/api/v1/user/api-keys \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"

POST /user/api-keys

Create a new API key. The secret is returned exactly once — store it securely.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY (or a session token)
name body string required
Label for the key, e.g. the service that will use it

Response 201 Created

Field Description
data.id string (uuid)
API key ID
data.name string
Label given at creation
data.api_key string
The key secret — shown only in this response
The same key works on the public REST API v2 and raises your rate limit there. See API Keys & Rate Limits.
Create one key per service so usage attribution and revocation stay simple.
curl -X POST https://xdcscan.io/account/api/v1/user/api-keys \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "production-backend" }'
curl -X POST https://xdcscan.io/account/api/v1/user/api-keys \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "production-backend" }'

DELETE /user/api-keys/{id}

Revoke an API key immediately. Requests authenticated with it start returning 401 at once.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY
id path string (uuid) required
API key ID to revoke

Response 200 OK

curl -X DELETE "https://xdcscan.io/account/api/v1/user/api-keys/9f2b1c4e-7a3d-4c21-9e8f-1a2b3c4d5e6f" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"
curl -X DELETE "https://xdcscan.io/account/api/v1/user/api-keys/9f2b1c4e-7a3d-4c21-9e8f-1a2b3c4d5e6f" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"

GET /user/watchlist

List watched addresses for the authenticated account, with pagination.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY
skip query integer
Offset. Default 0
limit query integer
Max records. Default 100

Response 200 OK

Field Description
data.items[] array
One entry per watched address
data.items[].id string
Watchlist entry ID — used to update or remove the entry
data.items[].address_hash string
Watched address
data.items[].name string
Label shown in notifications
data.items[].notification_settings object
Per-transfer-type incoming/outgoing toggles
data.pagination.total number
Total watched addresses for the account
data.pagination.hasMore boolean
True when more pages are available
curl "https://xdcscan.io/account/api/v1/user/watchlist?skip=0&limit=100" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"
curl "https://xdcscan.io/account/api/v1/user/watchlist?skip=0&limit=100" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"

POST /user/watchlist

Add an address to the watchlist and choose which events trigger notifications.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY
address_hash body string required
Address to watch (0x-prefixed)
name body string required
Label shown in notifications and the UI
notification_settings body object
Per-type toggles: native, ERC-20, ERC-721, ERC-1155, each with incoming/outgoing booleans
notification_methods body object
Delivery channels: email and/or webhook

Response 201 Created

Field Description
data.id string
Watchlist entry ID
data.address_hash string
Watched address
Watching the same address twice updates the existing entry instead of creating a duplicate.
Webhook URLs are configured account-wide under Account → Notifications — see the watchlist notifications section below.
curl -X POST https://xdcscan.io/account/api/v1/user/watchlist \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address_hash": "0x1234567890abcdef1234567890abcdef12345678",
    "name": "Treasury wallet",
    "notification_settings": {
      "native": { "incoming": true, "outgoing": true },
      "ERC-20": { "incoming": true, "outgoing": false }
    },
    "notification_methods": { "email": true, "webhook": true }
  }'
curl -X POST https://xdcscan.io/account/api/v1/user/watchlist \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address_hash": "0x1234567890abcdef1234567890abcdef12345678",
    "name": "Treasury wallet",
    "notification_settings": {
      "native": { "incoming": true, "outgoing": true },
      "ERC-20": { "incoming": true, "outgoing": false }
    },
    "notification_methods": { "email": true, "webhook": true }
  }'

DELETE /user/watchlist/{id}

Remove an address from the watchlist. Notifications for it stop immediately.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY
id path string required
Watchlist entry ID to remove

Response 200 OK

curl -X DELETE "https://xdcscan.io/account/api/v1/user/watchlist/42" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"
curl -X DELETE "https://xdcscan.io/account/api/v1/user/watchlist/42" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"

Watchlist notifications

Watchlist notifications

Watched addresses generate notifications when matching transactions are indexed — typically within seconds of block confirmation. Delivery is by email, webhook, or both.

Webhooks: configure the endpoint URL in Account → Notifications. The endpoint must accept JSON POST bodies over HTTPS and answer 2xx within 10 seconds; failed deliveries are retried with backoff.

Payload: each delivery is a watchlist.transaction event with the watchlist entry and the full transaction object (hash, from, to, value, block, timestamp).

Signatures: every delivery carries an X-OpenScan-Signature header — an HMAC-SHA256 of the raw body keyed with the secret shown when you create the webhook. Always verify it before processing.

At-least-once delivery: retries mean your endpoint may see the same event twice. Deduplicate on transaction.hash.
# Example webhook payload:
{
  "event": "watchlist.transaction",
  "watchlist_entry": {
    "address_hash": "0x1234567890abcdef1234567890abcdef12345678",
    "name": "Treasury wallet"
  },
  "transaction": {
    "hash": "0x9a8b7c6d...",
    "from": "0x0000000000000000000000000000000000000001",
    "to": "0x1234567890abcdef1234567890abcdef12345678",
    "value": "1500000000000000000000",
    "block": 89000123,
    "timestamp": "2026-08-30T12:34:56Z"
  }
}
# Example webhook payload:
{
  "event": "watchlist.transaction",
  "watchlist_entry": {
    "address_hash": "0x1234567890abcdef1234567890abcdef12345678",
    "name": "Treasury wallet"
  },
  "transaction": {
    "hash": "0x9a8b7c6d...",
    "from": "0x0000000000000000000000000000000000000001",
    "to": "0x1234567890abcdef1234567890abcdef12345678",
    "value": "1500000000000000000000",
    "block": 89000123,
    "timestamp": "2026-08-30T12:34:56Z"
  }
}

PATCH /user/watchlist/{id}

Update a watchlist entry's label, notification settings, or delivery channels.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY
id path string required
Watchlist entry ID
name body string
New label
notification_settings body object
Replacement per-type toggles
notification_methods body object
Replacement delivery channels

Response 200 OK

Omitted fields keep their current values — send only what changes.
curl -X PATCH "https://xdcscan.io/account/api/v1/user/watchlist/42" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "notification_settings": {
      "native": { "incoming": true, "outgoing": false }
    }
  }'
curl -X PATCH "https://xdcscan.io/account/api/v1/user/watchlist/42" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "notification_settings": {
      "native": { "incoming": true, "outgoing": false }
    }
  }'

Tags & custom ABIs

Private tags & custom ABIs

Tags attach your own labels to addresses and transactions; custom ABIs let the explorer decode contracts that are not publicly verified. Both are visible only to your account.

Private tags replace raw hashes with your labels across the explorer UI — in search results, transaction lists, and address pages — but only when you are signed in.

Custom ABIs enable method and event decoding for a contract address for your account's views, without public verification. If you own the contract, verify it publicly instead so everyone benefits — verified contracts expose their ABI through the smart-contracts endpoints.

Common errors:

  • 400 — the address hash is malformed, or the ABI JSON fails to parse.
  • 404 — the tag or ABI ID does not belong to your account.
  • Duplicate tag names are allowed but confusing — prefer unique labels.

GET /user/tags/address

List all private address tags for the authenticated account.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY

Response 200 OK

Field Description
data[].id string
Tag ID — used to delete the tag
data[].address_hash string
Tagged address
data[].name string
Label
curl https://xdcscan.io/account/api/v1/user/tags/address \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"
curl https://xdcscan.io/account/api/v1/user/tags/address \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"

POST /user/tags/address

Create a private tag for an address.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY
address_hash body string required
Address to tag (0x-prefixed)
name body string required
Label (max 35 characters)

Response 201 Created

Field Description
data.id string
Tag ID
Tagging an already-tagged address updates its label in place.
curl -X POST https://xdcscan.io/account/api/v1/user/tags/address \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address_hash": "0x1234567890abcdef1234567890abcdef12345678",
    "name": "Treasury wallet"
  }'
curl -X POST https://xdcscan.io/account/api/v1/user/tags/address \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address_hash": "0x1234567890abcdef1234567890abcdef12345678",
    "name": "Treasury wallet"
  }'

DELETE /user/tags/address/{id}

Delete a private address tag.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY
id path string required
Tag ID to delete

Response 200 OK

curl -X DELETE "https://xdcscan.io/account/api/v1/user/tags/address/7" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"
curl -X DELETE "https://xdcscan.io/account/api/v1/user/tags/address/7" \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"

GET /user/custom-abis

List custom ABIs uploaded by the authenticated account.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY

Response 200 OK

Field Description
data[].id string
Custom ABI record ID
data[].contract_address_hash string
Contract the ABI applies to
data[].name string
Label given at upload
data[].abi array
The ABI JSON
curl https://xdcscan.io/account/api/v1/user/custom-abis \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"
curl https://xdcscan.io/account/api/v1/user/custom-abis \
  -H "Authorization: Bearer $OPENSCAN_API_KEY"

POST /user/custom-abis

Upload a custom ABI for a contract. The explorer uses it to decode methods and events for your account.

Parameter Description
Authorization header string required
Bearer YOUR_API_KEY
contract_address_hash body string required
Contract address (0x-prefixed)
name body string required
Label for the ABI
abi body array | string required
ABI JSON — as an array or a stringified array

Response 201 Created

Field Description
data.id string
Custom ABI record ID
Uploading an ABI for a contract that already has one replaces it.
Publicly verified contracts do not need a custom ABI — their verified ABI takes precedence. See the smart-contracts endpoints in the REST API reference.
curl -X POST https://xdcscan.io/account/api/v1/user/custom-abis \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address_hash": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "name": "MyContract",
    "abi": "[{"type":"function","name":"balanceOf","inputs":[{"name":"account","type":"address"}],"outputs":[{"name":"","type":"uint256"}],"stateMutability":"view"}]"
  }'
curl -X POST https://xdcscan.io/account/api/v1/user/custom-abis \
  -H "Authorization: Bearer $OPENSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_address_hash": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "name": "MyContract",
    "abi": "[{"type":"function","name":"balanceOf","inputs":[{"name":"account","type":"address"}],"outputs":[{"name":"","type":"uint256"}],"stateMutability":"view"}]"
  }'

See also