OpenSea separates application access from wallet identity.
| Credential | How it is sent | Use |
|---|---|---|
| API key | X-API-KEY | REST and MCP access and quota |
| SIWE session | HTTP-only cookies | Create, list, rotate, or revoke scoped personal access tokens (PATs) |
| Scoped PAT | Body of /api/v2/auth/tokens/exchange | Mint replacement wallet JWTs without another signature |
| Wallet JWT | Authorization: Bearer <token> | Short-lived wallet identity and scopes for REST or MCP |
Public REST requests need an API key. Wallet-specific REST requests need both the API key and wallet JWT. MCP data tools follow the same rule; wallet-scoped tools need both credentials. The auth endpoints below and public scope discovery do not require an API key.
Never send a PAT in the Authorization header. Exchange it for a wallet JWT first.
CLI
Use OAuth for interactive work:
npm install -g @opensea/cli
opensea login --scopes read:favorites
opensea auth status
opensea whoamiUse SIWE when a server-side agent controls an EVM signing key:
export OPENSEA_API_KEY="..."
export OPENSEA_PRIVATE_KEY="..."
export DROP_SLUG="your-drop-slug"
opensea login --private-key --scopes read:eligibility
opensea whoami
opensea drops eligibility "$DROP_SLUG"
opensea auth revokeThe CLI keeps credentials in ~/.opensea/auth.json with file mode 0600. It does not store the private key. Run opensea auth refresh after the wallet JWT expires. See the CLI reference for commands.
SDK
OpenSeaAuth handles SIWE, PAT creation, JWT exchange, and session-authorized revocation:
import { ethers } from "ethers";
import { OpenSeaAPI, OpenSeaAuth } from "@opensea/sdk";
const privateKey = process.env.OPENSEA_PRIVATE_KEY;
if (!privateKey) throw new Error("OPENSEA_PRIVATE_KEY is required");
const signer = new ethers.Wallet(privateKey);
const auth = new OpenSeaAuth();
const token = await auth.authenticate(signer, {
scopes: ["read:favorites"],
});
try {
const api = new OpenSeaAPI({
apiKey: process.env.OPENSEA_API_KEY,
authToken: token.accessToken,
});
await api.walletAuth.getFavorites(await signer.getAddress(), { limit: 10 });
} finally {
const current = await auth.getValidToken();
await auth.revoke(current.accessToken);
}See the @opensea/sdk reference for setup.
Manual REST flow
Use this flow if the CLI and SDK are not available:
All paths below are on https://api.opensea.io.
POST /api/v2/auth/siwe/nonceto get a single-use nonce.- Build and sign the exact SIWE message locally.
accountTypeis required (EthereumorSolana); thesiwelibrary does not add it, and omitting it returns400 Invalid signatureeven when the signature is correct. POST /api/v2/auth/siwe/verifywith the parsed message, signature, andchainArch. Keep the returned session cookies.POST /api/v2/auth/tokenswith the cookies, a label, the smallest useful scope set, andexpiresInDays.- Save the returned PAT. The server returns it only once.
POST /api/v2/auth/tokens/exchangewith the PAT assubjectTokenandACCESS_TOKENassubjectTokenType.- Send the returned JWT with your API key:
curl "https://api.opensea.io/api/v2/drops/example/eligibility" \
-H "X-API-KEY: $OPENSEA_API_KEY" \
-H "Authorization: Bearer $OPENSEA_WALLET_JWT"PAT management is session-only. Use the SIWE session cookies with these endpoints:
| Method | Path | Action |
|---|---|---|
GET | /api/v2/auth/tokens | List PATs |
POST | /api/v2/auth/tokens | Create a PAT |
POST | /api/v2/auth/tokens/{id}/rotate | Rotate a PAT |
DELETE | /api/v2/auth/tokens/{id} | Revoke a PAT |
A wallet JWT cannot manage PATs. Revoking or rotating a PAT stops new exchanges, but JWTs already issued from it remain valid until they expire.
MCP
Connect to https://mcp.opensea.io/mcp. Compatible clients discover OAuth from the server automatically.
MCP data tools require X-API-KEY. Wallet-scoped tools also require the wallet JWT in Authorization: Bearer. The API key supplies access and quota; the JWT supplies wallet identity and scopes.
You can connect without credentials for the handshake, tools/list, and get_instant_api_key. Add the returned API key and reconnect before calling data tools. See the MCP setup guide.
Scopes
Discover the current scopes and their REST endpoints and MCP tools:
curl "https://api.opensea.io/api/v2/auth/scopes"
opensea auth scopesRequest only the scopes needed for the task. The live OpenAPI document contains the current request fields, response schemas, and scope requirements.
Token lifecycle
| Credential | Lifetime | Renewal |
|---|---|---|
| SIWE access cookie | 3.5 days | Refresh with /api/v2/auth/session/refresh |
| SIWE refresh cookie | 30 days | Sign in again after expiry |
| Scoped PAT | Set at creation | Rotate or create another PAT using the SIWE session |
| Wallet JWT | About 12 hours | Exchange the PAT again |
Session refresh rotates the refresh cookie. Store the newest cookie values.
Errors
| Status | What to do |
|---|---|
401 | Supply or replace the API key, or refresh an expired wallet JWT once |
403 | Request a PAT or OAuth token with the missing scope; do not retry unchanged credentials |
429 | Wait for Retry-After before retrying |
Safety
- Keep private keys, API keys, PATs, JWTs, cookies, signatures, and full authorization headers out of prompts, logs, client-side code, and version control.
- Keep signing keys in environment variables or a secrets manager. Do not pass them as command arguments.
- Use a separate, minimally funded wallet for testing and request the smallest useful scope set.
- Revoke task-specific PATs when the task is complete.
- Require human confirmation before signing or broadcasting a spend-bearing transaction.
For API-key options and limits, see Getting Your API Key.
