Documentation

Build on the Lineage HTTP API

Read chain state, submit transactions, and query node metadata directly over HTTP. No smart contracts required. Move through node concepts, the mempool, storage, and miner reference, and the SDK tutorials using the contents tree.

Contents

Documentation / Overview

Lineage HTTP API

NoteThis documentation describes what is currently in place on the network. It will be updated as roadmap items ship, so some behaviour will change as those land.

The Lineage HTTP API lets you integrate with the network directly: read chain state, submit transactions, and query node metadata. None of the flows in this documentation require on-chain smart contracts. Use a plain HTTP client (curl, fetch, or your language of choice) against the endpoints listed under each subsystem.

Routes are grouped by node class. Each class is served from its own origin, so confirm which host a route belongs to before you call it, as sending a storage read to the mempool host (or vice versa) will not resolve.

Public service URLs

These are the public testnet hosts used in every example below. They point to the live testnet; a mainnet will be announced separately.

Node classBase URL (testnet)Use for
Mempoolhttps://mempool.lineage.toTransactions, balances, supply, mempool metadata
Storagehttps://storage.lineage.toBlocks, chain entries, read-oriented history
Minerhttps://miner.lineage.toWallet, payments, and current mining block (coupled user node)

Requests & responses

The API is REST over HTTPS under /v1. Resources use standard verbs —GET to read, POST to create or submit — with JSON request and response bodies. Routes that require authorization take an x-api-key header; read-only routes are public.

Errors use application/problem+json (RFC 7807): an HTTP status with title and detail fields and a request_id for correlation.

json
{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404,
  "detail": "No block at that height",
  "request_id": "5eDtVyHFTE-6Fn2-21mRUA"
}

API quick start

Point your HTTP client at a node's base URL and verify connectivity with a read-only /v1 route before sending anything that writes. A good first call is the chain head on the storage host.

shell
# check the chain head
curl -sS "https://storage.lineage.to/v1/blocks/latest"
NoteBrowse every operation, with its request and response shapes, in the API reference. The SDKs below wrap the same API and handle transaction signing for you.

Data model

Lineage is a UTXO ledger, in the Bitcoin lineage rather than an account/EVM model. There is no stored account balance anywhere in the protocol; a balance is a view computed over the set of transaction outputs an address has not yet spent. Every payment consumes one or more existing outputs and creates new ones for the next spend to reference (see Transactions).

Every value a transaction moves is an Asset, and an asset is one of exactly two kinds:

  • Token(amount) — a plain integer quantity of the native token.
  • Item { amount, genesis_hash, metadata }— a fungible-by-type asset class. genesis_hash is the id stamped when the item is first created (its minting transaction); metadata is an optional string, capped at 800 bytes.

The native token's brand name is LNGX— that's a network/brand identifier, not something the node code itself knows about; on the wire and in node source, it is only ever the integer Token amount. Display values divide that raw integer by a fixed base-unit divisor of 72,072,000, and the protocol currently enforces a hard supply cap of 72,072,000 × 5,000,000,000 raw units — 5,000,000,000 LNGX at that divisor. This fixed cap reflects the model in place today; the network is moving to a managed supply that adjusts issuance to target price stability — see Peer-to-peer electronic cash revisited. See tokenomics for the economics and issuance schedule; this page only covers how the value is represented on-chain.

A read of an address's holdings reflects this directly: a token total, a map of item totals by genesis_hash, and the underlying outpoints backing them.

json
{
  "balance": {
    "total": {
      "tokens": 100,
      "items": { "g3b8f2a1…": 50 }
    },
    "address_list": {
      "d0e7c9b4…": [
        {
          "out_point": { "t_hash": "g3b8f2a1…", "n": 0 },
          "value": { "Token": 100 }
        }
      ]
    }
  }
}

Note the asset value here uses the wire form (capitalised keys like { "Token": 100 }), which differs from the REST ApiAsset response shape ({ "kind": "token", "amount": 100 }) used elsewhere in the API — see the API reference for exact response schemas.

Keys, addresses & wallets

Lineage keypairs are ed25519. An address is derived from a public key as hex(sha3_256(public_key))— a 64-character hex string. Two legacy address schemes also exist in the node code for backward compatibility (a 32-character variant and an older temporary scheme); new wallets use the 64-character form.

