Upload an IDL
Run as the program's upgrade authority to publish a canonical IDL (the one this explorer surfaces by default):
npx @solana-program/program-metadata@latest write idl <program-id> ./idl.jsonProgrammatic access to on-chain Solana program IDLs. Same engine that powers the explorer, available as an HTTP API, a CLI (@solana/idl), and a Node library. Resolves canonical PMP → fndn fallback PMP → Anchor.
Full reference, exports, and architecture in the GitHub README.
This explorer reads on-chain metadata. To write it — both IDLs and security.txt — use the official @solana-program/program-metadata CLI. Same seed-based PMP account that this site fetches from: idl for IDLs, security for security.txt.
Run as the program's upgrade authority to publish a canonical IDL (the one this explorer surfaces by default):
npx @solana-program/program-metadata@latest write idl <program-id> ./idl.jsonsecurity.txtSame command, swap the seed. Use the SPL JSON shape — the full 17 keys (Neodyme spec + PMP extensions like logo / description / version) are documented upstream.
npx @solana-program/program-metadata@latest write security <program-id> ./security.json{
"name": "MyProgram",
"project_url": "https://example.com",
"contacts": ["email:security@example.com", "discord:MyProgram#1234"],
"policy": "https://example.com/security-policy",
"source_code": "https://github.com/example/program",
"auditors": ["Audit Firm A", "Security Researcher B"],
"description": "Short description of what the program does",
"version": "0.1.0"
}write with that keypair. One per (program, seed) pair. This is what the explorer shows first.--non-canonical <your-pubkey>. Useful for frozen programs that no longer have an active upgrade authority, or for community-maintained IDLs. Looked up via the ?authority=<pubkey> query param on this site's API.Multisig (Squads) and buffered uploads are also supported — see the upstream README for the full command surface.
Programs that publish via anchor idl init / anchor idl upgrade still work — this site falls back to the Anchor IDL account when no PMP IDL is found. New programs should prefer PMP since it's the path the Solana Explorer and Codama tooling are aligning on.
Base URL: https://idl-one.vercel.app. All endpoints accept a cluster parameter: mainnet-beta (default) or devnet. Testnet is intentionally unsupported (PMP isn't deployed there).
/api/idlCurrent IDL for a program, resolved PMP-first with fndn fallback then Anchor. Returns 404 if no IDL exists.
curl "https://idl-one.vercel.app/api/idl?programId=BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya"{
"type": "pmp",
"content": "{\"version\":\"0.1.0\", ... }",
"address": "EwUbzv8sP8h8Q4...",
"authority": "fndnu15..."
}/api/latestPMP and Anchor side-by-side with version, slot, and timestamp. Each source returns at most one entry (the live revision). Either array can be empty if that source has no IDL.
curl "https://idl-one.vercel.app/api/latest?programId=BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya&cluster=mainnet-beta"/api/historyFull version history reconstructed from every PMP and Anchor transaction touching the program's metadata. One entry per distinct revision with slot/time ranges. Both GET and POST are supported — same inputs, same response shape.
300s (Vercel Pro max; Hobby caps to 60s). Programs with many upgrades may still hit the limit on hosted infra — the CLI against a private RPC is the reliable path. Response is sent with Cache-Control: no-store.# GET (preferred — shareable URL, auto-retried on transient errors)
curl "https://idl-one.vercel.app/api/history?programId=BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya&cluster=mainnet-beta"# POST (backward compatible)
curl -X POST "https://idl-one.vercel.app/api/history" \
-H 'Content-Type: application/json' \
-d '{ "programId": "BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya", "cluster": "mainnet-beta" }'/api/security-txtProgram security.txt — contacts, policy, auditors, and so on — resolved PMP-first (seed security) with ELF fallback (neodyme macro). Returns the parsed { programId, type: 'pmp' | 'elf', content, fields } shape that mirrors /api/idl. 404 if neither source has one. Powered by @solana/security-txt.
curl "https://idl-one.vercel.app/api/security-txt?programId=Memo4c2pN8afCj432Lb7RMVKi9PbQnnW7ewFFaV3oAH"{
"programId": "Memo4c2pN8afCj432Lb7RMVKi9PbQnnW7ewFFaV3oAH",
"type": "pmp",
"content": "{\"name\":\"SPL Memo\", ... }",
"fields": {
"name": "SPL Memo",
"project_url": "https://github.com/solana-program/memo",
"contacts": "link:...,email:security@anza.xyz",
"policy": "https://github.com/solana-program/memo/blob/main/SECURITY.md",
"description": "Solana Program Library Memo",
"version": "4.0.0"
}
}Optional ?source=pmp / ?source=elf forces one source (returns that source's full shape, with address and — for PMP — authority). ?source=both returns { pmp, elf } with null for whichever missed. ?authority=<pubkey> pins a non-canonical PMP authority.
200 — success400 — invalid programId or cluster404 — (/api/idl only) program has no IDL on either source422 — (/api/idl only) an IDL account is present but its bytes can't be decoded500 — server-side RPC failure or missing RPC_MAINNET / RPC_DEVNET env on the deploymentRun anywhere with npx, or install globally. Same three modes as the API.
# one-off
npx @solana/idl <program-id> --rpc <url>
# or install globally
npm install -g @solana/idl
idl <program-id> --rpc <url>Prints just the IDL body — pretty JSON if parsable, otherwise the raw string. Pipe to a file.
npx @solana/idl BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya \
--rpc https://api.mainnet-beta.solana.com > idl.jsonSame payload as GET /api/latest.
npx @solana/idl BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya \
--rpc https://api.mainnet-beta.solana.com --latestReplay every revision from on-chain transactions. Auto-detects whether the program has PMP, Anchor, or both.
npx @solana/idl BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya \
--rpc https://api.mainnet-beta.solana.com --historyAdd --dump-idls ./idls to write each distinct version as a JSON file. Full options: README → CLI options.
For Node services and tools, import the underlying functions directly. Dual ESM + CJS build, with @solana/kit as a peer dep.
pnpm add @solana/idl @solana/kitimport { createSolanaRpc, address } from '@solana/kit';
import { fetchIdl, fetchLatestIdls, fetchAllHistories } from '@solana/idl';
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const programId = address('BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya');
const current = await fetchIdl(rpc, programId);
const latest = await fetchLatestIdls(rpc, programId);
const history = await fetchAllHistories(rpc, programId);Full exports + types: README → Exports.