Asset Details Endpoints

Public reads: search and fetch assets in the v2 shape, icons and the append-only audit log. No authentication; CORS enabled.

NetworkBase URL
Liquidhttps://assets.blockstream.info/v2
Liquid Testnethttps://assets-testnet.blockstream.info/v2

Examples use the Liquid (mainnet) base URL. For testnet, swap in the testnet base URL.

Endpoints

MethodEndpointPath
GETSearch assets/v2/assets
GETGet an asset/v2/assets/:asset_id
GETGet all assets/v2/assets/all.json
GETGet the current icon/v2/assets/:asset_id/icon
GETGet an icon by hash/v2/assets/:asset_id/icon/:icon_hash.png
GETGet an asset's audit log/v2/assets/:asset_id/audit
GETSearch the global audit log/v2/audit
GETHealth check/health

Assets

Search assets

GET /v2/assets

Paginated list of active assets with filters and sorting. Each item is a full asset object.

Fields: items, page, page_size, total_count, total_pages.

Parameters

NameIn · typeDescription
If-Modified-Sinceheader · HTTP dateThe Last-Modified value from your previous response. Returns 304 with no body if no asset has changed since. Caching.
pagequery · integer1-based page. Default 1.
page_sizequery · integer1–500. Default 50.
sortquery · enum<field>_asc or <field>_desc, where field is asset_id, name, ticker, domain, created_at or updated_at. Default asset_id_asc.
asset_idquery · hexCase-insensitive asset ID prefix.
tickerquery · stringCase-insensitive ticker prefix.
namequery · stringCase-insensitive name prefix.
domainquery · stringCase-insensitive exact issuer domain.
asset_typequery · enumAMP_asset, stablecoin, security_token, other (set by registry admins)
category_tagquery · enum, repeatablestablecoin, bond, fixed-income, tokenized today. Several values match assets with any of them. Registry admins define this list and can add, change or remove values, so don't hard-code it.
trading_venuequery · enumsideswap or bitfinex
created_afterquery · RFC 3339Strictly after this time.
updated_afterquery · RFC 3339Strictly after this time. Use it for incremental sync.
🚧

Unknown query parameters are rejected with 400 (unknown query parameter), so don't add cache-busters or tracking parameters.

📘

ticker, name and asset_id are prefix matches: ticker=BMN returns BMN1 and BMN2. For an exact ticker, filter the results yourself.

👍

Keeping a local copy up to date? Follow Sync the registry: updated_after alone never reports removed assets.

Example request

curl "https://assets.blockstream.info/v2/assets?ticker=BMN&sort=ticker_asc&page=1&page_size=2"
// Node.js 18+ (ES module: save as .mjs or set "type": "module")
const BASE_URL = "https://assets.blockstream.info";

const res = await fetch(`${BASE_URL}/v2/assets?` + new URLSearchParams([["ticker","BMN"],["sort","ticker_asc"],["page","1"],["page_size","2"]]));
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(JSON.stringify(await res.json(), null, 2)); // full output: plain console.log cuts long strings and deep objects
# pip install requests
import requests

BASE_URL = "https://assets.blockstream.info"

res = requests.get(f"{BASE_URL}/v2/assets", params={"ticker": "BMN", "sort": "ticker_asc", "page": "1", "page_size": "2"}, timeout=30)
if not res.ok:
    raise RuntimeError(f"{res.status_code} {res.text}")