Wallets generate a mnemonic seed phrase and derive keypairs from it through hierarchical (HD) derivation — the reference SDKs hold keys locally, encrypted at rest with a passphrase you supply, and never send private keys to a node.

What you actually sign is narrower than the whole transaction. For each input, the signable message is the SHA3-256 hash of the JSON encoding of every output in the transaction, concatenated with the JSON encoding of that input's previous outpoint — hex-encoded. That is outputs plus the input's previous outpoint, and nothing else: the signature excludes fees, druid_info, and the input's own unlocking script (which is reset before the hash is computed). Two consequences follow directly: you sign exactly what you submit, and field order is load-bearing, since the JSON encoding is taken verbatim, in each struct's declared field order.

javascript
import { Wallet } from '@lineage-foundation/sdk-js';

const wallet = new Wallet();
await wallet.initNew({
  mempoolHost: 'https://mempool.lineage.to',
  passphrase: 'a secure passphrase',
});

// Derive a keypair; the address is hex(sha3_256(public_key)).
const keypair = wallet.getNewKeypair([]).content.newKeypairResponse;
console.log(keypair.address);

See Transactions for where these keys sign, and Scripts for how a spend is checked against an address at the protocol level.

Transactions

A transaction is { inputs, outputs, version, fees, druid_info }, in that declared field order — the order matters, because a transaction's id is the SHA3-256 hash of its bincode serialization (hex-encoded, prefixed with g, truncated to 32 characters), and serialization is order-sensitive.

Each input (TxIn) carries an optional previous_out (an OutPoint: the previous transaction hash and output index) plus a script_signature that proves the right to spend it. An input with previous_out: null is a create/coinbase input — it mints rather than spends. Each output (TxOut) states the value (an Asset), a locktime, and an optional script_public_key that locks it.

version is a plain integer the client stamps with the network version it is built against; the node does not branch protocol behaviour on it. In particular, a two-way (atomic swap) payment is not signalled by a particular version number — it is signalled by the presence of druid_info on the transaction. fees is a real list of outputs that inputs must fund alongside the visible outputs (inputs must balance against outputs plus fees); there is currently no fixed fee-rate or minimum-fee policy enforced by the node, so treat fees as a mechanism that exists in the format without an economic policy wired to it yet.

A submission to POST /v1/transactions looks like this (the asset value uses the wire form, { "Token": n }, not the REST ApiAsset shape used in read responses):

json
{
  "transactions": [
    {
      "inputs": [
        {
          "previous_out": { "t_hash": "g3b8f2a1…", "n": 0 },
          "script_signature": {
            "Pay2PkH": {
              "signable_data": "a1c4…",
              "signature": "6f2e…",
              "public_key": "5b8a…",
              "address_version": null
            }
          }
        }
      ],
      "outputs": [
        { "value": { "Token": 10 }, "locktime": 0, "script_public_key": "d0e7…" },
        { "value": { "Token": 90 }, "locktime": 0, "script_public_key": "a1b2…change" }
      ],
      "version": 6,
      "druid_info": null,
      "fees": null
    }
  ]
}

The SDKs build and sign this for you; a one-way token payment is a single call:

javascript
// keypair: your own keypair, already funded
const receipt = await wallet.makeTokenPayment(
  'recipient-address',
  10,
  [keypair],   // keypairs available to cover the inputs
  keypair,     // where change is returned
);
console.log(receipt.content.makePaymentResponse.transactionHash);

See Keys, addresses & wallets for exactly what gets signed, and the API reference for the full request and response schemas.

Scripts

Spend authorisation is checked by a small stack-based script language, in the Bitcoin Script tradition: bounded and loop-free (no back-jumps), so every script terminates and its worst-case cost is easy to bound. A dedicated condition stack handles IF/ELSE branching without introducing loops. Hard limits keep scripts cheap to validate: a stack item is capped at 520 bytes, a script at 201 opcodes and 10,000 bytes total, the execution stack at 1,000 items, and a multisig script at 20 public keys.

Opcodes fall into a few families:

  • Constants — push small literal values (OP_0OP_16).
  • Flow controlOP_IF, OP_NOTIF, OP_ELSE, OP_ENDIF, OP_VERIFY, OP_BURN.
  • Stack, splice, bitwise & arithmetic — duplicate, drop, compare, and combine stack items.
  • CryptoOP_SHA3, the OP_HASH256 family, OP_CHECKSIG / OP_CHECKSIGVERIFY, OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY.
  • Smart dataOP_CREATE, which mints a new item asset.

