
AIOZ Pin API keys aren't one flat secret with full access by default, they're generated with a specific set of scopes attached, and the actual authentication mechanics differ slightly depending on which endpoint you're calling. This covers the parts that don't show up in a quick glance at the docs: which endpoints expect a Bearer token versus raw key/secret headers, exactly what a scoped key can and can't do, and how to store credentials safely once you have them.
TL;DR:
Authorization: Bearer <access_token>testAuthentication and the Nft API instead use raw pinning_api_key/pinning_secret_key headersadmin, data, pinning, pin_nft) rather than defaulting to full accessGenerating, listing, and deleting API keys, along with account endpoints like /users/me, all authenticate with the standard pattern: Authorization: Bearer your_access_token_here. But testAuthentication and the Nft API work differently, they expect pinning_api_key and pinning_secret_key as separate headers, the raw key and secret rather than a bearer token. That's not an inconsistency to route around, it lines up with what those endpoints actually do: testAuthentication exists specifically to verify a key/secret pair is valid, and the Nft API is built to be called directly with a scoped key rather than through an intermediate token exchange.
In practice, this distinction matters most when you're debugging: if a call to /users/me or /apiKeys/list fails with an auth error, check your Bearer token. If a call to testAuthentication or the Nft API fails, check the raw key and secret values themselves, those endpoints aren't reading a token at all.
Generating a key is a POST to /apiKeys with a scopes object:
{
"admin": false,
"data": { "pin_list": true, "nft_list": false },
"pinning": { "unpin": false, "pin_by_hash": true, "pin_file_to_ipfs": true },
"pin_nft": { "unpin_nft": false, "pin_nft_to_ipfs": false }
}
AIOZ Pin's docs specify that non-admin keys need every property included explicitly, there's no partial-scope shorthand. Admin keys are the one exception: set "admin": true and the sub-properties can be omitted entirely, since an admin key already has full access regardless of what the other fields say. This means a key handed to a build pipeline that only pins new files can be scoped to pinning.pin_file_to_ipfs alone, with no ability to unpin existing content, touch NFT operations, or read billing data, a meaningfully smaller blast radius than one shared admin key used everywhere.
Every AIOZ Pin surface, the REST API, the Node.js SDK, and the CLI, ultimately needs the same key and secret, just supplied differently. The SDK takes them directly in its constructor (new AiozPinClient(apiKey, secretKey)), the CLI accepts them as --key/--secret flags or reads them from a ~/.pinning/credentials JSON file so you don't retype them every invocation, and the raw REST API expects them wrapped into the appropriate header for whichever endpoint you're calling. Whichever layer you're using, avoid hardcoding the raw values into source code that ends up committed anywhere, environment variables or the CLI's credentials file keep the secret out of your codebase's history.
The practical reason scoping is worth setting up correctly, not just leaving every key at admin by default, shows up the moment credentials leak, and they eventually do: committed to a public repo by accident, exposed in a client-side bundle, pasted into the wrong Slack channel. An admin key leaked this way hands whoever finds it full account access: read billing, unpin anything, mint NFT records, everything. A key scoped to pinning.pin_file_to_ipfs alone, the kind a build pipeline actually needs, leaked the same way, only lets an attacker pin new files under your account, real damage in the sense of unwanted storage costs, but not the ability to delete existing pins, touch NFT operations, or read anything, because those permissions were never granted to that key in the first place. Scoping doesn't prevent a leak, nothing about key management does. It bounds what a leak actually costs, which is the entire point of generating separate keys per integration instead of one credential reused everywhere.
DELETE /api/apiKeys/:id removes a key immediately, using the id returned when you generated it or from a GET /api/apiKeys/list call. Because keys are scoped individually, rotating credentials for one integration doesn't require touching any other key you've issued, generate a new scoped key for the specific use case, update that one integration, then delete the old key once you've confirmed the new one works.
Before deciding what to rotate or tighten, it helps to actually see what's currently issued: GET /api/apiKeys/list returns every key on the account, its id, a truncated or masked view of the key itself, its scopes, and when it was created. For an account that's accumulated keys over time, one per integration as this article recommends, this is the practical starting point for a periodic security review: confirm every listed key still corresponds to something actually in use, and that none of them are scoped more broadly than the integration behind them actually needs. A key issued months ago for a project that's since been decommissioned, still valid, still capable of pinning or reading data, is exactly the kind of unnecessary exposure a five-minute audit against this endpoint catches before it becomes a real problem.
Does every AIOZ Pin API endpoint use the same authentication header? No. Account and key-management endpoints use Authorization: Bearer <access_token>, while testAuthentication and the Nft API use raw pinning_api_key and pinning_secret_key headers instead.
Can an AIOZ Pin API key be limited to only pinning, with no delete access? Yes. Scopes are granular down to individual permissions like pin_file_to_ipfs or unpin, so a key can be issued with only the specific permissions an integration actually needs.
Do I need to specify every scope property when generating a key? For non-admin keys, yes, AIOZ Pin's docs specify all properties must be included. Admin keys are the exception: setting admin: true alone is sufficient, sub-properties can be omitted.
How do I revoke an AIOZ Pin API key? DELETE /api/apiKeys/:id, using the key's ID from when it was generated or from a GET /api/apiKeys/list call.
Where should I store my AIOZ Pin API key and secret? Not in source code. Use environment variables for the SDK or REST API, or the CLI's ~/.pinning/credentials file, so the raw secret doesn't end up committed to a repository.
~/.pinning/credentials file storage pattern in practice
ERC-1155 metadata on IPFS breaks when filenames ignore the {id} rule. Here is the exact 64-character format, a working folder layout, and the per-token option.

AIOZ Pin rate limits in one place: 180 requests per minute for the API, 15 per CID on the public gateway, and no predefined limit on premium gateways.

IPFS pin stuck on Pinning? Here is what Pinning, Pinned, and Failed mean on AIOZ Pin, why big directories can sit there, and how to read a pin's real state.

Two identical files, three IPFS tools, three different CIDs. Here is why that happened for years, and how IPIP-0499 made content addressing deterministic.

AIOZ Pin MCP server setup has two paths: llms.txt lets a super intelligence assistant read the API, the MCP server lets it call 11 tools. Here is each one.

AIOZ Pin bills three flat rates against a token wallet, with no tiers to pick between. Here is what storage, bandwidth and pinned files cost, with examples.