print(res.json())
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	baseURL := "https://assets.blockstream.info"
	q := url.Values{}
	q.Add("ticker", "BMN")
	q.Add("sort", "ticker_asc")
	q.Add("page", "1")
	q.Add("page_size", "2")
	endpoint := baseURL + "/v2/assets" + "?" + q.Encode()

	res, err := http.Get(endpoint)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("%d %s", res.StatusCode, body))
	}
	fmt.Println(string(body))
}
Response: 200 (production · application/json)
{
  "items": [
    {
      "asset_id": "11f91cb5edd5d0822997ad81f068ed35002daec33986da173461a8427ac857e1",
      "contract": {
        "entity": {
          "domain": "blockstream.com"
        },
        "name": "BMN Series 1",
        "precision": 2,
        "ticker": "BMN1",
        "version": 0,
        "issuer_pubkey": "02a1ff5fd5d6f17febe5cd2d6b9e45b6775a1e416b56fa8414e337e2589c2e9bd5"
      },
      "issuance_txin": {
        "txid": "6fbe5f8aedadf1fbfe023e97bb64d27a600c2c71fbf852d11059606e4a8f43c0",
        "vin": 0
      },
      "issuance_prevout": {
        "txid": "ed790fac247b5dfff4c0529d9b562d0f76757f7c08256b41fc2469b9a85bb3f9",
        "vout": 3
      },
      "initial_issuer_pubkey": "02a1ff5fd5d6f17febe5cd2d6b9e45b6775a1e416b56fa8414e337e2589c2e9bd5",
      "initial_issuer_pubkey_source": "registry_registration",
      "current_issuer_pubkey": "02a1ff5fd5d6f17febe5cd2d6b9e45b6775a1e416b56fa8414e337e2589c2e9bd5",
      "issuer_pubkey_history": [
        {
          "pubkey": "02a1ff5fd5d6f17febe5cd2d6b9e45b6775a1e416b56fa8414e337e2589c2e9bd5",
          "valid_from_audit_id": 587,
          "valid_until_audit_id": null
        }
      ],
      "mutable": {
        "trading_venues": [],
        "category_tags": [],
        "custom": {}
      },
      "admin": {
        "asset_type": null,
        "featured": false,
        "malicious": false,
        "delisted": false,
        "admin_notes": null,
        "last_admin_action": null
      },
      "icon": {
        "href": "/v2/assets/11f91cb5edd5d0822997ad81f068ed35002daec33986da173461a8427ac857e1/icon/e0f4c1f8eb9ab39bf0f835cbbb976a0a9ca42edf505df93118c59150ee979be9.png"
      },
      "status": "active",
      "created_at": "2026-07-16T15:08:46.919893Z",
      "updated_at": "2026-08-17T15:35:14.442979Z"
    },
    {
      "asset_id": "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034",
      "contract": {
        "entity": {
          "domain": "blockstream-mining2.stokr.io"
        },
        "name": "BMN Series 2",
        "precision": 4,
        "ticker": "BMN2",
        "version": 0,
        "issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b"
      },
      "issuance_txin": {
        "txid": "9bd4592c4238146e3b116f0b307100e38d58a26c62465e53c0ba7b8511ce7c88",
        "vin": 0
      },
      "issuance_prevout": {
        "txid": "b9317d00e44ab9f4ce435677b9b3f915e09d12b2be648da6bd12cd790d12658d",
        "vout": 3
      },
      "initial_issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
      "initial_issuer_pubkey_source": "registry_registration",
      "current_issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
      "issuer_pubkey_history": [
        {
          "pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
          "valid_from_audit_id": 13962,
          "valid_until_audit_id": null
        }
      ],
      "mutable": {
        "trading_venues": [],
        "category_tags": [],
        "custom": {}
      },
      "admin": {
        "asset_type": null,
        "featured": false,
        "malicious": false,
        "delisted": false,
        "admin_notes": null,
        "last_admin_action": {
          "action": "set_icon",
          "field": null,
          "admin_id": "8ecf873d-0463-440e-b6d2-e2c147958888",
          "timestamp": "2026-10-20T19:15:36.407298Z"
        }
      },
      "icon": {
        "href": "/v2/assets/aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034/icon/9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212.png"
      },
      "status": "active",
      "created_at": "2026-07-16T15:14:51.930732Z",
      "updated_at": "2026-10-20T19:15:36.438915Z"
    }
  ],
  "page": 1,
  "page_size": 2,
  "total_count": 2,
  "total_pages": 1
}
Error: unsupported sort: 422 (production · application/json)
{
  "detail": [
    {
      "type": "literal_error",
      "loc": [
        "query",
        "sort"
      ],
      "msg": "Input should be 'asset_id_asc', 'asset_id_desc', 'domain_asc', 'domain_desc', 'name_asc', 'name_desc', 'ticker_asc', 'ticker_desc', 'created_at_asc', 'created_at_desc', 'updated_at_asc' or 'updated_at_desc'",
      "input": "newest",
      "ctx": {
        "expected": "'asset_id_asc', 'asset_id_desc', 'domain_asc', 'domain_desc', 'name_asc', 'name_desc', 'ticker_asc', 'ticker_desc', 'created_at_asc', 'created_at_desc', 'updated_at_asc' or 'updated_at_desc'"
      }
    }
  ]
}
Error: unknown query parameter: 400 (production · application/json)
{
  "error": "validation_error",
  "message": "unknown query parameter",
  "details": {
    "parameters": [
      "limit"
    ]
  }
}

Get an asset

GET /v2/assets/:asset_id

One active asset, in the v2 shape: immutable contract, issuer keys, issuer-controlled metadata, admin annotations and icon. Works for assets registered through either API.

