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.

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

Status codes

  • 200 — success
  • 400 — invalid programId or cluster
  • 404 — (/api/idl only) program has no IDL on either source
  • 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.