API
The Vulcan API lets your own website, bot or scripts read the same member data the Member Dashboard shows: who is in your server, whether they verified, the wallets they linked, and the roles they hold. Use it to gate a holder portal, build an allowlist, or sync members into your own tools.
The API is read-only and part of the Pro and Enterprise plans. Each key reads one server.
Create a key
- Open API under Support in the dashboard sidebar.
- Name the key after what will use it, for example Holder portal, and choose Create key.
- Copy the key straight away. Vulcan keeps only a fingerprint of it, so it cannot be shown again. If you lose it, revoke it and create another.
Only the server owner and people with Administrator or Manage Roles on Discord can create or revoke keys. Team members can see the list.
A server can have up to 5 keys at once, so you can give each integration its own and rotate one without downtime: create the new key, switch your code over, then revoke the old one.
Treat a key like a password. Anyone holding it can read every member's linked wallets. Keep it on a server you control. Never put it in a website's front-end code, a public repository or a Discord message.
If the server drops below Pro, its keys stop working until it is back on Pro. They are not deleted.
Making requests
Every request is a GET to https://api.vulcan.xyz/v1/ with the key as a bearer token:
curl https://api.vulcan.xyz/v1/server/ \
-H "Authorization: Bearer YOUR_KEY"
Responses are JSON. Discord IDs are longer than JavaScript can hold exactly as numbers, so every ID is a string. Times are ISO 8601 in UTC.
Endpoints
GET /server/
The server the key belongs to. The quickest way to check a key works.
{
"id": "923315187519737866",
"name": "Example Club",
"plan": "pro",
"members_synced_at": "2026-10-13T04:12:09+00:00"
}
members_synced_at is when Vulcan last pulled your member list and roles from Discord. It is null before the first pull and while a pull is running.
GET /members/
Members of your server, a page at a time, in Discord ID order.
| Parameter | |
|---|---|
verified |
true for members who linked a wallet to this server, false for those who have not. Leave it out for everyone. |
role |
A Discord role ID: only members holding that role. |
limit |
Members per page, 1 to 500. Default 100. |
cursor |
The next_cursor from the previous page. |
{
"members": [
{
"discord_id": "112233445566778899",
"name": "Ada",
"username": "ada.eth",
"in_server": true,
"verified": true,
"roles": [{"id": "998877665544332211", "name": "Holder"}],
"wallets": ["0x1234…abcd"],
"joined_server_at": "2025-03-02T18:40:11+00:00",
"first_vulcan_role_at": "2025-03-02T18:44:52+00:00"
}
],
"next_cursor": "112233445566778899"
}
Keep requesting with cursor set to next_cursor until it is null.
in_serverisfalsefor a verified member who has left your server, once Vulcan's next pull of your member list from Discord notices. Withverified=truethey are still listed; otherwise only current members are.rolesisnullif Discord has not yet told Vulcan this member's roles.walletslists only the wallets the member linked to your server, not wallets they linked elsewhere.first_vulcan_role_atis when Vulcan first gave them a role in your server.
GET /members/{discord_id}/
One member, in the same shape, under "member". 404 if they are neither in your server nor verified in it.
GET /wallets/{address}/
Who in your server linked this wallet:
{"wallet": "0x1234…abcd", "member": {"discord_id": "112233445566778899", …}}
404 if no member linked that wallet to your server, even if it is linked to another server.
GET /roles/
Every role in your server, highest first, with how many members hold it:
{
"roles": [
{
"id": "998877665544332211",
"name": "Holder",
"position": 12,
"members": 1840,
"verified_members": 1802,
"granted_by_vulcan": true
}
]
}
granted_by_vulcan is true when one of your verification rules grants the role. The counts are the ones on your dashboard's member overview and can be up to an hour old.
How fresh the data is
The API reads what Vulcan already knows. It never checks a wallet's holdings or asks Discord while you wait. Vulcan updates roles within minutes of a transfer and re-checks on your plan's schedule. Member lists and role counts come from Discord pulls and the bot's live events.
Limits
Each server can make up to 60 requests a minute and 10,000 a day, shared across all its keys. Every request made with a valid key on a Pro server gets X-RateLimit-Limit and X-RateLimit-Remaining headers. Over the limit you get 429 with a Retry-After header in seconds.
Errors
Errors return a status code and a body like:
{"error": {"code": "invalid_key", "message": "…"}}
| Status | code |
Meaning |
|---|---|---|
| 400 | invalid_parameter |
A query parameter is not valid. |
| 401 | invalid_key |
The key is missing, mistyped or revoked. |
| 403 | plan_required |
The server is not on Pro or Enterprise. |
| 404 | not_found |
No such member or wallet in this server. |
| 429 | rate_limited |
Over the limit. Wait Retry-After seconds. |