Returns an asset object.

Parameters

NameIn · typeDescription
asset_id requiredpath · hex (64)Liquid asset ID. Upper-case hex is accepted and normalized.
If-Modified-Sinceheader · HTTP dateThe Last-Modified value from your previous response. Returns 304 with no body if no asset has changed since. Caching.
🚧

Moderation doesn't hide assets. A delisted or malicious asset is still returned with status: "active". Check admin.delisted and admin.malicious before showing it to users.

Example request

curl "https://assets.blockstream.info/v2/assets/aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"
// Node.js 18+ (ES module: save as .mjs or set "type": "module")
const BASE_URL = "https://assets.blockstream.info";
const ASSET_ID = "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034";

const res = await fetch(`${BASE_URL}/v2/assets/${ASSET_ID}`);
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(JSON.stringify(await res.json(), null, 2)); // full output: plain console.log cuts long strings and deep objects
# pip install requests
import requests

BASE_URL = "https://assets.blockstream.info"
ASSET_ID = "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"

res = requests.get(f"{BASE_URL}/v2/assets/{ASSET_ID}", timeout=30)
if not res.ok:
    raise RuntimeError(f"{res.status_code} {res.text}")
print(res.json())
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	baseURL := "https://assets.blockstream.info"
	assetID := "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"
	endpoint := baseURL + "/v2/assets/" + assetID

	res, err := http.Get(endpoint)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("%d %s", res.StatusCode, body))
	}
	fmt.Println(string(body))
}
Response: 200 (production · application/json)
{
  "asset_id": "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034",
  "contract": {
    "entity": {
      "domain": "blockstream-mining2.stokr.io"
    },
    "name": "BMN Series 2",
    "precision": 4,
    "ticker": "BMN2",
    "version": 0,
    "issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b"
  },
  "issuance_txin": {
    "txid": "9bd4592c4238146e3b116f0b307100e38d58a26c62465e53c0ba7b8511ce7c88",
    "vin": 0
  },
  "issuance_prevout": {
    "txid": "b9317d00e44ab9f4ce435677b9b3f915e09d12b2be648da6bd12cd790d12658d",
    "vout": 3
  },
  "initial_issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
  "initial_issuer_pubkey_source": "registry_registration",
  "current_issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
  "issuer_pubkey_history": [
    {
      "pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
      "valid_from_audit_id": 13962,
      "valid_until_audit_id": null
    }
  ],
  "mutable": {
    "trading_venues": [],
    "category_tags": [],
    "custom": {}
  },
  "admin": {
    "asset_type": null,
    "featured": false,
    "malicious": false,
    "delisted": false,
    "admin_notes": null,
    "last_admin_action": {
      "action": "set_icon",
      "field": null,
      "admin_id": "8ecf873d-0463-440e-b6d2-e2c147958888",
      "timestamp": "2026-10-20T19:15:36.407298Z"
    }
  },
  "icon": {
    "href": "/v2/assets/aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034/icon/9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212.png"
  },
  "status": "active",
  "created_at": "2026-07-16T15:14:51.930732Z",
  "updated_at": "2026-10-20T19:15:36.438915Z"
}
Error: unknown or deregistered asset: 404 (production · application/json)
{
  "error": "asset_not_found",
  "message": "asset not found",
  "details": {
    "asset_id": "0000000000000000000000000000000000000000000000000000000000000000"
  }
}

Get all assets

GET /v2/assets/all.json

Every active asset in one JSON object keyed by asset ID (v2 shape). Over 20 MB on mainnet; Accept-Encoding: gzip cuts it about tenfold.

Parameters

NameIn · typeDescription
If-Modified-Sinceheader · HTTP dateThe Last-Modified value from your previous response. Returns 304 with no body if no asset has changed since. Caching.
👍

Use it once to bootstrap a local copy, then sync incrementally.

📘

Sent with Cache-Control: no-cache and a registry-wide Last-Modified. Send that value back in If-Modified-Since to get a bodyless 304 when nothing changed. See Caching.

Example request

curl "https://assets.blockstream.info/v2/assets/all.json"
// Node.js 18+ (ES module: save as .mjs or set "type": "module")
const BASE_URL = "https://assets.blockstream.info";

const res = await fetch(`${BASE_URL}/v2/assets/all.json`);
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(JSON.stringify(await res.json(), null, 2)); // full output: plain console.log cuts long strings and deep objects
# pip install requests
import requests

BASE_URL = "https://assets.blockstream.info"

