Authentication
The Agent API uses a two-layer authentication system:
- JWT tokens -- Obtained by signing a message with your blockchain wallet. Used exclusively for API key management (creating, listing, revoking keys).
- API keys -- Long-lived credentials used for all agent endpoints (pool discovery, trading, webhooks). Each key has scoped permissions.
Wallet signature --> JWT token --> Create API key --> Use API key for all endpoints
JWT Authentication (Wallet Login)
JWT authentication ties API access to a blockchain wallet address. This ensures that only the wallet owner can create and manage API keys, and that all operations performed with those keys are attributed to that wallet.
Step 1: Request a Nonce
Request a one-time nonce that you will sign with your wallet.
curl -X POST https://home.dobprotocol.com/api/agent/auth/nonce \
-H "Content-Type: application/json" \
-d '{"wallet_address": "GBDM6KRXXJHKVYFJPTPW3WBDKUYVCH7NNEI67DDCP7YX4UHX2GODPHGI"}'
Response:
{
"success": true,
"data": {
"nonce": "dob_nonce_a1b2c3d4e5f6...",
"message": "Sign this message to authenticate with DobProtocol Agent API: dob_nonce_a1b2c3d4e5f6...",
"expires_at": "2026-03-10T12:30:00Z"
}
}
The nonce expires after 5 minutes. Request a new one if it expires before you sign.
Step 2: Sign the Message
Sign the message field using your wallet's private key. The signature method depends on the blockchain:
Stellar (ed25519):
from stellar_sdk import Keypair
keypair = Keypair.from_secret("SCZANGBA5YHTNYVVV3C7CAZMCLXPILHSE5BXBSOLRRUQSXKFHM7RI5OB")
message = "Sign this message to authenticate with DobProtocol Agent API: dob_nonce_a1b2c3d4e5f6..."
signature = keypair.sign(message.encode()).hex()
EVM (secp256k1):
from eth_account.messages import encode_defunct
from eth_account import Account
message = "Sign this message to authenticate with DobProtocol Agent API: dob_nonce_a1b2c3d4e5f6..."
signed = Account.sign_message(encode_defunct(text=message), private_key="0x...")
signature = signed.signature.hex()
Step 3: Verify and Obtain JWT
Submit the signature to receive a JWT token.
curl -X POST https://home.dobprotocol.com/api/agent/auth/verify \
-H "Content-Type: application/json" \
-d '{
"wallet_address": "GBDM6KRXXJHKVYFJPTPW3WBDKUYVCH7NNEI67DDCP7YX4UHX2GODPHGI",
"signature": "3a4b5c6d...",
"chain": "stellar"
}'
The chain field accepts "stellar" or "evm".
Response:
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2026-03-11T12:00:00Z",
"wallet_address": "GBDM6KRXXJHKVYFJPTPW3WBDKUYVCH7NNEI67DDCP7YX4UHX2GODPHGI"
}
}
JWT tokens are valid for 24 hours. Use the token in the Authorization header for key management endpoints:
curl https://home.dobprotocol.com/api/agent/auth/keys \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
API Key Authentication
API keys are the primary authentication method for all agent endpoints. They are long-lived, scoped, and do not require wallet interaction for each request.
Using API Keys
Include your API key in the X-API-Key header:
curl https://home.dobprotocol.com/api/agent/pools \
-H "X-API-Key: dob_ak_7f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a"
import requests
headers = {"X-API-Key": "dob_ak_7f3a9b2c..."}
response = requests.get(
"https://home.dobprotocol.com/api/agent/pools",
headers=headers
)
Key Format
API keys follow the format:
dob_ak_ + 64 hexadecimal characters
Example: dob_ak_7f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a
Key Storage and Security
- API keys are hashed with SHA-256 before storage. DobProtocol never stores your key in plaintext.
- The full key is returned only once at creation time. If you lose it, you must create a new key.
- Keys are bound to the wallet address that created them. Operations performed with a key are attributed to that wallet.
- Treat API keys like passwords. Do not commit them to version control or expose them in client-side code.
Scopes
Each API key has one or more scopes that determine what operations it can perform:
| Scope | Permissions |
|---|---|
read | Pool discovery, portfolio queries, marketplace listings (read-only), webhook management |
trade | Marketplace operations (buy, list, cancel), crowdfunding contributions |
A key with only the read scope cannot perform trading operations. A key with trade scope also needs read scope to discover pools and listings before trading.
Recommended configurations:
| Use Case | Scopes |
|---|---|
| Dashboard / monitoring | ["read"] |
| Trading bot | ["read", "trade"] |
| Webhook-only listener | ["read"] |
If a request requires a scope that the API key does not have, the API returns a 403 error with code INSUFFICIENT_SCOPE.
Complete Authentication Flow
Here is the end-to-end flow in Python:
import requests
BASE = "https://home.dobprotocol.com/api/agent"
WALLET = "GBDM6KRXXJHKVYFJPTPW3WBDKUYVCH7NNEI67DDCP7YX4UHX2GODPHGI"
# Step 1: Get nonce
nonce_resp = requests.post(f"{BASE}/auth/nonce", json={
"wallet_address": WALLET
}).json()
message = nonce_resp["data"]["message"]
# Step 2: Sign the message (using stellar_sdk)
from stellar_sdk import Keypair
keypair = Keypair.from_secret("SCZANGBA5YHTNYVVV3C7CAZMCLXPILHSE5BXBSOLRRUQSXKFHM7RI5OB")
signature = keypair.sign(message.encode()).hex()
# Step 3: Get JWT
jwt_resp = requests.post(f"{BASE}/auth/verify", json={
"wallet_address": WALLET,
"signature": signature,
"chain": "stellar"
}).json()
jwt_token = jwt_resp["data"]["token"]
# Step 4: Create an API key
key_resp = requests.post(f"{BASE}/auth/keys",
headers={"Authorization": f"Bearer {jwt_token}"},
json={"label": "my-bot", "scopes": ["read", "trade"]}
).json()
api_key = key_resp["data"]["key"]
print(f"API Key: {api_key}") # Save this! Only shown once.
# Step 5: Use the API key for all subsequent requests
pools = requests.get(f"{BASE}/pools",
headers={"X-API-Key": api_key},
params={"network_id": 10}
).json()
print(pools["data"])
Security Best Practices
- Use minimum required scopes. If your application only reads data, create a key with
["read"]only. - Rotate keys regularly. Use the key rotation endpoint to get a new key without downtime.
- Store keys in environment variables or a secrets manager. Never hardcode them.
- Revoke compromised keys immediately using the revoke endpoint.
- Use separate keys for separate services. This limits blast radius if one key is compromised and makes auditing easier.