API Keys & Authentication
Learn how to get your API key and authenticate your requests to Inodra's APIs.
Getting Your API Key
1. Create an Account
Sign up for a free Inodra account at inodra.com.
2. Select or Create a Project
API keys belong to projects, which are tied to specific Sui networks:
- Navigate to Projects in your dashboard
- Select an existing project or create a new one
- Choose the network (Mainnet or Testnet) for your project
Learn more about Projects and how to organize your resources.
3. Generate an API Key
- Navigate to API Keys in the sidebar
- Ensure the correct project is selected in the header dropdown
- Click Generate New API Key
- Give your key a descriptive name (e.g., "Production App", "Development")
- Copy your API key and store it securely
Note: API keys are project-specific. A key generated for a Mainnet project will only work with Mainnet endpoints.
⚠️ Keep your API key secure! Never commit API keys to version control. If you ship a key in client-side code, restrict it first: give it only the scopes it needs (see API Key Scopes) and limit it to your site's origins (see Allowed Origins). API Key Security covers every control in one place.
4. API Key Format
Your API key will look like this:
indr_pat_qsVOAbCdEf123456789...All Inodra API keys start with the indr_pat_ prefix. Treat anything with that prefix in a log, a commit, or a screenshot as a live credential.
API Key Scopes
Every API key carries a set of scopes that control which parts of the platform it can access:
| Scope | Grants access to | Typical use |
|---|---|---|
| Data | JSON-RPC, GraphQL, gRPC, and REST read endpoints | Reading chain data, including from frontends |
| Streams | Connecting to existing Warp streams (SSE and WebSocket) | Live event feeds in apps and frontends |
| Manage | Creating/editing/deleting webhooks and Warp streams, usage stats, key info | Backend services and automation |
New keys get the Data scope by default. Select additional scopes when creating a key, or change them later from the dashboard (click the Scopes summary on any key). Scope changes take effect within a few seconds.
A request made with a key that lacks the required scope is rejected with 403 and the error code INSUFFICIENT_SCOPE (WebSocket connections close with code 4003; gRPC calls fail with PERMISSION_DENIED).
Frontend keys: scopes exist so you can safely ship a key in a browser app. Give such keys Data (and Streams if you use Warp) but never Manage - a Manage-scoped key can read webhook signing secrets and redirect webhook deliveries, so keep it server-side only.
Allowed Origins
A key can be restricted to a list of web origins. When the list is not empty, the request must carry an Origin header that matches an entry. Set it from the Origins control on any key, or when you create it.
This is the control that makes a key in a public web page survivable: a copy lifted from your site cannot be replayed from another site, because a browser sets Origin itself and page JavaScript cannot forge it.
Entries look like [scheme://][*.]host[:port]:
| Entry | Matches |
|---|---|
example.com | example.com on any scheme and any port |
*.example.com | Any subdomain of example.com. Not the apex domain itself |
https://app.example.com | Exactly that origin |
http://localhost:3000 | Local development |
A restricted key fails closed: a request with no Origin is rejected with 403 and code ORIGIN_NOT_ALLOWED (WebSocket close code 4003, gRPC PERMISSION_DENIED). Native gRPC clients send no Origin, so they cannot use a restricted key.
Not an access control for backends: any non-browser caller can send whatever
Originit likes. Origin restriction stops key lifting from browsers. Pair it with a per-IP cap (see Rate Limits), which applies to everyone.
Full details, including matching rules and limits, are in API Key Security.
Rate Limits
Beyond your plan's organization-wide limit, each key can carry two optional caps (set them from the Limits control on any key in the dashboard):
| Cap | What it bounds | Use it for |
|---|---|---|
| Per visitor IP | Requests from a single IP address, for this key | Keys embedded in a website - each visitor gets their own budget |
| Per key | All traffic through this key combined | A ceiling for one integration |
The per-IP cap is what makes a browser-embedded key safe to ship: one abusive visitor - or someone who copies the key out of your page and replays it from their own server - is stopped at their own budget instead of draining your organization's quota. Keep it generous (20/s is a reasonable starting point): offices and mobile networks put many legitimate visitors behind a single IP.
Both caps apply to requests and stream connections - opening a Warp SSE or WebSocket stream counts once, when the connection is established. Events delivered over an already-open stream are not rate limited; their cost is metered in compute units instead.
Note: the per-IP cap depends on identifying the visitor, so treat it as a strong guard against a single abusive visitor rather than an absolute one. The per-key cap always applies, so set that too if you need a hard ceiling.
Requests rejected by either cap return 429 with code RATE_LIMIT_EXCEEDED and a Retry-After header - and do not consume credits, so an attacker cannot run up your bill. (A 429 from your plan's organization-wide limit is billed normally.)
The response deliberately doesn't say which of the two caps was hit, or what you configured it to: your key is readable by anyone using your site, and that detail would tell them how to work around it. You can always see the caps you set on the key in the dashboard.
Authentication
Include your API key in the x-api-key header for all requests:
JSON-RPC Authentication
curl -X POST https://mainnet-api.inodra.com/v1/jsonrpc \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"sui_getLatestCheckpointSequenceNumber","params":[]}'GraphQL Authentication
curl -X POST https://mainnet-api.inodra.com/v1/graphql \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"query": "{ checkpoints(first: 10) { nodes { sequenceNumber } } }"}'gRPC Authentication
Primary:
ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", "YOUR_API_KEY")
response, err := client.GetLatestCheckpoint(ctx, &GetLatestCheckpointRequest{})Fallback:
ctx := metadata.AppendToOutgoingContext(context.Background(), "authorization", "Bearer YOUR_API_KEY")HTTP Authentication (GraphQL / JSON-RPC)
curl -X POST https://mainnet-api.inodra.com/v1/graphql \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ chainIdentifier }"}'Managing API Keys
Viewing Keys
In your dashboard, you can:
- View all your API keys
- See last used timestamps
- Monitor usage statistics per key
Rotating Keys
For security best practices:
- Generate a new API key
- Update your applications to use the new key
- Delete the old key once migration is complete
Revoking Keys
If a key is compromised:
- Go to your dashboard
- Find the compromised key
- Click Delete to immediately revoke access
Organizations & Teams
Creating Organizations
Organizations allow you to:
- Share API keys with team members
- Manage billing centrally
- Set usage limits per team
Inviting Team Members
- Go to Organizations in your dashboard
- Click Invite Members
- Enter email addresses
- Assign roles (Admin or Member)
Role Permissions
- Admin: Full access to billing, keys, and team management
- Member: Can create and manage API keys, view usage statistics
Testing Your Setup
Verify your API key works:
# Test with a simple checkpoint query
curl -X POST https://mainnet-api.inodra.com/v1/jsonrpc \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getLatestCheckpointSequenceNumber",
"params": []
}'Expected response:
{
"jsonrpc": "2.0",
"result": "12345678",
"id": 1
}Common Issues
Invalid API Key
- Error:
401 Unauthorized - Solution: Check that your API key is correct and active
Missing Header
- Error:
401 Unauthorized - Solution: Ensure you're including the
x-api-keyheader
Insufficient Scope
- Error:
403 Forbiddenwith codeINSUFFICIENT_SCOPE - Solution: The key lacks the scope that endpoint requires (see API Key Scopes). Edit the key's scopes in the dashboard, or use a key that has the right scope.
Origin Not Allowed
- Error:
403 Forbiddenwith codeORIGIN_NOT_ALLOWED - Solution: The key is restricted to specific web origins and this request's origin is not on its allowlist (see Allowed Origins). Add the origin in the dashboard, or use an unrestricted key. Clients that send no
Origincannot use a restricted key.
Network Mismatch
- Error:
403 Forbiddenwith codeNETWORK_MISMATCH - Solution: The key belongs to a project on the other network. Use the endpoint that matches the key's network, or a key from a project on that network.
Rate Limit Exceeded (per key or per IP)
- Error:
429 Too Many Requestswith codeRATE_LIMIT_EXCEEDED - Solution: You hit a cap set on this specific key (see Rate Limits). Honor the
Retry-Afterheader, or raise/remove the cap in the dashboard. These rejections don't consume credits.
Expired Key
- Error:
401 Unauthorizedwith codeAPI_KEY_EXPIRED - Solution: The key passed its expiration date. Generate a new key in the dashboard and update your application. Expired keys show an Expired badge in the dashboard's key list.
Rate Limit Exceeded (organization-wide)
- Error:
429 Too Many Requests, with nocodefield and aretryAftervalue in the body - Solution: You hit your plan's requests-per-second limit, shared by every key in the organization. Wait
retryAfterseconds, spread the load, or upgrade your plan. TheX-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Resetheaders on every response show where you stand.
Credit Quota Exceeded
- Error:
429 Too Many Requestswith codeCU_QUOTA_EXCEEDED - Solution: The organization has spent its monthly compute units. Check
X-Inodra-Credit-RemainingandX-Inodra-Credit-Replenish-Dateon any response, then upgrade your plan or wait for the reset. Open Warp WebSocket streams close with code1008and reasonQUOTA_EXCEEDED.