res = requests.get(f"{BASE_URL}/v2/assets/all.json", timeout=30)
if not res.ok:
    raise RuntimeError(f"{res.status_code} {res.text}")
print(res.json())
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	baseURL := "https://assets.blockstream.info"
	endpoint := baseURL + "/v2/assets/all.json"

	res, err := http.Get(endpoint)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("%d %s", res.StatusCode, body))
	}
	fmt.Println(string(body))
}
Response: 200 (production · application/json · 14,230 entries, first shown)
{
  "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034": {
    "asset_id": "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034",
    "contract": {
      "entity": {
        "domain": "blockstream-mining2.stokr.io"
      },
      "name": "BMN Series 2",
      "precision": 4,
      "ticker": "BMN2",
      "version": 0,
      "issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b"
    },
    "initial_issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
    "initial_issuer_pubkey_source": "registry_registration",
    "current_issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
    "issuer_pubkey_history": [
      {
        "pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
        "valid_from_audit_id": 13962,
        "valid_until_audit_id": null
      }
    ],
    "mutable": {
      "trading_venues": [],
      "category_tags": [],
      "custom": {}
    },
    "admin": {
      "asset_type": null,
      "featured": false,
      "malicious": false,
      "delisted": false,
      "admin_notes": null,
      "last_admin_action": {
        "action": "set_icon",
        "field": null,
        "admin_id": "8ecf873d-0463-440e-b6d2-e2c147958888",
        "timestamp": "2026-10-20T19:15:36.407298Z"
      }
    },
    "icon": {
      "href": "/v2/assets/aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034/icon/9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212.png"
    },
    "status": "active",
    "created_at": "2026-07-16T15:14:51.930732Z",
    "updated_at": "2026-10-20T19:15:36.438915Z",
    "issuance_txin": {
      "txid": "9bd4592c4238146e3b116f0b307100e38d58a26c62465e53c0ba7b8511ce7c88",
      "vin": 0
    },
    "issuance_prevout": {
      "txid": "b9317d00e44ab9f4ce435677b9b3f915e09d12b2be648da6bd12cd790d12658d",
      "vout": 3
    }
  }
}

Icons

Get the current icon

GET /v2/assets/:asset_id/icon

Redirects (307, Cache-Control: no-cache) to the asset's current content-addressed icon. Use it when you want one stable URL per asset.

Parameters

NameIn · typeDescription
asset_id requiredpath · hex (64)Liquid asset ID. Upper-case hex is accepted and normalized.

Example request

curl -i "https://assets.blockstream.info/v2/assets/aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034/icon"   # 307 with a Location header; add -L to follow it
// Node.js 18+ (ES module: save as .mjs or set "type": "module")
const BASE_URL = "https://assets.blockstream.info";
const ASSET_ID = "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034";

const res = await fetch(`${BASE_URL}/v2/assets/${ASSET_ID}/icon`, { redirect: "manual" });
console.log(res.status, res.headers.get("location"));
# pip install requests
import requests

BASE_URL = "https://assets.blockstream.info"
ASSET_ID = "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"

res = requests.get(f"{BASE_URL}/v2/assets/{ASSET_ID}/icon", allow_redirects=False, timeout=30)
print(res.status_code, res.headers["Location"])
package main

import (
	"fmt"
	"net/http"
)

