Troubleshooting
Common issues and solutions when working with Inodra's Sui infrastructure.
Authentication Issues
Invalid API Key (401)
Symptoms: API requests return 401 Unauthorized
Solutions:
Verify API Key Format
- Keys should start with
indr_ - Check for extra whitespace or copy-paste errors
- Keys should start with
Check Dashboard
- Log into inodra.com/dashboard
- Verify key status is "Active"
- Ensure usage limits haven't been exceeded
Correct Header Format
javascript// Primary method (recommended) headers: { 'x-api-key': 'indr_abc123...' } // Alternative (also works) headers: { 'Authorization': 'Bearer indr_abc123...' } // Common mistakes headers: { 'X-API-KEY': 'indr_abc123...', // Wrong! Case sensitive 'api-key': 'indr_abc123...' // Wrong! Must be x-api-key }
Expired API Key (401)
Symptoms: requests return 401 with the error code API_KEY_EXPIRED (WebSocket close code 4001; gRPC UNAUTHENTICATED with message "API key expired"). A key that used to work stops working on its expiry date.
Solutions:
- Open API Keys in the dashboard - expired keys carry an Expired badge and show their expiry date in red
- Generate a replacement key and update your application; keys can be set to never expire
- Note the distinction:
API_KEY_EXPIREDmeans the key was real but is past its date, while a plainINVALID_API_KEYmeans the key is unknown, disabled, or mistyped
Insufficient Scope (403)
Symptoms: API requests return 403 Forbidden with the error code INSUFFICIENT_SCOPE; WebSocket connections close with code 4003; gRPC calls fail with PERMISSION_DENIED.
Cause: Every API key carries scopes (Data, Streams, Manage) and the endpoint you called needs one the key doesn't have. For example, chain reads need Data, connecting to Warp streams needs Streams, and webhook/stream management needs Manage.
Solutions:
- Open API Keys in the dashboard and click the key's Scopes summary to see and edit its scopes - changes apply within a few seconds
- For frontend-embedded keys, keep Manage off and perform management calls server-side with a separate key
See API Key Scopes for the full scope reference.
Rate Limit Exceeded (429)
Symptoms: API returns HTTP 429 Too Many Requests
Solutions:
Check Rate Limit Headers
bashcurl -I -H "x-api-key: YOUR_KEY" https://mainnet-api.inodra.com/v1/checkpoints # Look for these headers: # X-RateLimit-Limit: 1000 # X-RateLimit-Remaining: 50 # X-RateLimit-Reset: 1640995200 # Retry-After: 60Implement Exponential Backoff
javascriptasync function makeRequestWithRetry(url, options, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { const response = await fetch(url, options) if (response.status === 429) { const retryAfter = response.headers.get('retry-after') || Math.pow(2, i) await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000)) continue } return response } }Optimize Request Patterns
- Use pagination for large datasets
- Cache frequently accessed data
- Batch requests when possible
- Consider upgrading plan for higher limits
Connection Issues
Request Timeouts
Symptoms: Requests timeout or take very long
Solutions:
Increase Timeout Values
javascriptconst response = await fetch('https://mainnet-api.inodra.com/v1/transactions', { headers: { 'x-api-key': 'YOUR_KEY' }, signal: AbortSignal.timeout(30000) // 30 seconds })Use Pagination
javascript// Request smaller chunks const response = await fetch('/v1/transactions?limit=100')Test Connectivity
bashping mainnet-api.inodra.com curl -I https://mainnet-api.inodra.com/health
DNS Resolution Issues
Symptoms: Cannot resolve mainnet-api.inodra.com
Solutions:
# Test DNS resolution
nslookup mainnet-api.inodra.com
dig mainnet-api.inodra.com
# Try alternative DNS servers
# Google DNS: 8.8.8.8, 8.8.4.4
# Cloudflare DNS: 1.1.1.1, 1.0.0.1Webhook Issues
Not Receiving Events
Symptoms: Webhooks created but no events received
Solutions:
Test Webhook URL
bashcurl -X POST https://your-domain.com/webhook \ -H "Content-Type: application/json" \ -d '{"test": true}'Verify Event Filters
- Check event type format:
package::module::Event - Remove sender filter to test broader scope
- Confirm events are actually occurring on blockchain
- Check event type format:
Check HTTPS
- Webhook URLs must use HTTPS in production
- Verify SSL certificate validity
- Test:
openssl s_client -connect your-domain.com:443
Duplicate Events
Symptoms: Same event delivered multiple times
Cause: Webhooks use at-least-once delivery (normal behavior)
Solution:
// Implement idempotency
const processedEvents = new Set()
app.post('/webhook', (req, res) => {
const eventId = req.body.id
if (processedEvents.has(eventId)) {
return res.status(200).send('Already processed')
}
processedEvents.add(eventId)
processEvent(req.body)
res.status(200).send('OK')
})Processing Timeouts
Symptoms: Webhook deliveries marked as failed
Cause: Endpoint takes > 10 seconds to respond
Solution:
// Return 200 immediately, process async
app.post('/webhook', (req, res) => {
// Acknowledge receipt immediately
res.status(200).send('OK')
// Process in background
processWebhookAsync(req.body)
})
async function processWebhookAsync(event) {
try {
await processEvent(event)
} catch (error) {
console.error('Webhook processing failed:', error)
}
}Data Issues
Transaction Not Found (404)
Symptoms: API returns 404 for valid transaction digest
Causes:
- Transaction very recent (not yet indexed)
- Invalid digest format
Solutions:
Wait and Retry for recent transactions
javascriptasync function getTransactionWithRetry(digest, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fetch(`/v1/transactions/${digest}`) } catch (error) { if (error.status === 404 && i < maxRetries - 1) { await new Promise((resolve) => setTimeout(resolve, 2000)) continue } throw error } } }Validate Digest Format
javascriptfunction isValidTxDigest(digest) { return /^[1-9A-HJ-NP-Za-km-z]{44}$/.test(digest) }
Response Format Issues
Symptoms: Response doesn't match expected schema
Solutions:
Check Response Headers
javascriptconst response = await fetch('/v1/checkpoints') console.log('Content-Type:', response.headers.get('content-type')) console.log('API-Version:', response.headers.get('x-api-version'))Validate JSON
javascripttry { const data = await response.json() } catch (error) { console.error('Invalid JSON:', await response.text()) }Check API Documentation
- Verify endpoint exists and format
- Review the API Reference for current specifications
Performance Optimization
Slow Response Times
Solutions:
Use Pagination
javascript// Request smaller chunks const fetchTransactions = async (address, limit = 100) => { let allTxs = [] let cursor = null do { const params = new URLSearchParams({ limit }) if (cursor) params.set('cursor', cursor) const response = await fetch(`/v1/accounts/${address}/transactions?${params}`) const data = await response.json() allTxs.push(...data.data) cursor = data.pagination?.cursor } while (cursor) return allTxs }Use Specific Endpoints
javascript// Good: Get only what you need const balance = await fetch(`/v1/accounts/${address}/balance`) // Avoid: Get everything then extract what you need const account = await fetch(`/v1/accounts/${address}`)Implement Caching
javascriptconst cache = new Map() async function getCachedData(url, ttl = 60000) { const cached = cache.get(url) if (cached && Date.now() - cached.timestamp < ttl) { return cached.data } const data = await fetch(url).then((r) => r.json()) cache.set(url, { data, timestamp: Date.now() }) return data }
Getting Help
Support Channels
- Status Page - Check service status
- Discord Community - Community support
- Support Email - Direct support
Diagnostic Information
When contacting support, include:
Full Request
bashcurl -v -H "x-api-key: indr_xxx" \ "https://mainnet-api.inodra.com/v1/checkpoints"Error Details
- Full error response body
- HTTP status code
- Timestamp of issue
Environment
- Operating system
- Programming language/version
- Library versions (if applicable)