Skip to main content

Authentication

The Agent API uses a two-layer authentication system:

  1. JWT tokens -- Obtained by signing a message with your blockchain wallet. Used exclusively for API key management (creating, listing, revoking keys).
  2. 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:

ScopePermissions
readPool discovery, portfolio queries, marketplace listings (read-only), webhook management
tradeMarketplace 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 CaseScopes
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

  1. Use minimum required scopes. If your application only reads data, create a key with ["read"] only.
  2. Rotate keys regularly. Use the key rotation endpoint to get a new key without downtime.
  3. Store keys in environment variables or a secrets manager. Never hardcode them.
  4. Revoke compromised keys immediately using the revoke endpoint.
  5. Use separate keys for separate services. This limits blast radius if one key is compromised and makes auditing easier.