func main() {
	baseURL := "https://assets.blockstream.info"
	assetID := "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"
	endpoint := baseURL + "/v2/assets/" + assetID + "/icon"

	client := &http.Client{CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
	res, err := client.Get(endpoint)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	fmt.Println(res.StatusCode, res.Header.Get("Location"))
}
Response: 307 (production)
Location: /v2/assets/aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034/icon/9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212.png
Error: no approved icon: 404 (production · application/json)
{
  "error": "icon_not_found",
  "message": "published icon not found",
  "details": {
    "asset_id": "a6027bba1721182eb6c422b028ec805ad113ffcd1288b680d7a5882d0736a002"
  }
}

Get an icon by hash

GET /v2/assets/:asset_id/icon/:icon_hash.png

The PNG bytes of a published icon. The URL contains the SHA-256 of the bytes, so the response never changes: cache it forever. This is the URL in an asset's icon.href.

Parameters

NameIn · typeDescription
asset_id requiredpath · hex (64)Liquid asset ID. Upper-case hex is accepted and normalized.
icon_hash requiredpath · hex (64)SHA-256 of the PNG bytes.
📘

Headers: Cache-Control: public, max-age=31536000, immutable, ETag: "<icon_hash>" (quoted), X-Content-Type-Options: nosniff. Send the ETag back in If-None-Match to get a 304; see Caching.

📘

New icons are exactly 500×500, but icons imported from the legacy registry can have other sizes (e.g. 537×537). Scale them to your layout.

Example request

curl -o icon.png "https://assets.blockstream.info/v2/assets/aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034/icon/9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212.png"
// Node.js 18+ (ES module: save as .mjs or set "type": "module")
const BASE_URL = "https://assets.blockstream.info";
const ASSET_ID = "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034";
const ICON_HASH = "9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212";

const res = await fetch(`${BASE_URL}/v2/assets/${ASSET_ID}/icon/${ICON_HASH}.png`);
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
await (await import("node:fs/promises")).writeFile("icon.png", Buffer.from(await res.arrayBuffer()));
console.log("saved icon.png, ETag", res.headers.get("etag"));
# pip install requests
import requests

BASE_URL = "https://assets.blockstream.info"
ASSET_ID = "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"
ICON_HASH = "9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212"

res = requests.get(f"{BASE_URL}/v2/assets/{ASSET_ID}/icon/{ICON_HASH}.png", timeout=30)
if not res.ok:
    raise RuntimeError(f"{res.status_code} {res.text}")
with open("icon.png", "wb") as f:
    f.write(res.content)
print("saved icon.png, ETag", res.headers["ETag"])
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	baseURL := "https://assets.blockstream.info"
	assetID := "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"
	iconHash := "9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212"
	endpoint := baseURL + "/v2/assets/" + assetID + "/icon/" + iconHash + ".png"

	res, err := http.Get(endpoint)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("%d %s", res.StatusCode, body))
	}
	if err := os.WriteFile("icon.png", body, 0o644); err != nil {
		panic(err)
	}
	fmt.Println("saved icon.png, ETag", res.Header.Get("ETag"))
}
Response: 200 (production · image/png)
<10836 bytes of PNG>
Conditional request (If-None-Match): 304 (production)
(no body)

Audit

Get an asset's audit log

GET /v2/assets/:asset_id/audit

Append-only history of every accepted change to one asset, oldest first by default. Assets imported from the legacy registry start with a legacy_register entry. See audit entry and verifying the trail.

Fields: items, next_since_audit_id (see Audit entry).

Parameters

NameIn · typeDescription
asset_id requiredpath · hex (64)Liquid asset ID. Upper-case hex is accepted and normalized.
since_audit_idquery · integerExclusive cursor. Default 0.
limitquery · integer1–1000. Default 100.
orderquery · asc | descDefault asc.
👍

To read everything, page with order=asc and pass next_since_audit_id back as since_audit_id. Use order=desc&limit=N only for "latest N": the cursor moves forward, not backward.

Example request

curl "https://assets.blockstream.info/v2/assets/aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034/audit?limit=10&order=asc"
// Node.js 18+ (ES module: save as .mjs or set "type": "module")
const BASE_URL = "https://assets.blockstream.info";
const ASSET_ID = "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034";

const res = await fetch(`${BASE_URL}/v2/assets/${ASSET_ID}/audit?` + new URLSearchParams([["limit","10"],["order","asc"]]));
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(JSON.stringify(await res.json(), null, 2)); // full output: plain console.log cuts long strings and deep objects
# pip install requests
import requests

BASE_URL = "https://assets.blockstream.info"
ASSET_ID = "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"

res = requests.get(f"{BASE_URL}/v2/assets/{ASSET_ID}/audit", params={"limit": "10", "order": "asc"}, timeout=30)
if not res.ok:
    raise RuntimeError(f"{res.status_code} {res.text}")