The standard lock is P2PKH (pay-to-pubkey-hash). The unlocking side pushes check data, a signature, and a public key; the locking side then runs OP_DUP, hashes the pushed public key, compares it against the address baked into the output (OP_EQUALVERIFY), and finally checks the signature against the public key (OP_CHECKSIG):

text
<check_data> <signature> <public_key>
OP_DUP OP_HASH256 <address> OP_EQUALVERIFY OP_CHECKSIG

A spend is valid only if that combined script runs to a truthy result — so the signature has to verify against the pushed public key, and that public key has to hash to the address the output was locked to. See Keys, addresses & wallets for what the signature actually covers. Multisig locks and pay-to-script-hash (P2SH) addresses are also supported for flows where more than one signer must authorise a spend, such as two-way payments.

Node types

Lineage runs five node roles, each its own binary. Four serve the /v1 HTTP API described in the API reference; the fifth, pre_launch, is a one-shot helper that sends its startup requests and exits — it has no HTTP API of its own. See Technology → Subsystems for how the roles fit together at the network level.

RoleJobServes /v1?
MempoolValidates and pools transactions, drives the block round, coordinates miners and storageYes
StoragePersists the chain, serves blocks and history to clientsYes
MinerRuns proof-of-work for the mempool it is paired withYes
UserWallet client — holds keys, builds and sends payments, reads UTXOsYes
Pre-launchOne-shot bootstrap/upgrade helper; sends startup requests, then exitsNo

Mempool node

Mempool nodes accept transactions and replicate them through the mempool's own RAFT group, so every node in the group agrees on the same transaction pool, timestamp, and pipeline state before acting on it. Once a round starts, the group runs the mining round together (see Consensus & the block round), assembles the winning block once a miner's proof is chosen, and sends the assembled block on to storage. Because the replicated state must be deterministic — same inputs, same order, same result — every mempool node independently reaches the same outcome without needing to trust a single leader.

Storage node

Storage nodes receive a block from the mempool path and check its proof-of-work along with transaction and merkle-root consistency. Storage does not currently re-verify the UNiCORN randomness that selected the round's participants and winner — that check happens on the mempool side; storage's job is to confirm the block it received is internally valid, not to re-run mempool's selection logic.

Blocks arrive in parts and are replicated through storage's own RAFT group before being reassembled into a complete block, persisted, and indexed for header, transaction-id, and proof lookups. Once a block is stored, storage notifies the mempool so it can seed the next round.

Miner node

Each round, a miner builds a coinbase transaction and searches for a SHA3-256 proof-of-work over the block's merkle root. Not every registered miner grinds on every block: the round's UNiCORN (see Consensus & the block round) selects both the participating subset of miners and, from the proofs submitted, the single winner — keeping energy use proportionate to what a round actually needs.

The block reward follows a decaying formula rather than periodic halving, and is split across the mempool quorum that produced the block. Coinbase outputs mature — become spendable — 100 blocks after they are mined.

Consensus & the block round

Lineage's consensus mechanism is named Prime Radiant Consensus in the whitepaper. See Technology → Consensus for the proof-of-work economics; this article covers the mechanics of how a block round actually runs.

A deployment runs on two RAFT groups— one across the mempool nodes, one across the storage nodes. Whatever a group replicates has to be deterministic: same inputs, same order, same result, or member nodes would silently fork. Only local state, such as caches and metrics, is allowed to differ between nodes. Even the round's timestamp is itself a replicated log item rather than something each node reads off its own clock, precisely to keep that determinism.

A round, phase by phase:

  • Tx intake — incoming transactions are replicated to every node in the mempool group.
  • Block body & UNiCORN — a block body is built from the replicated pool, and the round's UNiCORN is constructed from it.
  • Participant intake — registered miners apply to the round; the UNiCORN selects which of them actually get to participate.
  • PoW intake — the selected miners submit their proofs.
  • Winner selection — the UNiCORN picks the winning proof from the submissions.
  • Assemble & commit — the mempool group stamps the winning nonce and coinbase hash into the header, assembles the block, and sends it to storage; storage commits it and notifies the mempool, which seeds the next round.

