Programmatic 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 PMPfndn fallback PMP Anchor.

Full reference, exports, and architecture in the GitHub README.

Publish your own

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.

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.json

Upload a security.txt

Same 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"
}

Canonical vs. third-party uploads

  • Canonical — signed by the program's upgrade authority. Default when you run write with that keypair. One per (program, seed) pair. This is what the explorer shows first.
  • Third-party (non-canonical) — anyone can publish with --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.

Anchor IDLs (legacy)

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.

HTTP API

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).

GET/api/idl

Current 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..."
}

GET/api/latest

PMP 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"

GET/POST/api/history

Full 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.

Heavy endpoint. Function timeout is set to 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" }'

GET/api/security-txt

Program 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.

Status codes

  • 200 — success
  • 400 — invalid programId or cluster
  • 404 — (/api/idl only) program has no IDL on either source
  • 422 — (/api/idl only) an IDL account is present but its bytes can't be decoded
  • 500 — server-side RPC failure or missing RPC_MAINNET / RPC_DEVNET env on the deployment

CLI

Run anywhere with npx, or install globally. Same three modes as the API.

Install (optional)

# one-off
npx @solana/idl <program-id> --rpc <url>

# or install globally
npm install -g @solana/idl
idl <program-id> --rpc <url>

Bare IDL (default)

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.json

Side-by-side latest

Same payload as GET /api/latest.

npx @solana/idl BUYuxRfhCMWavaUWxhGtPP3ksKEDZxCD5gzknk3JfAya \
  --rpc https://api.mainnet-beta.solana.com --latest

Full history

Replay 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 --history

Add --dump-idls ./idls to write each distinct version as a JSON file. Full options: README → CLI options.

Library

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/kit
import { 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.