print(res.json())
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	baseURL := "https://assets.blockstream.info"
	assetID := "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034"
	q := url.Values{}
	q.Add("limit", "10")
	q.Add("order", "asc")
	endpoint := baseURL + "/v2/assets/" + assetID + "/audit" + "?" + q.Encode()

	res, err := http.Get(endpoint)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("%d %s", res.StatusCode, body))
	}
	fmt.Println(string(body))
}
Response (legacy asset: one imported entry): 200 (production · application/json)
{
  "items": [
    {
      "audit_id": 13962,
      "server_received_at": "2026-07-16T15:14:51.930732Z",
      "actor": "system",
      "verified_pubkey": null,
      "admin_id": null,
      "action": {
        "request": {
          "name": "BMN Series 2",
          "entity": {
            "domain": "blockstream-mining2.stokr.io"
          },
          "ticker": "BMN2",
          "version": 0,
          "asset_id": "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034",
          "contract": {
            "name": "BMN Series 2",
            "entity": {
              "domain": "blockstream-mining2.stokr.io"
            },
            "ticker": "BMN2",
            "version": 0,
            "precision": 4,
            "issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b"
          },
          "precision": 4,
          "collection": null,
          "issuance_txin": {
            "vin": 0,
            "txid": "9bd4592c4238146e3b116f0b307100e38d58a26c62465e53c0ba7b8511ce7c88"
          },
          "issuer_pubkey": "0206eb0dd95be6ace6d83e5e865815d73bed9e553a1a829fe8c2de74189ee2289b",
          "issuance_prevout": {
            "txid": "b9317d00e44ab9f4ce435677b9b3f915e09d12b2be648da6bd12cd790d12658d",
            "vout": 3
          }
        },
        "contract_hash": "998614e8941c5cc4fd674e1d9b29e53468ced64290ec5742273659ef103cc461"
      },
      "action_hash": null,
      "signature": null
    },
    {
      "audit_id": 16007,
      "server_received_at": "2026-08-17T15:35:14.442979Z",
      "actor": "system",
      "verified_pubkey": null,
      "admin_id": null,
      "action": {
        "source": "legacy_icons_json",
        "asset_id": "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034",
        "icon_hash": "a6fa6352bfd700a23aea18ab5494cf08de30a063e2deb18b02163e905b6537a0",
        "operation": "import_legacy_icon"
      },
      "action_hash": null,
      "signature": null
    },
    {
      "audit_id": 17823,
      "server_received_at": "2026-10-20T19:15:36.407298Z",
      "actor": "admin",
      "verified_pubkey": "02fa74607f51aba28596cceb95e7c6c6e4ff44a0b0cf76f3045df80e34f04c5eb8",
      "admin_id": "8ecf873d-0463-440e-b6d2-e2c147958888",
      "action": {
        "nonce": "f212bbde3d80ae4a9b295b5b055b7d8a",
        "asset_id": "aa909f1b77451e409fe95fe1d3638ad017ab3325c6d4f00301af6d582d0f2034",
        "icon_hash": "9389e4e5458f76347a0f5bcd8f963f6aa3e14c1b6b923d5304c91f63614a5212",
        "operation": "set_icon",
        "timestamp": "2026-10-20T19:15:36Z",
        "actor_pubkey": "02fa74607f51aba28596cceb95e7c6c6e4ff44a0b0cf76f3045df80e34f04c5eb8",
        "signing_context": "liquid-asset-registry-admin-action-v1"
      },
      "action_hash": null,
      "signature": "uQb6mz9Cg6s7STaloLHjd7h0DFZXOewpD7k3dEtj/E3Heul5DGJ1Jmt2hcnbEV9G1gtkd5HUdh6vqGxhtVJPCg=="
    }
  ],
  "next_since_audit_id": 17823
}
A v2 asset with issuer and admin actions: 200 (local instance · application/json · showing 3 of 12 items)
{
  "items": [
    {
      "audit_id": 1,
      "server_received_at": "2026-11-03T22:47:34.213879Z",
      "actor": "system",
      "verified_pubkey": null,
      "admin_id": null,
      "action": {
        "mutable": {
          "custom": {
            "website": "https://example-issuer.com"
          },
          "category_tags": [
            "stablecoin"
          ],
          "trading_venues": [
            {
              "url": "https://sideswap.io/",
              "venue": "sideswap"
            }
          ]
        },
        "asset_id": "5ac9a0f9d1b54e2c8e7f3a6b2d4c8e1f0a9b7c5d3e1f2a4b6c8d0e2f4a6b8c0d",
        "contract": {
          "name": "Example Dollar",
          "entity": {
            "domain": "example-issuer.com"
          },
          "ticker": "EXUSD",
          "version": 2,
          "precision": 8,
          "initial_issuer_pubkey": "03566ecb682f1a49ccad62a6dbc5b4045d96d65912bbbb177b7121c27c01d91e6e"
        },
        "operation": "register",
        "contract_hash": "d0d6126a9574aaf930fead73d0859da1c807cc0756ae6ca77392fd14418c6f9e",
        "initial_issuer_pubkey": "03566ecb682f1a49ccad62a6dbc5b4045d96d65912bbbb177b7121c27c01d91e6e",
        "domain_verification_method": "dns",
        "initial_issuer_pubkey_source": "contract"
      },
      "action_hash": "3c19a3bef43921f4ce0dfa865da2c08f153e9285fcef31db4f54b97455f89547",
      "signature": null
    },
    {
      "audit_id": 3,
      "server_received_at": "2026-11-03T22:47:34.326597Z",
      "actor": "issuer",
      "verified_pubkey": "03566ecb682f1a49ccad62a6dbc5b4045d96d65912bbbb177b7121c27c01d91e6e",
      "admin_id": null,
      "action": {
        "nonce": "391bad7c-f582-436e-a026-29eea333bff9",
        "asset_id": "5ac9a0f9d1b54e2c8e7f3a6b2d4c8e1f0a9b7c5d3e1f2a4b6c8d0e2f4a6b8c0d",
        "operation": "replace_category_tags",
        "timestamp": "2026-11-03T22:47:34.323000Z",
        "category_tags": [
          "stablecoin",
          "tokenized"
        ],
        "signing_context": "liquid-asset-registry-action-v1",
        "prev_action_hash": "3c19a3bef43921f4ce0dfa865da2c08f153e9285fcef31db4f54b97455f89547",
        "mutable_schema_version": 1
      },
      "action_hash": "84a664d89014aedb77fab1f145dcc60d98d2f1632d31e8c0bdbe46be9c1a4d7f",
      "signature": "Fa1R9CBMVbDLBcltLo1IRkF87XT4pUDgE68SzhcJ6XJoJzv4zyt0yE2Ka+PYXFR83Ab6bX6Frv9aEMDeXDjksg=="
    },
    {
      "audit_id": 4,
      "server_received_at": "2026-11-03T22:47:34.360514Z",
      "actor": "issuer",
      "verified_pubkey": "03566ecb682f1a49ccad62a6dbc5b4045d96d65912bbbb177b7121c27c01d91e6e",
      "admin_id": null,
      "action": {
        "nonce": "533ba854-99fa-445f-8db6-bd32a0850839",
        "asset_id": "5ac9a0f9d1b54e2c8e7f3a6b2d4c8e1f0a9b7c5d3e1f2a4b6c8d0e2f4a6b8c0d",
        "operation": "replace_trading_venues",
        "timestamp": "2026-11-03T22:47:34.359000Z",
        "trading_venues": [
          {
            "url": "https://sideswap.io/",
            "venue": "sideswap"
          },
          {
            "url": "https://trading.bitfinex.com/t/EXUSD:USD",
            "venue": "bitfinex"
          }
        ],
        "signing_context": "liquid-asset-registry-action-v1",
        "prev_action_hash": "84a664d89014aedb77fab1f145dcc60d98d2f1632d31e8c0bdbe46be9c1a4d7f",
        "mutable_schema_version": 1
      },
      "action_hash": "e0f86da7419b1594bdfdae4bb264468e423d063ed59b47a39ec35536c3984c5b",
      "signature": "O453jjZDsHqq0U+qYLYgpVRItgZzqYQ2b75pSWMAL0xGhKPQSfP+lnYzPVlMGaF1bQd/sib85TfZh6+dcEGY+Q=="
    }
  ],
  "next_since_audit_id": 22
}