Difficulty is set by ASERT(an in-repo port of ASERT3-2D). Classic ASERT assumes a fixed number of winning hashes per block and lets the timestamp vary; Lineage inverts that: the block interval is fixed and the number of hashes floats, so a surplus or shortfall of hashing power over a round is mapped onto a synthetic elapsed time that feeds ASERT's usual retarget math. The interval is fixed at 30 seconds— block height tracks UTC time directly, 2,880 blocks per UTC day — from an epoch of 2026-08-28T00:00:00Z.

Proof-of-work hashes with SHA3-256, via CPU, OpenGL, or Vulkan mining backends, so GPU mining is supported today through those backends. A separate, purpose-built Lineage hash (SandWorm) exists but is not yet wired into the mining fleet — see Technology for that direction.

Blocks & headers

A block is a header plus the hashes of the transactions it contains:

rust
struct Block {
    header: BlockHeader,
    transactions: Vec<String>,   // transaction hashes
}

The header carries everything needed to identify, order, and validate the block without touching the transactions themselves:

rust
struct BlockHeader {
    version: u32,
    bits: usize,                                  // ASERT compact target; 0 = legacy leading-zeroes PoW
    nonce_and_mining_tx_hash: (Vec<u8>, String),   // winning PoW nonce + coinbase tx hash
    b_num: u64,                                    // block height
    timestamp: i64,
    seed_value: Vec<u8>,                           // UNiCORN "{seed}-{witness}"
    previous_hash: Option<String>,
    txs_merkle_root_and_hash: (String, String),    // MerkleLog root + flat SHA3 digest of the tx-hash list
}

txs_merkle_root_and_hash is a pair, not a nested tree: the first element is a MerkleLog root over the block's transaction hashes, the second is a flat SHA3-256 digest of that same hash list. seed_value carries the round's UNiCORN seed and witness, joined as "{seed}-{witness}". bits holds the ASERT compact target for the round; a value of 0 marks the legacy leading-zeroes proof-of-work scheme instead.

Read blocks over HTTP with GET /v1/blocks/latest or GET /v1/blocks/{num} — see the API reference for full request and response shapes. Both return the block as opaque JSON rather than a typed schema (a block field on /latest; a data field alongside storage metadata on /{num}), so treat the struct above as the underlying shape, not a guaranteed response contract.

Two-way (DRUID) payments

A two-way payment is an atomic swap: two transaction halves, built and submitted independently by each party, either settle in the same block or neither does. There is no separate swap primitive at the protocol level — a two-way payment is an ordinary transaction (see Transactions) that additionally carries a druid_info field. As covered there, this is what actually signals a two-way payment — not a particular version number.

druid_info is Some(DdeValues), where:

rust
DdeValues {
    druid: String,                        // shared id both halves match on
    participants: usize,
    expectations: Vec<DruidExpectation {
        from: String,
        to: String,
        asset: Asset,
    }>,
    genesis_hash: Option<String>,
}

druid_info is unsigned: it is one of the fields excluded from the signable preimage described in Keys, addresses & wallets. So a two-way payment cannot be matched by checking a signature over the DRUID, and it is not matched by any version field either — matching is structural. For a given DRUID, the node collects every transaction carrying that druid_info.druid and checks that each declared expectation (from/to/asset) actually appears among the real outputs of that transaction set. Only if every expectation on both sides is met does the swap settle; matching halves sit in the mempool's DRUID pool until then, so a two-way payment that never gets its counterpart simply never clears.

Flow (sdk-js): the initiator calls make2WayPayment, which generates a DRUID, builds and signs its own transaction half, and drops an offer — the DRUID plus both parties' expectations — into the counterparty's mailbox on valence. The counterparty polls with fetchPending2WayPayment, and on accept2WayPayment builds its own matching half, submits it to the mempool, and marks the offer accepted on valence so the initiator's side can be sent in turn.

javascript
// Party A — offers to swap
const offer = await wallet.make2WayPayment(
  partyBAddress,     // Party B's address
  sendingAsset,      // what A sends
  receivingAsset,    // what A expects back
  allKeypairs,
  receiveKeypair,    // where A's incoming asset lands
);
const { druid } = offer.content.make2WayPaymentResponse;

// Party B — checks its mailbox, then accepts
const pending = await wallet.fetchPending2WayPayment(keypair, allEncryptedTxs);
const details = pending.content.fetchPending2WResponse[druid];
await wallet.accept2WayPayment(druid, details, allKeypairs);