Search the global audit log

GET /v2/audit

All assets' actions and admin lifecycle actions in one stream, ordered by the global audit_id.

Fields: items, next_since_audit_id (see Audit entry).

Parameters

NameIn · typeDescription
asset_idquery · hex (64)Only this asset.
operationquery · stringe.g. legacy_register, replace_custom, add_admin.
actorquery · enumissuer, admin or system.
from_server_received_atquery · RFC 3339Inclusive lower bound.
to_server_received_atquery · RFC 3339Upper bound.
since_audit_idquery · integerExclusive cursor. Default 0.
limitquery · integer1–1000. Default 100.
orderquery · asc | descDefault asc.

Example request

curl "https://assets.blockstream.info/v2/audit?limit=2&order=desc"
// Node.js 18+ (ES module: save as .mjs or set "type": "module")
const BASE_URL = "https://assets.blockstream.info";

const res = await fetch(`${BASE_URL}/v2/audit?` + new URLSearchParams([["limit","2"],["order","desc"]]));
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(JSON.stringify(await res.json(), null, 2)); // full output: plain console.log cuts long strings and deep objects
# pip install requests
import requests

BASE_URL = "https://assets.blockstream.info"

res = requests.get(f"{BASE_URL}/v2/audit", params={"limit": "2", "order": "desc"}, timeout=30)
if not res.ok:
    raise RuntimeError(f"{res.status_code} {res.text}")