Offers ride on valence, which is E2E-encrypted by design — but the reference sdk-js client currently posts the offer payload (the DRUID, both expectations, and status) to valence as plain JSON, unencrypted. Treat two-way offers relayed by the current SDK as visible to anyone who can read that mailbox entry, not as confidential.

The valence relay

Valence is a generic, opaque, end-to-end-encrypted relay for exchanging data between addresses — an axum service backed by Redis. It carries two-way payment offers, but it has no model of what a “payment” or a “DRUID” is: it stores opaque JSON blobs under a caller-supplied id, one mailbox per address, and returns them unchanged on read. Clients are expected to encrypt the data they store for the recipient before sending it, so valence itself never has to see plaintext.

A mailbox is an address, and entries within it are keyed by whatever id the caller chooses — a DRUID is a common choice for two-way offers, but it is only ever that: an example id, not something valence understands. An entire mailbox expires after a TTL (600 seconds by default, refreshed on every write), so unread offers eventually disappear rather than accumulating forever.

Every route under /messages requires three headers: address (the mailbox being read or written — not necessarily the caller's own), public_key, and signature, an ed25519 signature over the raw UTF-8 bytes of the address string. Verification is deliberately verify-only: valence checks that signature is valid for address under public_key, but does not require address to be derived from public_key. That is by design, not an oversight — a sender addresses an offer to a recipient's mailbox while signing with their own key (exactly what make2WayPayment does above), so binding the two would reject every send. Confidentiality comes from client-side E2E encryption, not from mailbox access control.

json
{
  "address": "76e…dd6",
  "public_key": "a4c…e45",
  "signature": "b9f…506"
}
RouteEffect
POST /messagesStore { id, data } in the caller-addressed mailbox; 201 with { id }. Posting an existing id overwrites it.
GET /messagesThe whole mailbox as an id → data map.
GET /messages/{id}A single entry as { id, data }, or 404.
DELETE /messages/{id}Removes one entry; 204.
DELETE /messagesClears the whole mailbox; 204.
GET /healthzUnauthenticated liveness check.

Valence only stores and returns whatever JSON it is given — it does not know a two-way offer from any other message. The pending → accepted lifecycle described in Two-way (DRUID) payments (the status field, matching a DRUID back to a locally-encrypted transaction, deciding when to submit to the mempool) is logic that lives entirely in the SDK and wallet, not in valence.

UNiCORN randomness

A UNiCORN is a Sloth VDF(Verifiable Delay Function, after Lenstra & Wesolowski) — slow to evaluate, fast to verify. Evaluating it forward takes a fixed run of iterations that cannot be meaningfully parallelised or shortcut, but anyone holding the seed and the resulting witness can verify the output almost instantly. The whitepaper describes the result as uncontestable: the seed is fixed before the VDF runs, so the only way to steer the outcome is to steer the round's replicated inputs themselves — and those are agreed by consensus before the UNiCORN is ever constructed.

The seed is a SHA3 hash over three inputs, each already agreed by the mempool group's RAFT log: the round's transaction inputs, the participating-miner list, and the winning proof-of-work hashes from two blocks ago. Because all three are RAFT-replicated before the VDF runs, every mempool node computes the identical UNiCORN independently — there is no leader to trust and nothing to distribute after the fact.

The result seeds a Fortuna CSPRNG, which the round draws from twice: once to select which registered miners actually get to mine this round (the participating subset), and again to pick the winner among the proofs they submit. The seed and witness are stamped into the block header's seed_value field (see Blocks & headers) as "{seed}-{witness}", so the choice is auditable from the stored block alone. The whitepaper additionally describes rotating the mempool triple used to source this entropy on a daily basis.

Because every mempool node evaluates the identical seed independently from the same replicated inputs, there is nothing left to check after the fact on that side. Downstream, storage nodes do not currently re-check the UNiCORN at all — they validate the assembled block's proof-of-work and transaction/merkle consistency instead.

API reference

The full /v1 REST API — reading chain state, submitting transactions, and querying balances, supply, blocks, and wallet operations — is documented endpoint by endpoint, grouped by the node that serves each one.

Open the API reference, or download the full OpenAPI document at /openapi.json to import into Postman or any OpenAPI tool. Each node also serves its own subset at /v1/openapi.json (for example https://storage.lineage.to/v1/openapi.json).

MCP server

A hosted Model Context Protocol endpoint lets AI agents and assistants use Lineage as tools: balances and transactions, keypair and seed generation, block / entry / transaction lookups, supply, and node health. It wraps the same HTTP API documented here.

Endpoint: mcp.lineage.to

AI Skills

The lineage plugin is a set of packaged skills that make an AI coding agent an expert in Lineage. It works across Claude Code, Codex, Cursor, the Gemini CLI, opencode, and any tool that reads an AGENTS.md index. There is nothing to invoke by hand: as you work on a Lineage task, the agent automatically pulls in the skill that matches it.

The skills span three tracks — fundamentals (the base every other skill assumes), building on Lineage (SDK usage, the /v1 API, two-way DRUID payments, and standing up a dev node), and core contributing (working inside the node codebase). The full catalogue lives in the skills repository. No credentials are needed, and the skills don’t require the MCP server.

Install in Claude Code

Add the marketplace, then install the lineage plugin from the /plugin menu.

shell
# In Claude Code
/plugin marketplace add lineage-foundation/skills

# then open the plugin menu and install "lineage"
/plugin

Other agents

The same skills ship as adapters for other tools, generated into the repository and discovered automatically:

  • Codex — register the generated .codex-plugin/ directory per your Codex environment’s plugin-setup steps (no one-line command is published yet).
  • Cursor — the .cursor/skills/ directory is auto-discovered when you open the repository in Cursor.
  • Gemini CLI — the .gemini/skills/ directory is picked up as workspace skills.
  • opencode — the .opencode/skills/ directory is discovered automatically.
  • Copilot, Aider, Zed, and similar — read the root AGENTS.md index, which lists every skill.

SDKs & tutorials

Beyond the raw endpoint reference, Lineage ships official client libraries across a range of languages plus node tooling. The full walkthroughs and runnable code live in the published repositories; the cards below summarise each SDK and where it fits. They all wrap the same HTTP API documented above; configure each with a mempool base URL, a storage base URL, and a passphrase for local key encryption.

Install

Add the client for your stack.

shell
# JavaScript / TypeScript
npm install @lineage-foundation/sdk-js

# Python (imports as `lineage`)
pip install lineage-sdk

# Go
go get github.com/lineage-foundation/sdk-go

# Rust
cargo add lineage-sdk

# PHP
composer require lineage/php

# Laravel
composer require lineage/laravel

First call

Create a Wallet, point it at a mempool host with a passphrase for local key encryption, and initialise a new keypair. initNew returns the generated seed phrase. Store it securely; it is the only way to recover the wallet.

javascript
import { Wallet } from '@lineage-foundation/sdk-js';

const wallet = new Wallet();

const CONFIG = {
  mempoolHost: 'https://mempool.lineage.to',
  passphrase: 'a secure passphrase',
};

wallet.initNew(CONFIG).then((res) => {
  console.log(res.content.initNewResponse.seedphrase);
});

Send your first payment

The SDK keeps your keys local, signs transactions for you, and submits them to the mempool, so the whole flow is a handful of calls. There is no public faucet yet: generate an address, then send it to the team to be seeded, or, if you run your own node, request a donation from a funded peer over POST /v1/donation-requests. Every address payment returns a transaction hash you can follow on the block explorer.

javascript
import { Wallet } from '@lineage-foundation/sdk-js';

const wallet = new Wallet();

// 1. Create a wallet — store the returned seed phrase safely.
const res = await wallet.initNew({
  mempoolHost: 'https://mempool.lineage.to',
  passphrase: 'a secure passphrase',
});
console.log(res.content.initNewResponse.seedphrase);

// 2. Generate an address to receive funds.
const keypair = wallet.getNewKeypair([]).content.newKeypairResponse;
console.log(keypair.address);

// 3. Once funded, check the balance.
const bal = await wallet.fetchBalance([keypair.address]);
console.log(bal.content.fetchBalanceResponse.total);

// 4. Send a payment — change returns to your own keypair.
const receipt = await wallet.makeTokenPayment(
  'recipient-address',
  1000,
  [keypair],
  keypair,
);
// receipt carries the transaction hash, amount, and addresses used
console.log(receipt);

The Python client mirrors the same flow:

python
from lineage.wallet import Wallet

wallet = Wallet()

# 1. Load your wallet from its seed phrase.
wallet.from_seed(seed_phrase, {
    'mempoolHost': 'https://mempool.lineage.to',
    'passphrase': 'your-secure-passphrase',
})

# 2. The address to receive funds.
address = wallet.get_address()
print(address)

# 3. Once funded, check the balance.
balance = wallet.fetch_balance([address])
if balance.is_ok:
    print(balance.get_ok())

# 4. Send a payment.
receipt = wallet.create_transactions(
    destination_address='recipient-address',
    amount=1000,
)
if receipt.is_ok:
    print(receipt.get_ok())

sdk-js

The JavaScript / TypeScript client for browser and Node apps and wallets: create a wallet, create items and assets, run two-way payments, send and receive. Drop-in for web front-ends and Valence servers.

lineage-foundation/sdk-js

sdk-python

The Python client for backends, data tooling, and automation: key management, balance and supply reads, transaction construction, and two-way flows. It covers the same surface as sdk-js, idiomatic for Python services and notebooks.

lineage-foundation/sdk-python

sdk-go

The Go client for services, CLIs, and backends: a keyless read client and a key-holding wallet covering key management, balance and supply reads, transaction construction, payments, and two-way flows. Same surface as sdk-js, idiomatic for Go.

lineage-foundation/sdk-go

sdk-rust

The Rust client for performance-sensitive services and tooling: key management, chain reads, transaction construction, payments, and two-way flows. Covers the same surface as sdk-js.

lineage-foundation/sdk-rust

sdk-php

The PHP client for server-side web stacks: wallet creation, asset issuance, payments, chain reads, and two-way flows. Covers the same surface as sdk-js, idiomatic for PHP services.

lineage-foundation/sdk-php

sdk-laravel

The Laravel wrapper around sdk-php: wallets and keypairs backed by Eloquent models, plus Artisan commands for creating wallets, deriving keypairs, minting items, and making token and item payments.

lineage-foundation/sdk-laravel

Valence node & core

The application-server pattern. Valence node exposes HTTP routes (health checks, JSON forwarding, optional static/webhook endpoints); Valence core is the embeddable part with lifecycle hooks and plugin registration. Plugins add application behaviour but never change chain rules.

Repositories

API usage

A guided order of operations for calling the public HTTP API directly: pick a node class, verify connectivity with a read-only route, then move on to writes. Start from the quick start above.

Service URLs

Running a node

The fastest way to stand up a full Lineage stack (mempool, storage, and miner) is the lineage-foundation/fleet repository, which ships a Docker Compose stack and a from-source build. The steps below mirror its README.

Prerequisites

A recent Rust toolchain and the Linux build dependencies. On Ubuntu:

shell
sudo apt-get update && sudo apt-get install -y \
  build-essential m4 llvm libclang-dev clang cmake pkg-config \
  git curl python3 libglfw3-dev libxrandr-dev libxinerama-dev \
  libxcursor-dev libxi-dev
shell
# install Rust
curl https://sh.rustup.rs -sSf | sh
source "$HOME/.cargo/env"
rustc --version

Docker Compose (recommended)

Build and start the full multi-node stack from the repo root:

shell
docker compose build
docker compose up

This brings up three services:

ServicePortNotes
Mempool3003HTTP API
Storage3001Read / history
MinerStarts after mempool & storage

Node configuration is read from ./.docker/conf/node_settings.toml (mounted to /etc/node_settings.toml). Point at a different file with the NODE_SETTINGS override:

shell
NODE_SETTINGS=/absolute/path/to/node_settings.toml docker compose up

On Apple Silicon, select the ARM platform (default is linux/amd64):

shell
FLEET_COMPOSE_PLATFORM=linux/arm64 docker compose up

Rebuild a single service, or tear the stack down and remove volumes:

shell
docker compose build mempool-node
docker compose down -v

Build from source

shell
cargo build --release
cargo test

Or build just the container image (distroless cc-debian13, runs as nonroot; binary at /lineage/lineage):

shell
docker build -t fleet-node:local --platform linux/amd64 .
ContributingBase work on an updated main and open PRs against it, following Conventional Commits (feat, fix, docs, chore, refactor, test, ci, perf; mark breaking changes with a ! suffix). Full details in the fleet README.