print(res.json())
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	baseURL := "https://assets.blockstream.info"
	q := url.Values{}
	q.Add("limit", "2")
	q.Add("order", "desc")
	endpoint := baseURL + "/v2/audit" + "?" + q.Encode()

	res, err := http.Get(endpoint)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("%d %s", res.StatusCode, body))
	}
	fmt.Println(string(body))
}
Response (latest 2 entries): 200 (production · application/json)
{
  "items": [
    {
      "audit_id": 18230,
      "server_received_at": "2026-11-03T16:54:07.182798Z",
      "actor": "admin",
      "verified_pubkey": "02e3e9ed5dcf5e468e66dacee5722df414237c2905ad488b2a535fd6a0a8412c7a",
      "admin_id": "23c12594-9fbe-4084-a631-85453e254d0f",
      "action": {
        "nonce": "a2ba13f9-a5fd-4045-97b6-9b4ca8a7b1b4",
        "operation": "add_admin",
        "timestamp": "2026-11-03T16:54:06.889Z",
        "permissions": [
          "migrate_assets",
          "review_icons",
          "manage_icons",
          "annotate_assets",
          "delist_assets"
        ],
        "actor_pubkey": "02e3e9ed5dcf5e468e66dacee5722df414237c2905ad488b2a535fd6a0a8412c7a",
        "admin_pubkey": "029be720939041f800d368d9a62c2a20c6016dc2c9cabb37d30c0835e3c0d2ea67",
        "friendly_name": "raspitor",
        "signing_context": "liquid-asset-registry-admin-action-v1"
      },
      "action_hash": null,
      "signature": "7wVPGrMNPKSRDcXnrwZPIlDIAEOhavftjtD6A/KT8ZwZ7W19oBPQaSXYLgZ33Ujmlt1lyVLyUtJnuDYBBYsXhw=="
    },
    {
      "audit_id": 18229,
      "server_received_at": "2026-11-03T16:52:40.519469Z",
      "actor": "admin",
      "verified_pubkey": "02e3e9ed5dcf5e468e66dacee5722df414237c2905ad488b2a535fd6a0a8412c7a",
      "admin_id": "23c12594-9fbe-4084-a631-85453e254d0f",
      "action": {
        "nonce": "725945f6-0fe0-434a-9e96-6aaa7d3efe00",
        "operation": "remove_admin",
        "timestamp": "2026-11-03T16:52:40.147Z",
        "actor_pubkey": "02e3e9ed5dcf5e468e66dacee5722df414237c2905ad488b2a535fd6a0a8412c7a",
        "admin_pubkey": "02fa74607f51aba28596cceb95e7c6c6e4ff44a0b0cf76f3045df80e34f04c5eb8",
        "signing_context": "liquid-asset-registry-admin-action-v1"
      },
      "action_hash": null,
      "signature": "gZNTzt+T7aBOdUVVhlbPeSW3//gFnyBjpTpbOs1JK5JIKfBVtDZBneTH8uhP5GHQMrvk8LR05A8MNdmtETcF+Q=="
    }
  ],
  "next_since_audit_id": 18230
}

Service

Health check

GET /health

Process health. Returns 200 with the deployment environment.

Example request

curl "https://assets.blockstream.info/health"
// Node.js 18+ (ES module: save as .mjs or set "type": "module")
const BASE_URL = "https://assets.blockstream.info";

const res = await fetch(`${BASE_URL}/health`);
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(JSON.stringify(await res.json(), null, 2)); // full output: plain console.log cuts long strings and deep objects
# pip install requests
import requests

BASE_URL = "https://assets.blockstream.info"

res = requests.get(f"{BASE_URL}/health", timeout=30)
if not res.ok:
    raise RuntimeError(f"{res.status_code} {res.text}")
print(res.json())
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	baseURL := "https://assets.blockstream.info"
	endpoint := baseURL + "/health"

	res, err := http.Get(endpoint)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	if res.StatusCode != http.StatusOK {
		panic(fmt.Sprintf("%d %s", res.StatusCode, body))
	}
	fmt.Println(string(body))
}
Response: 200 (production · application/json)
{
  "status": "ok",
  "environment": "production"
}

The Liquid Network is a production Bitcoin sidechain built with Elements, supporting confidential transactions, asset issuance and programmable smart contracts.

© 2026 Liquid Network
All rights reserved.

Feedback and Requests

We'd be happy to hear your suggestions on how to improve this site.

Simplicity Forum

Discuss SimplicityHL, tooling and applications on Liquid at community.simplicity-lang.org.

Liquid Dev Community

Community Telegram group where most of the Liquid developers hang out. Go to t.me/liquid_devel to join.