English πΊπΈ | FranΓ§ais π«π· | EspaΓ±ol πͺπΈ
StellarKit API is a developer utility service that exposes the Stellar Horizon blockchain through a simple REST interface. It is designed for application developers who need fast, typed access to account details, fee estimates, transaction history, network health, and asset metadata.
StellarKit API is a wrapper around the Stellar Horizon API, built with Express.js and the official @stellar/stellar-sdk library. It normalizes Horizon responses, provides a clean REST structure, and adds convenience endpoints for the most common Stellar developer workflows.
This project is ideal for:
- Web and mobile developers building on Stellar
- Server-side services consuming Stellar account and transaction data
- Wallet providers that need reliable fee estimation and account summaries
- Applications requiring typed API responses via bundled TypeScript definitions
- π Network status and ledger health
- π° Dynamic fee estimation for optimal transaction pricing
- π₯ Account detail aggregation including balances, signers, and thresholds
- π Paginated transaction history and operation history per account
- πͺ Asset metadata search and issuer lookup
- π« Built-in security middleware with rate limiting, helmet headers, CORS, and HPP
- π§ͺ Test coverage using Jest and Supertest
- π¦ Bundled TypeScript types for safe integration in TypeScript projects
- SDK Migration Guide β migrating from the JavaScript SDK to the TypeScript SDK
- SDK README β JavaScript client usage and method reference
- Getting Started Guide - Set up the project and make your first API calls
- SEP Integration Guide - Use StellarKit discovery, account, asset, fee, and monitoring endpoints in SEP-10, SEP-24, and SEP-31 workflows
- Soroban Integration Guide - End-to-end workflow for querying contract state, monitoring events, checking expiry, and simulating invocations
- Soroban Endpoints Guide β Soroban contract endpoints: what Soroban is, how contract IDs work, and how to inspect deployed contracts via
/soroban/contract/:id,/soroban/contract/:id/storage, and/soroban/contract/:id/functions - Production Deployment Guide - Deploy to production with Node.js, Docker, Railway, Render, or Fly.io
- API Design Guidelines - Design conventions and response patterns
- Response Format Guide - Standard response envelopes, pagination, and data formats
- Streaming Guide - SSE and WebSocket streaming endpoints, event payloads, reconnection, and clean close handling
- Webhooks Guide - Register webhooks, available events, payload shapes, signature verification, retries, and unregistration
- Webhook Security Guide - Verify HMAC-SHA256 delivery signatures in Node.js/Python/Go, handle invalid signatures, store secrets safely, and rotate with the dual-secret pattern
- Batch Endpoints Guide - Batch trust-status, freeze-status, and transaction status APIs, limits, and when to use batch vs individual
- DEX Endpoints Guide - All six DEX endpoints with curl examples, sample responses, and guidance on spread vs depth vs imbalance vs arbitrage
- Compliance Endpoints Guide - All compliance and risk endpoints with curl examples, sample responses, and a complete compliance workflow
- Network Endpoints Guide - All network and fee endpoints with curl examples, cache TTLs, and sample responses
- Caching Strategy - Per-endpoint cache TTLs and configuration
- Logging Guide - Log levels, configuration, structured log entry fields, JSON parsing, and production monitoring
- Monitoring Guide - Key metrics, alert thresholds, health check polling strategy, and integration patterns for Prometheus, Datadog, CloudWatch, and uptime tools
- Observability Guide - Cache stats endpoint, request tracing via requestId, and structured log field reference
- Performance Guide - Latency expectations, cache TTL tuning, Horizon optimization, and scaling recommendations
- Error Reference - All error types, status codes, and suggested fixes
- Error Codes - HTTP status code reference with descriptions, scenarios, and sample responses
- Account Endpoints Guide - Account endpoints grouped by use case (portfolio, activity, multisig, compliance) with curl examples for every endpoint
- Transaction Endpoints Guide - Transaction and operation endpoints for building explorers and submission tools, with curl examples and usage patterns
- Rate Limiting - Default limits, configuration, response headers, and retry strategies
- Frequently Asked Questions (FAQ) - Common setup and contribution questions
- Utilities Guide - All utility endpoints with use cases, curl examples, and sample responses
- Asset Endpoints Guide - All six asset endpoints with curl examples, sample responses, and guidance on when to use each one
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | / |
Lists available API endpoints | β |
| GET | /health |
Service health check | β |
| GET | /network-status |
Latest ledger, fees, and protocol info | fresh |
| GET | /network/ledger-timing |
Analyze ledger close time consistency | β |
| GET | /network/validators |
Current validator list grouped by organisation | fresh |
| GET | /network/validator-quorum |
Current quorum health status | fresh |
| GET | /network/base-fee |
Current network base fee in stroops and XLM | fresh |
| GET | /network/fee-percentiles |
Fee distribution percentiles from recent activity | fresh |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /fee-estimate |
Fee tiers for transaction submission | operations, fresh |
| GET | /fee-estimate/surge-status |
Fee surge detection and recommendations | fresh |
| GET | /fee-estimate/trends |
Fee trend analysis across the last 50 ledgers (avg, min, max, trend direction, and recommendation) | fresh |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /account/:id |
Account details, balances, reserve breakdown | β |
| GET | /account/:id/age |
Account age and longevity metrics | β |
| GET | /account/:id/balances |
XLM and asset balances | native, assets |
| GET | /account/:id/native-balance |
Native XLM balance only | β |
| GET | /account/:id/asset-balance/:assetCode/:assetIssuer |
Balance for a specific asset trustline | β |
| GET | /account/:id/sequence |
Current sequence number | β |
| GET | /account/:id/trustlines |
Trustlines with TOML asset metadata resolved | assetCode, sponsored |
| GET | /account/:id/payments |
Payment and create_account operations | limit, order, cursor, assetCode, assetIssuer |
| GET | /account/:id/funding-history |
Account funding sources with sender, amount, asset, and timestamp | β |
| GET | /account/:id/trades |
DEX trades for the account | limit, order, cursor, fresh |
| GET | /account/:id/offers |
Open DEX offers for an account | limit, cursor |
| GET | /account/:id/offer-history |
Historical offer operations | limit, order, cursor |
| GET | /account/:id/analytics |
Account activity analytics: transaction frequency, first/last seen timestamps, and average transactions per day | β |
| GET | /account/:id/transaction-count |
Total transaction count, first and last transaction timestamps | β |
| GET | /account/:id/inactivity |
Days since last transaction and status | β |
| GET | /account/:id/funding-history |
Initial funding sources sorted by amount descending | β |
| GET | /account/:id/volume |
Transaction volume by asset over a time period (default: 30 days, max: 90 days) | days (default: 30, max: 90) |
| GET | /account/:id/risk-score |
Computed risk score and contributing factors | β |
| GET | /account/:id/freeze-status/:assetCode/:assetIssuer |
Check if an asset is frozen on an account | β |
| GET | /account/:id/can-receive/:assetCode/:assetIssuer |
Check if an account can receive a specific asset | β |
| GET | /account/:id/signers |
Account signers, their weights, and threshold configuration | β |
| GET | /account/:id/subentry-health |
Subentry usage and remaining capacity | β |
| GET | /account/:id/sponsorship |
Sponsorship relationships for the account β returns raw sponsored entries and accounts this account is sponsoring. Prefer /sponsorships for new integrations. Note: both endpoints will be consolidated in a future release (see issue #19). |
β |
| GET | /account/:id/sponsorships |
Preferred. Typed sponsorship summary with sponsoredBy and sponsoring arrays; each entry includes type, address, sponsor, and reserveAmount. More structured than /sponsorship. Note: will be consolidated with /sponsorship in a future release (see issue #19). |
β |
| GET | /account/:id/claimable-balances/eligible |
Evaluates every claimable balance where the account is a claimant and categorises each as eligible, not yet claimable, or expired. See the Claimable Balances section for details. | limit, cursor, order, fresh |
| GET | /account/:id/pool-positions |
Liquidity pool positions and share values | β |
| GET | /account/:id/counterparties |
Frequent payment counterparties | β |
| GET | /account/:id/transactions/search |
Search transactions by memo content | memo, memo_type, limit, cursor, order |
| POST | /account/:id/multisig-plan |
Signer combinations for each threshold | Body: availableSigners |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /transactions/:id |
Paginated transaction history for an account | limit, order, cursor |
| GET | /transactions/:id/operations |
Paginated operation history for an account | limit, order, cursor |
| POST | /transactions/batch-status |
Check confirmation status of multiple tx hashes | Body: hashes (max 20) |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /asset/:code/:issuer |
Asset metadata and statistics | fresh |
| GET | /asset/:code/:issuer/holders |
Paginated accounts holding an asset | limit, order, cursor |
| GET | /asset/:code/:issuer/distribution |
Holder concentration and Gini coefficient | β |
| GET | /asset/:code/:issuer/supply |
Total, circulating, and locked supply breakdown | β |
| GET | /asset/:code/:issuer/verify |
Verify issuer via flags, home_domain, and stellar.toml | β |
| GET | /asset/:code/:issuer/issuance-history |
Time series of supply changes over a specified period | resolution (7d, 30d, 90d) |
| GET | /asset/search |
Search assets by code across all issuers | code, limit |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /dex/price/:sellAsset/:buyAsset |
Effective exchange rate via best DEX path | amount |
| GET | /dex/spread/:sellAsset/:buyAsset |
Bid-ask spread for a trading pair | β |
| GET | /dex/depth/:sellAsset/:buyAsset |
Full order book depth analysis | β |
| GET | /dex/imbalance/:sellAsset/:buyAsset |
Buy/sell pressure imbalance detection | β |
| GET | /dex/arbitrage/:assetCode/:assetIssuer |
Circular arbitrage path discovery | β |
| GET | /dex/top-markets |
Top markets ranked by recent trade activity | limit |
| GET | /dex/pool-share-value/:poolId/:shares |
Calculate the equivalent value of pool shares in both reserve assets | β |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /liquidity-pools |
List liquidity pools with normalized reserves, fees, shares, and trustline metadata | limit, cursor, page, order, fresh |
| GET | /liquidity-pools/:id |
Live pool details from Horizon (reserves, fee, shares) | β |
| GET | /liquidity-pools/:id/profitability |
Estimated annualized fee income | β |
| GET | /liquidity-pools/:id/reserve-ratio |
Reserve ratio and drift from equal | β |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /claimable-balances/:id/evaluate/:accountId |
Evaluate claimability for a specific account | β |
| Method | Path | Description | Query Params |
|---|---|---|---|
| WS | /stream/ledgers |
Real-time ledger updates via WebSocket | β |
| GET | /stream/transactions/:id |
Live account transactions via SSE | β |
| GET | /stream/payments/:id |
Live payment events via SSE | β |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /stellar-toml/:domain |
Fetch and parse stellar.toml for a domain | β |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /utils/friendbot/:accountId |
Fund a testnet account via Friendbot | β |
| GET | /utils/convert |
Convert between XLM and stroops | xlm or stroops |
| GET | /utils/validate-account |
Validate a Stellar public key format | id |
| GET | /utils/validate-asset |
Validate a Stellar asset code format | code |
| GET | /utils/memo |
Decode a raw Horizon memo | type, value |
| GET | /utils/base64 |
Encode or decode Base64 strings | encode or decode |
| GET | /utils/ledger-date |
Estimate close date for a ledger sequence | sequence |
| GET | /utils/keypair |
Generate a random testnet keypair | β |
| POST | /utils/decode-xdr |
Decode a transaction XDR envelope to JSON | Body: xdr |
| Method | Path | Description | Query Params |
|---|---|---|---|
| GET | /cache/stats |
Cache hit rate and performance statistics | β |
Soroban is Stellarβs smart contract platform for running WebAssembly (WASM) contracts on the Stellar ledger. It differs from traditional Stellar operations because it allows developers to execute programmable contract logic, instead of only submitting payments, trustline updates, account settings, and other built-in ledger operations.
A Soroban contract is referenced by a contract ID, which is the address used to invoke the contract after it has been deployed. The contractβs WASM hash is the digest of the compiled contract binary and uniquely identifies the contract code that is stored and executed on the network.
StellarKit API supports Soroban contract inspection through three endpoints: GET /soroban/contract/:id looks up contract details by contract ID, including the associated WASM hash and ledger metadata, GET /soroban/contract/:id/storage returns the contract's instance-storage entries, and GET /soroban/contract/:id/functions returns exported function names, parameter types, and return types parsed from the contract ABI. Together they make it easier to combine traditional Stellar account workflows with Soroban contract interactions.
See docs/soroban.md for a full walkthrough with curl examples and sample responses.
- docs/sep-integration.md β SEP-10 authentication, SEP-24 hosted transfers, and SEP-31 cross-border payment workflows using StellarKit.
- docs/soroban.md β Soroban contract endpoints: what Soroban is, how contract IDs work, and how to inspect deployed contracts via
/soroban/contract/:id,/soroban/contract/:id/storage, and/soroban/contract/:id/functions. - docs/account-endpoints.md β Account endpoints grouped by use case (portfolio, activity, multisig, compliance) with curl examples for every endpoint.
- docs/webhooks.md β Webhook registration, events, payloads, signature verification, retries, and unregistration.
- docs/webhook-security.md β Verifying HMAC-SHA256 delivery signatures (Node.js/Python/Go), handling invalid signatures, secret storage, and dual-secret rotation.
- docs/batch-endpoints.md β Batch API endpoints, address/hash limits, per-entry errors, and when to use batch vs individual.
src/index.jsβ application entry pointsrc/websocket.jsβ WebSocket helper for Stellar streaming datasrc/config/β Stellar network configuration and cache TTL settingssrc/routes/β Express route handlers (21 files covering account, asset, DEX, liquidity pools, claimable balances, Soroban, webhooks, and more)src/services/β cache, metrics, webhook delivery, and contract event polling servicessrc/utils/β shared helpers for formatting, validation, caching, response shaping, and Horizon mappingsrc/middleware/β API key auth, validation, error handling, rate limiting, sanitisation, and request loggingtests/β 170+ test files organised into root-level unit tests, plusintegration/,middleware/,routes/,stream/, andutils/subdirectoriestypes/index.d.tsβ exported TypeScript type definitionsdocs/β in-depth guides for deployment, webhooks, Soroban, streaming, rate limiting, observability, and moreexamples/β runnable demo scripts for multisig, pool positions, spread calculation, and transaction searchscripts/β developer utility scripts including testnet account seeding and WebSocket client demosdk/β TypeScript SDK client with typed methods for accounts, assets, DEX, fees, network, and Sorobantypes/β bundled TypeScript type declarations for use in TypeScript projects.github/β GitHub Actions CI workflow and pull request template
Contains endpoint implementations (21 route files). All routes import the shared Horizon server instance from src/config/stellar.js to ensure consistent SDK configuration across the application.
Shared helpers for formatting, validation, caching, and response shaping:
| File | Purpose |
|---|---|
response.js |
Wraps data in consistent JSON success response envelopes with metadata. |
validators.js |
Query parameter and account ID validators for pagination, asset codes, and Stellar addresses. |
errors.js |
Detects and translates Horizon timeout errors and provides user-friendly messages. |
StellarKitError.js |
Custom error class for consistent error handling with HTTP status, type, detail, and suggestions. |
cache.js |
Creates shared NodeCache instances for network status, fee estimates, and contract dependencies. |
logger.js |
Structured Pino-based logger with automatic redaction of sensitive fields and environment-based verbosity. |
horizonErrors.js |
Provides plain-English translations for common Horizon error codes (tx_bad_seq, op_no_trust, etc.). |
horizonHealth.js |
Pings Horizon and returns connectivity status (ok/degraded/unreachable) for health checks. |
horizonStatusMapper.js |
Maps Horizon result codes to corresponding HTTP status codes (e.g., tx_bad_seq β 409). |
formatAmount.js |
Normalizes Stellar amounts to fixed seven-decimal string format across types. |
formatBalance.js |
Formats Stellar balance strings with thousand separators (e.g., "10,000.1234567"). |
formatLedgerSequence.js |
Converts ledger sequence numbers to consistent integer format from string or number inputs. |
formatTransaction.js |
Formats Horizon transaction records into clean SSE payload structure. |
parseStellarAmount.js |
Converts stroops (Stellar's smallest unit) to seven-decimal XLM strings. |
operationFormatter.js |
Normalizes Horizon operation records into consistent API operation shape. |
toCamelCase.js |
Recursively converts snake_case object keys to camelCase throughout nested structures. |
memo.js |
Decodes Stellar memos from base64 to UTF-8 text or hexadecimal hashes. |
asset.js |
Parses Stellar asset strings in "CODE:ISSUER" format into SDK Asset objects. |
assetHelpers.js |
Utility helpers for detecting native XLM assets across different object shapes. |
assetToml.js |
Fetches and normalizes asset metadata from TOML files (home domain resolution). |
tomlResolver.js |
Resolves and caches TOML files from asset home domains with inline comment stripping. |
accountAge.js |
Calculates account age and longevity metrics with maturity classification (new, established). |
contractDeployment.js |
Finds Soroban contract deployment metadata (deployer, timestamp, ledger) from Horizon operations. |
contractSpec.js |
Parses and maps Soroban contract specification XDR data to human-readable type information. |
crypto.js |
Generates SHA-256 proof hashes with salt for cryptographic verification and security features. |
effectTypes.js |
Defines the canonical list of valid Horizon effect type strings for validation. |
mapAccountTrade.js |
Maps raw Horizon trade records to normalized StellarKit shape with formatted prices. |
mapFeeEstimate.js |
Maps Horizon fee statistics to StellarKit fee estimate response with surge capacity detection. |
mapNetworkStatus.js |
Maps Horizon server info and latest ledger into normalized network status payload. |
pagination.js |
Resolves page numbers to Horizon paging cursors using async token lookups. |
Middleware functions that validate, transform, and handle requests. Middleware execution order is important β see docs/project-structure.md for details.
| File | Purpose |
|---|---|
errorHandler.js |
Centralized error handler that formats Horizon/SDK errors into consistent JSON responses. |
rateLimiter.js |
Express rate limiter with configurable per-endpoint limits (global, account, asset endpoints). |
requestLogger.js |
Logs completed requests with method, path, status, request ID, and response time via Pino. |
requestId.js |
Generates or validates incoming request IDs with UUID fallback and injection pattern checking. |
sanitize.js |
Trims whitespace and strips null bytes from params/query; validates length and injection patterns. |
apiKeyAuth.js |
Optional API key authentication middleware that validates X-API-Key header against hashed keys from env. |
restrictHttpMethods.js |
Rejects unsupported HTTP methods (only GET, POST, DELETE, PATCH allowed; returns 405). |
contentTypeValidator.js |
Requires "application/json" Content-Type header for POST and PATCH requests (415 rejection). |
bodySizeLimit.js |
Enforces maximum request body size (default 10 KB) with configurable KB or legacy size strings. |
coerceQueryParams.js |
Converts query parameters (limit, operations, fresh) from strings to integers/booleans. |
normalizeAssetCode.js |
Uppercases asset code in route params and query params for consistent handling. |
rejectDuplicateQueryParams.js |
Prevents HTTP parameter pollution by rejecting requests with duplicate query keys. |
validateRouteParams.js |
Validates required route parameters are not empty and registers param validation handlers. |
etag.js |
Generates ETags from response bodies and returns 304 Not Modified if client If-None-Match matches. |
metricsCollector.js |
Intercepts responses and forwards status code, response time, and cache headers to metrics service. |
routeCounter.js |
Per-route request counter middleware that tracks totals by "METHOD /path" pattern. |
webhookSignatureAuth.js |
Validates HMAC-SHA256 webhook signatures with optional secret rotation support. |
New to Stellar or this API? Start with the Getting Started Guide for step-by-step instructions. Also see the Glossary for explanations of Stellar-specific terminology.
- Node.js >= 18
- npm >= 9
git clone https://github.com/stellarkit-lab-devtools/stellarkit-api.git
cd stellarkit-api
npm install
copy .env.example .envOpen .env and configure your environment variables:
STELLAR_NETWORK=testnet
PORT=3000Supported values for STELLAR_NETWORK are testnet and mainnet.
# Development with auto-reload
npm run dev
# Production
npm startVisit http://localhost:3000 after startup.
| Variable | Default | Description | Required |
|---|---|---|---|
STELLAR_NETWORK |
testnet |
Target Stellar network. Accepted values: testnet or mainnet. Controls which Horizon server is used and gates testnet-only endpoints such as Friendbot. |
β¬ No |
HORIZON_URL |
(derived from STELLAR_NETWORK) |
Override the Horizon server URL. When omitted, defaults to https://horizon-testnet.stellar.org for testnet and https://horizon.stellar.org for mainnet. |
β¬ No |
SOROBAN_RPC_URL |
(testnet only) | Soroban RPC server URL used by the /soroban/* endpoints. Defaults to https://soroban-testnet.stellar.org on testnet. No default on mainnet β must be set to use /soroban/* there. |
β¬ No |
PORT |
3000 |
TCP port the Express server listens on. | β¬ No |
NODE_ENV |
development |
Runtime environment. Set to production to enable combined HTTP logging and sanitised error messages. Set to test to suppress console output during test runs. |
β¬ No |
RATE_LIMIT_WINDOW_MS |
900000 |
Length of the rate-limit window, in milliseconds. See Rate Limiting. | β¬ No |
RATE_LIMIT_MAX |
100 |
Maximum number of requests allowed per IP address per rate-limit window. Applies to the global rate limiter. | β¬ No |
CACHE_TTL_MS |
5000 |
Cache time-to-live in milliseconds for the /network-status and /fee-estimate endpoints. |
β¬ No |
CACHE_TTL_CONTRACT_STORAGE_MS |
15000 |
Cache time-to-live in milliseconds for the /soroban/contract/:id/storage endpoint. |
β¬ No |
REQUIRE_API_KEY |
false |
Enables API key authentication. When true, clients must provide a valid API key via X-API-Key header. | β¬ No |
API_KEYS |
(empty) | Comma-separated list of valid API keys. Required when REQUIRE_API_KEY=true. | β¬ No |
All variables are optional β the server starts with sensible defaults when none are set. Set
STELLAR_NETWORK=mainnetexplicitly before deploying to production to avoid accidentally pointing at testnet.
New to Stellar? See the Glossary for plain-language explanations of stroops, trustlines, claimable balances, anchors, liquidity pools, and other key concepts.
Stellar requires all accounts to maintain a minimum XLM balance to exist on the ledger. This mechanism deters ledger spam and ensures the network remains efficient.
- Base Reserve: The fundamental unit of reserve on Stellar, currently set to 0.5 XLM.
- Account Reserve: To be activated, an account must hold at least 2 base reserves (1 XLM).
- Subentry Reserve: Every item an account owns (such as a trustline for a new asset, an open offer, a data entry, or an additional signer) is called a subentry. Each subentry increases the account's minimum balance requirement by 1 base reserve (0.5 XLM).
If an account is funded and holds 3 trustlines, its minimum balance is calculated as follows:
- Account Base: 2 base reserves = 1 XLM
- 3 Trustlines: 3 subentries Γ 0.5 XLM = 1.5 XLM
- Total Minimum Balance: 2.5 XLM
An account's spendable balance is the amount of XLM it can freely transfer or spend. It is calculated as:
Spendable Balance = Total Balance - Minimum Balance - Liabilities
You don't need to calculate this manually! The GET /account/:id endpoint provided by this API automatically computes and returns both the minimumBalance and spendableBalance for any Stellar account.
Stellar accounts can be configured with multiple signers and a threshold system that controls which transactions are allowed. Each signer has a weight, and the account also has three transaction thresholds:
- Low threshold for simple operations like account reads, data updates, and trustline management.
- Medium threshold for typical payment and offer operations.
- High threshold for sensitive actions such as setting account options, adding/removing signers, or changing thresholds.
Each signer on an account contributes its configured weight toward authorizing a transaction. Stellar evaluates the combined weight of all signers that sign a transaction and compares it to the threshold required by the operation.
- If the combined weight is equal to or greater than the operation's threshold, the transaction is valid.
- If the combined weight is lower than the required threshold, the transaction is rejected.
For example, an account could have:
- signer A with weight
1 - signer B with weight
1 - signer C with weight
2
If a medium-threshold operation requires 2, then either signer C alone or signers A and B together can authorize it.
StellarKit API exposes the account's multisignature details through dedicated account endpoints:
GET /account/:id/signersreturns the account's current signers and their weights.POST /account/:id/multisig-planreturns the account's threshold plan and how signers contribute to low, medium, and high threshold requirements.
These endpoints let developers inspect who can sign transactions, how much combined weight is available, and whether the account is configured correctly for its intended security model.
Use
GET /account/:id/signersto verify signer keys and weights, andPOST /account/:id/multisig-planto understand the threshold requirements before submitting multisig transactions. The multisig-plan endpoint accepts a JSON body with anavailableSignersarray β the list of signer public keys you expect to use.
curl -X POST http://localhost:3000/account/GABC.../multisig-plan \
-H "Content-Type: application/json" \
-d '{
"availableSigners": [
"GABC...",
"GDEF...",
"GXYZ..."
]
}'A claimable balance is a Stellar ledger entry that holds funds on behalf of one or more future recipients without requiring those recipients to exist on the network or take any action in advance. Think of it as placing money in a secure lockbox and handing out keys β each key can have conditions attached that control when it can be used.
With a regular payment operation, the destination account must already exist, must have a trustline for non-native assets, and receives the funds immediately. A claimable balance removes all three constraints:
- No destination account required at creation time. The recipient's public key is listed as a claimant, but their account does not need to be funded yet. They can create and fund their account later and then claim the balance.
- No trustline required in advance. The claimant does not need a pre-existing trustline for the asset. Stellar creates the necessary trustline automatically when the balance is claimed.
- Funds are not delivered instantly. The balance sits on the ledger until a claimant actively submits a
claimClaimableBalanceoperation. This makes claimable balances ideal for deferred, conditional, or opt-in transfers.
The account that creates the claimable balance pays the base reserves to keep the entry on the ledger. Those reserves are returned when the balance is eventually claimed or reclaimed.
Every claimant in a claimable balance is paired with a predicate β a rule that determines whether the claim is allowed at a given moment. Stellar supports five predicate types that can be nested to build arbitrarily complex conditions.
{ "unconditional": true }
The claimant can claim the balance at any time, with no restrictions. This is the simplest predicate and is useful when you just want to park funds for someone to pick up whenever they are ready.
{ "abs_before": "2026-12-31T23:59:59Z" }
The claim must happen before the specified timestamp. Once the deadline passes, this predicate evaluates to false and the claimant can no longer claim through it. Use this to set expiration dates β for example, a promotional reward that expires at the end of the quarter.
{ "abs_after": "2026-06-01T00:00:00Z" }
The claim is only allowed on or after the specified timestamp. Before that moment the predicate evaluates to false. This is useful for vesting schedules, release dates, or any scenario where funds should be locked until a future date.
{
"and": [
{ "abs_after": "2026-06-01T00:00:00Z" },
{ "abs_before": "2026-12-31T23:59:59Z" }
]
}Both sub-predicates must be true at the same time. The example above creates a claim window: the funds can only be claimed between June 1 and December 31, 2026. Outside that window the claim is denied.
{
"or": [{ "abs_after": "2026-06-01T00:00:00Z" }, { "unconditional": true }]
}At least one sub-predicate must be true. Compound or predicates are less common but can model fallback conditions β for example, "claimable after a certain date, or claimable unconditionally by a backup account."
{
"not": { "abs_before": "2026-06-01T00:00:00Z" }
}Inverts the inner predicate. not(abs_before X) is logically equivalent to abs_after X. While not is rarely needed on its own, it becomes powerful when nested inside and/or trees to express precise business rules.
| Use Case | How Claimable Balances Help |
|---|---|
| Onboarding new users | Send tokens to a public key that does not exist yet. The new user creates their account later and claims the balance β no coordination needed. |
| Vesting schedules | Create a balance with an abs_after predicate set to the vesting date. The employee or contributor can only claim once the date arrives. |
| Time-limited promotions | Use an and predicate combining abs_after (start) and abs_before (expiry) to define a claim window for airdrops or rewards. |
| Escrow / conditional release | The sender and a mediator are both listed as claimants. The sender's predicate uses abs_after (allowing reclaim after a timeout), while the recipient's predicate is unconditional. |
| Recurring grants | Create multiple claimable balances with staggered abs_after dates to simulate a payment schedule without requiring the recipient to be online. |
StellarKit API exposes claimable balance data through two surfaces:
| Endpoint | Description |
|---|---|
GET /account/:id/summary |
Returns the account's open claimable balances alongside recent transactions, open offers, and account details. |
GET /account/:id/claimable-balances/eligible |
Evaluates every claimable balance where the account is a claimant and categorizes each one as eligible (claimable right now), not yet claimable (a future time predicate has not been met), or expired (a deadline predicate has passed). Also listed in the Account API reference table. |
Use the /claimable-balances/eligible endpoint to build dashboards that show users exactly which funds are available to claim today and which are still locked. The API handles predicate evaluation server-side, so clients do not need to implement their own predicate logic.
Stellar's Liquidity Pools are automated market makers (AMMs) that enable decentralized asset swaps. This guide explains how pools work, how liquidity providers earn fees, and the fundamental concepts behind pool mechanics.
A liquidity pool is a smart ledger contract that holds equal-value reserves of two assets and facilitates swaps between them. Instead of relying on a central order book operator, the pool uses an automated pricing algorithm to execute trades and reward liquidity providers.
Key characteristics:
- Holds two assets in a constant product invariant: the product of the two reserve amounts remains constant before and after each swap.
- Issues pool share tokens to liquidity providers, representing fractional ownership of both reserves.
- Charges a trading fee (typically 0.3%) on every swap, which accrues to share holders.
- Operates on Stellar's native ledger without requiring external oracles or complicated governance.
When you deposit assets into a liquidity pool, you receive pool share tokens proportional to your contribution. These shares represent your ownership stake in both reserves.
Example:
If you deposit 1,000 XLM and 50,000 USDC into an empty pool, you receive 7,071 pool shares (calculated as
If the pool price changes and another user deposits at a different ratio, your percentage ownership dilutes β but the total value of your shares typically increases because of accumulated fees.
Stellar liquidity pools maintain a 50/50 reserve ratio by value. This means the total value of reserve A should equal the total value of reserve B at all times.
When a user swaps one asset for another, the pool adjusts prices according to the constant product formula, driving the ratio back toward 50/50. This self-correcting mechanism ensures the pool remains balanced and prevents depletion of either reserve.
Why 50/50?
- Minimizes impermanent loss for liquidity providers by keeping prices stable.
- Ensures neither reserve can be exhausted by extreme trades.
- Creates natural price discovery through the swap mechanism.
Every swap in a liquidity pool incurs a trading fee, typically 0.3% (expressed as 30 basis points). This fee is taken from the input amount and distributed to all pool share holders in proportion to their ownership.
Example: If you hold 10% of a pool's shares and the pool earns 100 USDC in fees over a period, you automatically receive 10 USDC when you withdraw or check your position. Fees are not claimed separately β they accrue directly to your share's proportional value.
The fee mechanism incentivizes liquidity provision: share holders earn passive income simply by holding their shares and allowing others to trade through the pool.
StellarKit API provides several endpoints to interact with and analyze liquidity pools:
| Endpoint | Description |
|---|---|
GET /liquidity-pools |
Retrieves a paginated list of liquidity pools with normalized reserve details and fee information. Supports limit (1β100), cursor (Horizon paging token), page (1-based convenience pagination), order (asc/desc), and fresh=true to bypass the cache. |
GET /liquidity-pools/:id |
Fetches detailed information about a specific pool, including reserves, share count, and fee basis points. |
GET /account/:id/pool-positions |
Returns all liquidity pool positions for an account with calculated share values and equivalent reserves. |
GET /dex/pool-share-value/:poolId/:shares |
Calculates the equivalent value of a specific number of pool shares in both reserve assets. |
Use these endpoints to build pool analysis dashboards, calculate LP returns, and help users decide when to provide or withdraw liquidity.
Returns a list of available API endpoints and a brief description.
Returns basic service health status.
Returns current Stellar network information, latest ledger data, fee settings, and protocol version.
Calculates a fee estimate for a transaction using the current network base fee and requested operation count.
Fetches account details, balances, signers, thresholds, flags, and spendable balance for the given Stellar public key.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN"Returns account balance details for XLM and all non-native assets.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/balances"Returns only the native XLM balance with buying and selling liabilities.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/native-balance"Returns the current sequence number for an account.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/sequence"Returns account age, creation ledger, and maturity category.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/age"Returns all trustlines for the account with TOML metadata resolved from the issuer's home domain. Filter by asset code with ?assetCode=, or by sponsorship status with ?sponsored=.
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
assetCode |
string | No | None | Case-insensitive asset code filter. |
sponsored |
boolean | No | None | true returns only trustlines sponsored by another account; false returns only unsponsored trustlines. Omitted returns all. |
# All trustlines
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/trustlines"
# Filter to USDC only
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/trustlines?assetCode=USDC"
# Only sponsored trustlines
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/trustlines?sponsored=true"Returns a compact account summary suitable for dashboards and quick views.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/summary"Lists payments and asset transfers for the account.
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
limit |
integer | No | 20 |
Maximum number of payment records to return per page. |
cursor |
string | No | None | Horizon pagination cursor from a previous response. |
order |
string | No | desc |
Sort order for results: asc or desc. |
assetCode |
string | No | None | Case-insensitive asset code filter that matches all issuers for that code. |
assetIssuer |
string | No | None | Asset issuer filter used only when assetCode is also provided; by itself it has no effect. |
# Latest 20 payments
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/payments"
# First 10 payments in ascending order (oldest first)
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/payments?limit=10&order=asc"
# Filter to USDC payments only
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/payments?assetCode=USDC"
# Paginate to the next page using a cursor
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/payments?limit=20&cursor=163305704040034305"Returns trades executed by the account on the Stellar DEX.
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
limit |
integer | No | 20 |
Maximum number of trade records to return (max: 200). |
cursor |
string | No | None | Horizon pagination cursor from a previous response. |
order |
string | No | desc |
Sort direction: asc (oldest first) or desc (newest first). |
fresh |
boolean | No | false |
Set to true to bypass the server-side cache. |
# Latest trades (newest first)
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/trades"
# Oldest trades first
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/trades?order=asc"
# Paginate through trades
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/trades?limit=50&order=desc&cursor=163305704040034305"
# Bypass cache for live data
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/trades?fresh=true"Returns open DEX offers for the account.
# Open offers (default limit 20)
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/offers"
# Paginate with a larger limit
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/offers?limit=50"Returns historical offer operations (create, update, delete) for the account.
# Most recent offer history
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/offer-history"
# Oldest first
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/offer-history?order=asc&limit=50"Returns a computed risk score and contributing factors for the account.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/risk-score"Returns days since the account's last transaction and a status label (active, idle, or dormant).
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/inactivity"Returns basic account activity analytics derived from the account's transaction history. Includes the total number of successful transactions, average transactions per day over the account's active period, and first/last seen timestamps.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/analytics"Returns subentry usage, remaining capacity, and a warning level when approaching the protocol limit.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/subentry-health"Note: Both
/sponsorshipand/sponsorshipswill be consolidated in a future release (issue #19). For new integrations, prefer/sponsorshipsβ it returns a more structured response.
Returns sponsorship relationships β entries on this account sponsored by others, and accounts this account is sponsoring. The response includes a flat sponsoredEntries array (each entry has type, sponsor, and reserveAmount) and an accountsSponsoring array of account IDs this account sponsors. Use this endpoint for audit or billing workflows where you need the raw list of sponsored ledger entries.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/sponsorship"Preferred endpoint. Will be consolidated with
/sponsorshipin a future release (issue #19).
Returns a typed sponsorship summary with sponsoredBy and sponsoring arrays. Each sponsoredBy entry includes a type, address, sponsor, and reserveAmount. Unlike /sponsorship, this endpoint organises results into distinct typed arrays making it easier to filter by entry type (trustline, signer, data entry, offer) and to display sponsorship direction clearly in a UI.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/sponsorships"Checks whether a specific asset trustline is frozen or partially frozen on the account.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/freeze-status/USDC/GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"Checks whether the account can currently receive a specific asset (trustline exists, is authorized, and has available capacity).
# Check for USDC
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/can-receive/USDC/GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
# Check for native XLM
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/can-receive/XLM/native"Returns transaction volume broken down by asset over the last N days (default: 30, max: 90).
# Last 30 days (default)
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/volume"
# Last 7 days
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/volume?days=7"Returns all liquidity pool positions for the account with calculated share values and equivalent reserves.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/pool-positions"Returns the most frequent payment counterparties for the account.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/counterparties"Searches transaction history filtered by memo content.
# Search by text memo
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/transactions/search?memo=invoice-123"
# Search by numeric ID memo
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/transactions/search?memo=987654321&memo_type=id"Calculates the minimal signer combinations needed to meet each threshold.
curl -X POST "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/multisig-plan" \
-H "Content-Type: application/json" \
-d '{"availableSigners": ["GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"]}'Retrieves transaction history for an account, with pagination.
Retrieves operation history for an account, with pagination.
Checks the confirmation status of up to 20 transaction hashes in a single request. All Horizon lookups are performed in parallel. Each hash in the response includes a found flag; when found is true the entry also carries successful, ledger, createdAt, and fee.
Request body:
{
"hashes": [
"6bc97b244e4eff6e3a1c82e4bab89f6e6b6a3a1e5e6b7e8f9a0b1c2d3e4f5a6b",
"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
]
}curl example:
curl -X POST "http://localhost:3000/transactions/batch-status" \
-H "Content-Type: application/json" \
-d '{
"hashes": [
"6bc97b244e4eff6e3a1c82e4bab89f6e6b6a3a1e5e6b7e8f9a0b1c2d3e4f5a6b",
"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
]
}'Sample response:
{
"success": true,
"data": {
"items": [
{
"hash": "6bc97b244e4eff6e3a1c82e4bab89f6e6b6a3a1e5e6b7e8f9a0b1c2d3e4f5a6b",
"found": true,
"successful": true,
"ledger": 52834901,
"createdAt": "2026-09-20T14:32:11Z",
"fee": "100"
},
{
"hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"found": false
}
],
"total": 2
}
}Key points:
- Body:
hashesβ array of 64-character hex transaction hashes, maximum 20 per request. - Returns
400if more than 20 hashes are supplied or any hash is not a valid 64-character hex string. - When
found: falsethe hash was not found on the network (unconfirmed or invalid). - Per-hash
feeis in stroops (100 stroops = 0.0000100 XLM).
Returns metadata and statistics for a specific Stellar asset.
Searches for assets by code and returns matching results, including issuer details.
These are common Horizon transaction and operation result codes developers may see when submitting transactions to the Stellar network.
| Error code | Meaning | How to fix it |
|---|---|---|
tx_bad_seq |
The transaction sequence number does not match the account's current sequence number. | Reload the source account from Horizon before building the transaction, then rebuild and sign it with the latest sequence number. |
tx_insufficient_fee |
The transaction fee is too low for the number of operations or current network conditions. | Increase the transaction fee, use the current base fee from Horizon, and multiply it by the number of operations in the transaction. |
op_no_trust |
The destination account does not have a trustline for the asset being sent. | Have the destination account create a trustline for the asset before sending the payment. |
op_line_full |
The destination trustline exists but does not have enough remaining limit to receive the asset. | Ask the destination account to raise its trustline limit or reduce the payment amount. |
op_no_destination |
The destination account does not exist on the network. | Create the account first with a createAccount operation, or confirm the destination public key is correct. |
tx_bad_auth |
The transaction is missing a required signature or has an invalid signature. | Sign with every required signer for the source account and operations, and confirm the correct network passphrase is used. |
op_underfunded |
The source account does not have enough funds to complete the operation. | Add funds to the source account, reduce the operation amount, or account for fees and minimum reserve requirements. |
op_low_reserve |
The operation would leave the account below its required minimum XLM reserve. | Keep more XLM in the account, remove unused subentries, or reduce the operation so the account stays above minimum reserve. |
All StellarKit API endpoints follow a standardized JSON response envelope. This ensures developers know exactly what structure to expect from every API call, whether it succeeds or fails.
Every successful response includes the following structure:
{
"success": true,
"data": {},
"meta": {}
}Fields:
success(boolean): Alwaystruefor successful responses.data(object): The actual response payload. Structure varies by endpoint.meta(object): Optional metadata about the response, such as pagination information.
{
"success": true,
"data": {
"accountId": "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN",
"sequence": "12345678",
"xlm": {
"balance": "100.0000000",
"minimumBalance": "1.0000000",
"spendableBalance": "99.0000000"
}
},
"meta": {}
}When an endpoint returns paginated results, the meta field includes pagination details:
{
"success": true,
"data": [
{
"id": "txn_001",
"type": "payment",
"amount": "50.0000000"
},
{
"id": "txn_002",
"type": "payment",
"amount": "25.5000000"
}
],
"meta": {
"cursor": "eyJpZCI6InR4bl8wMDIifQ==",
"limit": 10,
"order": "desc"
}
}When an error occurs, the response structure differs:
{
"success": false,
"error": {
"type": "AccountNotFound",
"message": "Account does not exist on the Stellar network"
}
}Fields:
success(boolean): Alwaysfalsefor error responses.error.type(string): A machine-readable error code for programmatic handling (e.g.,AccountNotFound,InvalidAccountId,ValidationError).error.message(string): A human-readable error message describing what went wrong.
{
"success": false,
"error": {
"type": "ValidationError",
"message": "Invalid Stellar account ID. Must be a valid public key starting with 'G'."
}
}Every request to StellarKit API is assigned a unique identifier for tracing and debugging purposes. This header helps you correlate requests with server logs, monitor application performance, and troubleshoot issues across distributed systems.
The X-Request-ID header is a unique identifier attached to every API request. It serves three primary purposes:
- Request Correlation: Link requests across multiple services and systems using a common identifier.
- Debugging: Find specific requests in server logs by searching for the request ID.
- Monitoring: Track request flow through your application architecture and identify bottlenecks.
If you send a custom request ID:
- StellarKit API uses the
X-Request-IDvalue you provide in your request. - The same ID is returned in the response header.
- Useful for correlating API calls with your internal logging or tracing systems.
If you don't send a request ID:
- StellarKit API automatically generates a UUID v4 (e.g.,
550e8400-e29b-41d4-a716-446655440000). - The generated ID is returned in the response header.
- You can extract and log this ID for future reference.
To send a custom request ID, include the X-Request-ID header in your request:
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN" \
-H "X-Request-ID: my-request-001"The custom ID can be any non-empty string (UUID, alphanumeric, or any format you prefer).
Every response includes the X-Request-ID header. Extract it from the response headers to log, trace, or correlate with other systems:
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN" \
-iResponse (headers shown):
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
...
{
"success": true,
"data": { ... }
}curl -X GET "http://localhost:3000/network-status" \
-H "X-Request-ID: my-health-check-001" \
-H "Accept: application/json"Response headers:
X-Request-ID: my-health-check-001The server echoes back your custom ID, which you can log for correlation with your application logs.
curl -X GET "http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN" \
-s -i | grep X-Request-IDOutput:
X-Request-ID: a1b2c3d4-e5f6-47g8-h9i0-j1k2l3m4n5o6
Save this ID in your logs for debugging later.
const axios = require('axios');
async function fetchAccountWithTracing() {
const requestId = 'my-custom-trace-' + Date.now();
try {
const response = await axios.get(
'http://localhost:3000/account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN',
{
headers: {
'X-Request-ID': requestId
}
}
);
// Extract the request ID from response headers
const responseRequestId = response.headers['x-request-id'];
console.log('Request ID:', responseRequestId);
console.log('Account data:', response.data);
} catch (error) {
console.error('Error:', error.message);
}
}
fetchAccountWithTracing();| Use Case | Example |
|---|---|
| Distributed tracing | Pass the same request ID across multiple microservices to trace a user action end-to-end. |
| Log correlation | Log the request ID alongside your application events, then search server logs by ID to reconstruct the full request flow. |
| Support debugging | When a user reports a problem, ask for the request ID from their client and search the API logs for that ID to understand what happened. |
| Monitoring dashboards | Aggregate request IDs in your monitoring system to track request latency, success rates, and error patterns over time. |
| Rate limiting analysis | Use request IDs to identify which requests contributed to hitting a rate limit and when they occurred. |
- Always log the request ID: Include the
X-Request-IDfrom the response in your application logs. This makes troubleshooting significantly easier. - Use meaningful custom IDs: If you send a custom request ID, use a format that makes sense in your logging context (e.g.,
user-123-action-456). - Correlate across services: In a microservices architecture, propagate the same
X-Request-IDto downstream API calls so you can trace the entire flow. - Attach to error reports: When reporting bugs or API errors, always include the
X-Request-IDso engineers can look up the exact request in the logs.
Several endpoints in the StellarKit API return lists of records and support cursor-based pagination. This allows clients to fetch large datasets efficiently in smaller chunks.
When querying a paginated endpoint, the following optional parameters can be used:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 10 |
The maximum number of records to return in a single page (Max 200, except /account/:id/timeline which has a max of 50). |
order |
string | desc |
The chronological sorting order of the records: desc (newest first) or asc (oldest first). (Not supported by /account/:id/timeline). |
cursor |
string | β | A pointer to a specific location in the dataset from which to resume fetching. |
- Initial Request: Make a request to a paginated endpoint without specifying a
cursor. You can optionally set thelimitandorderparameters. - Metadata Inspection: The successful response contains a
metaobject.- If
nextCursorhas a string value (andhasMoreistrue), there is more data available. - If
nextCursorisnull(or not present), you have reached the end of the dataset.
- If
- Subsequent Request: To fetch the next page of results, make the same API call but include the
nextCursorvalue as thecursorquery parameter.
Below is a step-by-step example showing how to paginate through transaction history for an account.
Request a page of transactions with a limit of 2:
GET /transactions/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN?limit=2Response:
{
"success": true,
"data": [
{
"id": "51234567-001",
"hash": "8f8c4bc6f...",
"ledger": 51234567,
"createdAt": "2026-05-29T12:00:00Z",
"sourceAccount": "GAAZI4..."
},
{
"id": "51234566-002",
"hash": "4a3b8cd12...",
"ledger": 51234566,
"createdAt": "2026-05-29T11:58:00Z",
"sourceAccount": "GAAZI4..."
}
],
"meta": {
"count": 2,
"limit": 2,
"order": "desc",
"nextCursor": "51234566-002",
"hasMore": true
}
}Extract "nextCursor": "51234566-002" from the first response and send it as the cursor query parameter:
GET /transactions/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN?limit=2&cursor=51234566-002Response:
{
"success": true,
"data": [
{
"id": "51234560-001",
"hash": "1d2e3f4a...",
"ledger": 51234560,
"createdAt": "2026-05-29T11:45:00Z",
"sourceAccount": "GAAZI4..."
}
],
"meta": {
"count": 1,
"limit": 2,
"order": "desc",
"nextCursor": null,
"hasMore": false
}
}Since nextCursor is null and hasMore is false, the client knows that there are no additional records to fetch.
The following StellarKit API endpoints support cursor-based pagination:
GET /transactions/:id: Returns paginated transaction history for an account.GET /transactions/:id/operations: Returns paginated operation history for an account.GET /account/:id/payments: Returns paginated payment and create_account operations for an account.GET /account/:id/timeline: Returns a unified chronological timeline of events for an account.GET /account/:id/transactions/search: Searches transaction history filtered by memo content.GET /asset/:code/:issuer/holders: Returns accounts holding a trustline for a specific asset.
Stellar represents assets in different formats depending on the context. This reference explains how native and non-native assets are formatted in API responses and request parameters.
XLM, the native asset of Stellar, is represented in one of two ways:
In most API responses:
{
"asset_type": "native"
}In CODE:ISSUER format (used in DEX and path endpoints):
XLM:native
The keyword native is always used in place of an issuer for XLM, since XLM has no issuer β it is the platform's native currency.
Assets with 4-character or shorter codes are formatted as alphanum4. Examples include USD, EUR, CNY, and custom codes like JPY or EURT.
In API responses:
{
"asset_type": "credit_alphanum4",
"asset_code": "USD",
"asset_issuer": "GBUQWP3BOUZX34ULNQG23RQ6F4BVWCIYU2IYLLU2DENJCAHE4WREQDFT"
}In CODE:ISSUER format:
USD:GBUQWP3BOUZX34ULNQG23RQ6F4BVWCIYU2IYLLU2DENJCAHE4WREQDFT
Assets with codes longer than 4 characters (up to 12) are formatted as alphanum12. Examples include yXLM, abcdef123xyz, and longer custom asset codes.
In API responses:
{
"asset_type": "credit_alphanum12",
"asset_code": "yXLM",
"asset_issuer": "GARDNV3Q7YGH5JEKUJE2QG7MEMBZA47GYUYFQ6EVJYY3YKGU6EBQABE"
}In CODE:ISSUER format:
yXLM:GARDNV3Q7YGH5JEKUJE2QG7MEMBZA47GYUYFQ6EVJYY3YKGU6EBQABE
| Asset | CODE:ISSUER Format | Description |
|---|---|---|
| XLM (Native) | XLM:native |
Stellar's native asset |
| USDC (USD Coin) | USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5 |
Stablecoin issued by Circle |
| yXLM (Yield XLM) | yXLM:GARDNV3Q7YGH5JEKUJE2QG7MEMBZA47GYUYFQ6EVJYY3YKGU6EBQABE |
Yield-bearing XLM wrapper |
| EUR (Euro) | EUR:GBUQWP3BOUZX34ULNQG23RQ6F4BVWCIYU2IYLLU2DENJCAHE4WREQDFT |
Fiat-backed asset |
| BTC (Bitcoin) | BTC:GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ65JJLDHKHRUZI3EUEKMTCH |
Bitcoin-backed asset |
DEX Endpoints:
When querying DEX endpoints like /dex/depth, /dex/spread, /dex/price, or /dex/imbalance, use the CODE:ISSUER format as path parameters:
GET /dex/depth/XLM:native/USDC:GBBD47IF...
GET /dex/spread/XLM:native/USDC:GBBD47IF...
GET /dex/spread/yXLM:GARDN.../USDC:GBBD...
GET /dex/price/XLM:native/USDC:GBBD47IF...?amount=100
Asset Lookup Endpoints:
When querying specific asset information via /asset/:code/:issuer, use the path parameters directly:
GET /asset/USDC/GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
GET /asset/yXLM/GARDNV3Q7YGH5JEKUJE2QG7MEMBZA47GYUYFQ6EVJYY3YKGU6EBQABE
Stellar transactions can include an optional memo field to help identify and organize payments. Each memo type serves a specific use case, and understanding when to use each type is important for building reliable payment systems.
Max Size: N/A (no memo)
Use Case: No memo is attached to the transaction. Use this when the transaction is self-documenting or when no reference is needed. Most system-to-system transfers or internal account movements use MEMO_NONE.
Example:
Transfer: Internal wallet sweep between accounts
Max Size: 28 bytes (approximately 28 ASCII characters)
Use Case: Attach human-readable text that describes the transaction purpose. Common for payment references, invoice numbers, order IDs, or short descriptions. Useful for customer support and transaction reconciliation.
Example:
memo: "INV-2024-0512"
memo: "Salary June 2024"
memo: "Airbot withdrawal"
Max Size: 64-bit unsigned integer (0 to 18,446,744,073,709,551,615)
Use Case: Attach a numeric identifier to a transaction. Use this when you want to reference a specific transaction against a numeric database ID or unique number. Many payment processors use memo IDs to link blockchain transactions to internal records.
Example:
memo_id: 123456789 // Links to customer ID in payment processor
memo_id: 987654321 // References an internal invoice number
memo_id: 1234567890123456 // Unique transaction identifier
Max Size: 32 bytes (SHA-256 hash digest)
Use Case: Attach a cryptographic hash to represent a document, contract, or data commitment. Use this when you need to prove a transaction relates to specific data without disclosing the data itself, or when you want to anchor a transaction to a specific document hash.
Example:
memo_hash: "8f7c4b8c3f8c9e7f4c1a2b3c4d5e6f7g" // Hash of a contract
memo_hash: "sha256(order_data)" // Hash of order details
Max Size: 32 bytes (return hash for payment errors)
Use Case: Used by receivers to send a payment back to the sender, typically when a payment cannot be processed. The memo_return value echoes the hash from the original transaction. This is most common in automated return/refund flows.
Example:
Original transaction memo_hash: "abc123def456"
Return transaction memo_return: "abc123def456" // Echoes original to link refund
Use this decision tree to select the right memo type for your use case:
| Scenario | Recommended Type | Reason |
|---|---|---|
| No reference needed | MEMO_NONE | Simplest, no overhead |
| Readable invoice or order reference | MEMO_TEXT | Human-friendly, easy to track |
| Link to numeric database ID | MEMO_ID | Efficient, indexed database lookups |
| Cryptographic proof of document | MEMO_HASH | Immutable, non-repudiable commitment |
| Automated refund or return flow | MEMO_RETURN | Tracks original transaction |
Use the GET /account/:id/transactions/search endpoint to find transactions by memo content. The endpoint supports filtering by memo type:
GET /account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/transactions/search?memo=INV-2024-0512&memo_type=text
GET /account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/transactions/search?memo=123456789&memo_type=id
Also use the GET /utils/memo endpoint to decode raw memo data from transaction responses:
GET /utils/memo?memo=SGVsbG8gV29ybGQ=&memo_type=text
{
"success": true,
"data": {
"status": "ok",
"service": "StellarKit API",
"version": "1.0.0",
"timestamp": "2024-07-01T12:00:00.000Z",
"network": "testnet",
"uptimeSeconds": 42,
"nodeVersion": "v20.11.0",
"startedAt": "2024-07-01T11:59:18.000Z",
"horizon": {
"status": "ok",
"responseTimeMs": 45,
"network": "testnet"
}
}
}Note: The
versionfield is read dynamically frompackage.jsonat runtime. The value shown above reflects the current release and will update automatically with each new version.
{
"success": true,
"data": {
"network": "testnet",
"latestLedger": {
"sequence": 123456,
"closedAt": "2024-07-01T12:00:00Z",
"transactionCount": 42,
"operationCount": 89
},
"fees": {
"baseFeeInStroops": 100,
"baseFeeInXLM": "0.0000100"
},
"protocol": {
"version": 21
}
}
}{
"success": true,
"data": {
"operationCount": 3,
"perOperation": {
"economy": { "stroops": 100, "xlm": "0.0000100" },
"standard": { "stroops": 200, "xlm": "0.0000200" },
"priority": { "stroops": 500, "xlm": "0.0000500" }
},
"totalFee": {
"economy": { "stroops": 300, "xlm": "0.0000300" },
"standard": { "stroops": 600, "xlm": "0.0000600" },
"priority": { "stroops": 1500, "xlm": "0.0001500" }
}
}
}Fetch fee tiers for a transaction, optionally requesting fresh Horizon data.
curl -X GET "http://localhost:3000/fee-estimate?operations=3&fresh=true"{
"success": true,
"data": {
"operationCount": 3,
"perOperation": {
"economy": { "stroops": 100, "xlm": "0.0000100" },
"standard": { "stroops": 200, "xlm": "0.0000200" },
"priority": { "stroops": 500, "xlm": "0.0000500" }
},
"totalFee": {
"economy": { "stroops": 300, "xlm": "0.0000300" },
"standard": { "stroops": 600, "xlm": "0.0000600" },
"priority": { "stroops": 1500, "xlm": "0.0001500" }
},
"networkStats": {
"lastLedgerBaseFee": 100,
"ledgerCapacityUsage": "0.72",
"p50": "200",
"p95": "500"
},
"recommendation": "Standard tier is recommended for moderate congestion."
}
}Check whether the network is currently in a fee surge period.
curl -X GET "http://localhost:3000/fee-estimate/surge-status"{
"success": true,
"data": {
"isSurging": false,
"avgCapacityUsage": 0.43,
"ledgersAnalyzed": 10,
"suggestedFee": 100,
"suggestedFeeInXLM": "0.0000100",
"recommendation": "Network is operating normally with low congestion.",
"currentNetworkStats": {
"lastLedgerBaseFee": 100,
"ledgerCapacityUsage": "0.43",
"p50Fee": "200",
"p95Fee": "500"
}
}
}Analyze fee trends across the last 50 ledgers.
curl -X GET "http://localhost:3000/fee-estimate/trends"{
"success": true,
"data": {
"ledgersAnalyzed": 50,
"avgBaseFee": 120.34,
"minBaseFee": 100,
"maxBaseFee": 500,
"avgCapacityUsage": 0.65,
"trend": "rising",
"recommendation": "Fees are trending upward. Consider submitting time-sensitive transactions soon or use the priority tier."
}
}Stellar fees are paid in tiny units of XLM called stroops. One XLM equals 10,000,000 stroops, so a fee of 100 stroops is 0.0000100 XLM. Horizon and the Stellar protocol often report fees in stroops because they are exact integers, while wallets and user interfaces usually display the same value as XLM.
Every transaction starts with a base fee per operation. If a transaction contains three operations and the base fee is 100 stroops, the minimum fee is 300 stroops. When the network has spare capacity, transactions that pay the base fee are usually enough. When many transactions are competing for ledger space, Stellar uses surge pricing: transactions that offer higher fees are more likely to be included first.
Capacity usage is the practical signal to watch. Low usage means an economy fee can keep costs minimal. Moderate usage is a good time to choose the standard tier for a stronger chance of timely inclusion. High usage or time-sensitive flows, such as checkout, swaps, or account setup, may need the priority tier so the transaction competes better during surge pricing.
Use the GET /fee-estimate endpoint before submitting transactions. It returns economy, standard, and priority fee tiers in both stroops and XLM, already multiplied by the requested operation count, so clients can choose the lowest fee that still fits their urgency.
XDR (External Data Representation) is the binary serialization format Stellar uses to encode transactions, operations, and results on the ledger. Every transaction that is built, signed, and submitted to the network is serialized into XDR before it travels anywhere. Horizon stores and returns this serialized form alongside the human-readable fields in its responses.
In practice, XDR looks like a long Base64-encoded string β for example:
AAAAAgAAAAA1YmS1mXvUjD7Zq0L0m3i4XN6T8z7j8X7X8X7X8X7XAAAAZAAA...
It is compact and deterministic, which makes it ideal for signing and network transmission, but it is not human-readable on its own. That is why a decoder is useful during development.
You will encounter XDR fields in several places across the StellarKit API:
| Field | Endpoint | Description |
|---|---|---|
envelopeXdr |
GET /transactions/:id, GET /account/:id/transactions/search |
The full signed transaction envelope. Contains the transaction body, all operations, and all signatures. This is the exact bytes that were submitted to the network. |
envelopeXdr |
GET /stream/transactions/:id (SSE stream) |
Same envelope data, returned via the streaming transaction formatter. |
resultXdr |
GET /stream/transactions/:id (SSE stream) |
The transaction result as recorded by the ledger. Encodes whether the transaction succeeded and the result code for each operation. |
resultMetaXdr |
GET /stream/transactions/:id (SSE stream) |
Ledger entry changes produced by the transaction β which accounts, trustlines, offers, or data entries were created, updated, or deleted. |
Most of the time you can ignore XDR fields entirely β the API already surfaces the important data (fee, memo, operation count, success status) as plain JSON. XDR becomes relevant when you need to:
- Inspect raw operations β verify exactly what operations a transaction contained, including source accounts and parameters not surfaced in the summary fields.
- Debug failed transactions β
result_xdrencodes the precise failure reason for each operation, which is more detailed than the top-levelsuccessfulflag. - Audit ledger state changes β
result_meta_xdrshows every ledger entry that was modified, useful for reconciliation and auditing. - Re-sign or resubmit β if you need to take an existing envelope, inspect it, and resubmit or modify it, you start from the
envelopeXdrvalue.
Use the POST /utils/decode-xdr endpoint to convert any Base64-encoded transaction envelope into a readable JSON object. Pass the XDR string in the request body:
POST /utils/decode-xdr
Content-Type: application/json
{ "xdr": "AAAAAgAAAAD..." }
The response breaks the envelope down into its component parts:
{
"success": true,
"data": {
"sourceAccount": "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN",
"fee": "100",
"sequenceNumber": "12345678",
"memo": { "type": "text", "value": "invoice-123" },
"timeBounds": null,
"operations": [
{
"type": "payment",
"destination": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"asset": { "code": "USDC", "issuer": "GA5Z..." },
"amount": "50.0000000"
}
]
}
}The decoder accepts envelopeXdr values from any StellarKit response and works for both testnet and mainnet transactions.
This repository publishes type declarations in types/index.d.ts. Use these types to make your client integration type-safe.
import type { AccountResponse, ApiError } from "stellarkit-api";
async function loadAccount(accountId: string) {
const response = await fetch(`http://localhost:3000/account/${accountId}`);
const payload = await response.json();
if (!response.ok) {
const error = payload as ApiError;
throw new Error(error.error.message);
}
return payload as AccountResponse;
}npm testnpm run lint
npm run lint:fixnpm run seedContributions are welcome! See CONTRIBUTING.md for guidelines on pull requests, issue reporting, and code style.
This project is licensed under the MIT License.
Returns full account details for a Stellar public key.
Example:
GET /account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN
Response:
{
"success": true,
"data": {
"accountId": "GAAZI4...",
"sequence": "12345678",
"xlm": {
"balance": "100.0000000",
"minimumBalance": "1.0000000",
"spendableBalance": "99.0000000"
},
"assets": [...],
"signers": [...],
"flags": {...}
### Understanding Account Sponsorship
Account sponsorship in Stellar allows one account (the sponsor) to cover the base reserve and associated subentry reserves for ledger entries owned or created for another account. Sponsorship makes it possible for custodial services, marketplaces, or onboarding flows to pay ledger costs on behalf of users while sponsorship is active.
- What it means: sponsorship ties specific ledger entries (accounts, trustlines, signers, data entries, offers, claimable balances, etc.) to a sponsoring account that pays the associated reserve while the sponsorship exists.
- Sponsored reserves: while sponsorship is active, the sponsor is responsible for the base reserve required by those sponsored ledger entries. If sponsorship ends, the sponsored account must meet the reserve requirements itself or the network may require cleanup or disallow some entries.
- Why it exists: to simplify onboarding, reduce friction for new users, and enable managed services to cover ledger costs temporarily or indefinitely.
Using this API:
- Inspect sponsorship relationships using `GET /account/:id/sponsorships` (preferred) or `GET /account/:id/sponsorship`. See the [API reference table](#account) for a comparison of the two endpoints and which to use for new integrations.
Note: This repository documents the sponsorship inspection endpoint; it does not change any runtime behavior or add sponsorship logic.
}
}Returns all liquidity pool positions for an account with calculated share values and equivalent reserves.
Example:
GET /account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/pool-positions
Response:
{
"success": true,
"data": [
{
"poolId": "67339253ccd0390f4886b5952d7f8d68f70f61280d908e234190c609c95b6026",
"shares": "1000.0000000",
"sharePercent": "5.2500",
"totalPoolShares": "19047.6190476",
"reserveA": {
"asset": "native",
"totalAmount": "50000.0000000",
"equivalentAmount": "2625.0000000"
},
"reserveB": {
"asset": "USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"totalAmount": "50000.0000000",
"equivalentAmount": "2625.0000000"
},
"feeBp": 30,
"totalTrustlines": 42,
"lastModifiedLedger": 12345678
}
],
"meta": {
"count": 1,
"accountId": "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN"
}
}Key Fields:
shares: The account's pool share tokenssharePercent: Percentage of total pool ownershipequivalentAmount: The account's proportional share of each reserve assetfeeBp: Pool fee in basis points (30 = 0.3%)
Searches transaction history for a Stellar account and filters results by memo content. Useful for developers building payment reference tracking systems.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
memo |
string | Yes | Memo value to search for |
memo_type |
string | No | Filter by memo type: text, id, hash, return |
limit |
number | No | Number of results (default: 10, max: 200) |
cursor |
string | No | Pagination cursor from previous response |
order |
string | No | Sort order: asc or desc (default: desc) |
Example:
GET /account/GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN/transactions/search?memo=invoice-123
GET /account/GAAZI4.../transactions/search?memo=12345&memo_type=id
Response:
{
"success": true,
"data": [
{
"id": "123456789",
"hash": "abc123...",
"ledger": 12345678,
"createdAt": "2024-07-01T12:00:00Z",
"sourceAccount": "GAAZI4...",
"fee": {
"charged": "100",
"account": "GAAZI4..."
},
"feeSummary": {
"chargedInStroops": 100,
"chargedInXLM": "0.0000100",
"perOperationInStroops": 100,
"perOperationInXLM": "0.0000100"
},
"operationCount": 1,
"memoType": "text",
"memo": "invoice-123",
"successful": true,
"envelopeXdr": "..."
}
],
"meta": {
"count": 1,
"limit": 10,
"order": "desc",
"searchQuery": {
"memo": "invoice-123",
"memoType": "any"
},
"nextCursor": "123456789",
"hasMore": false
}
}Search Behavior:
- Text memos: Case-insensitive substring match (e.g., "inv" matches "invoice-123")
- ID/Hash/Return memos: Exact match only
- Transactions with
memo_type: noneare excluded from results - Only successful transactions are returned
Returns paginated transaction history for an account.
Query params:
| Param | Type | Default | Description |
|---|---|---|---|
limit |
number | 10 |
Number of results (max 200) |
order |
string | desc |
asc or desc |
cursor |
string | β | Pagination cursor from previous response |
Returns paginated operation history for an account. Same query params as above.
Returns metadata and statistics for a specific Stellar asset.
Example:
GET /asset/USDC/GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
Calculates the bid-ask spread for a trading pair on the Stellar DEX. Helps developers and traders assess market liquidity at a glance.
Asset Format: CODE:ISSUER (e.g., XLM:native, USDC:GA5Z...)
Example:
GET /dex/spread/XLM:native/USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
GET /dex/spread/USDC:GA5Z.../EURC:GB...
Response:
{
"success": true,
"data": {
"bestBid": {
"price": "0.0850000",
"amount": "1000.0000000"
},
"bestAsk": {
"price": "0.0855000",
"amount": "500.0000000"
},
"spreadAbsolute": "0.0005000",
"spreadPercent": "0.5882",
"midPrice": "0.0852500",
"liquidity": "high",
"orderBookDepth": {
"bids": 25,
"asks": 30,
"totalBidVolume": "50000.0000000",
"totalAskVolume": "45000.0000000",
"totalVolume": "95000.0000000"
}
}
}Key Fields:
bestBid: Highest buy order price and amountbestAsk: Lowest sell order price and amountspreadAbsolute: Difference between ask and bid pricesspreadPercent: Spread as percentage of mid pricemidPrice: Average of best bid and askliquidity: Market depth assessment (high/medium/low)- high: Total volume β₯ 10,000
- medium: Total volume β₯ 1,000
- low: Total volume < 1,000
Error Responses:
400: Invalid asset format404: No order book exists for trading pair
Returns paginated accounts holding a trustline for a specific Stellar asset.
Query params:
| Param | Type | Default | Description |
|---|---|---|---|
limit |
number | 10 |
Number of holders (max 200) |
order |
string | desc |
asc or desc |
cursor |
string | β | Pagination cursor from previous response |
Example:
GET /asset/USDC/GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN/holders
Searches for all assets with a given code across all issuers.
Example:
GET /asset/search?code=USDC
Establishes a live, real-time WebSocket connection to stream Stellar ledger updates. As new ledgers are closed on the Stellar blockchain, the API receives them via the Stellar Horizon SDK subscription, parses them, and immediately broadcasts them to connected WebSocket clients.
Each ledger update is broadcast as a JSON object containing:
{
"sequence": 51234567,
"closedAt": "2026-05-26T20:15:00Z",
"baseFee": 100,
"transactionCount": 54
}Fields:
sequenceβ The ledger sequence number (incremental counter)closedAtβ ISO 8601 timestamp when the ledger closedbaseFeeβ Base fee in stroops for transactions in this ledgertransactionCountβ Number of successful transactions in this ledger
Install wscat globally if you don't have it:
npm install -g wscatConnect to the ledger stream:
wscat -c ws://localhost:3000/stream/ledgersYou'll immediately start receiving live ledger updates as they close on the network.
const ws = new WebSocket("ws://localhost:3000/stream/ledgers");
ws.onopen = () => {
console.log("Connected to StellarKit ledger stream!");
};
ws.onmessage = (event) => {
const ledger = JSON.parse(event.data);
console.log("New ledger closed:", ledger);
console.log(`Ledger ${ledger.sequence} closed at ${ledger.closedAt}`);
console.log(`Transactions: ${ledger.transactionCount}, Base Fee: ${ledger.baseFee} stroops`);
};
ws.onerror = (error) => {
console.error("WebSocket error:", error);
};
ws.onclose = () => {
console.log("WebSocket connection closed.");
};const WebSocket = require("ws");
const ws = new WebSocket("ws://localhost:3000/stream/ledgers");
ws.on("open", () => {
console.log("Connected to StellarKit ledger stream!");
});
ws.on("message", (data) => {
const ledger = JSON.parse(data.toString());
console.log("New ledger:", ledger);
});
ws.on("error", (error) => {
console.error("WebSocket error:", error);
});
ws.on("close", () => {
console.log("Connection closed");
});To create a funded Stellar testnet account for local development/testing, run:
npm run seedThis script:
- generates a new keypair
- funds the public key on Stellar testnet using Friendbot
- prints the public/private keys to the console
Note: keep the printed private key secret.
npm testTests use Jest + Supertest. Coverage report is generated at coverage/.
Contributions are very welcome! This project participates in the Stellar Wave Program on Drips β you can earn rewards for solving open issues.
To contribute:
- Fork the repository
- Create a feature branch:
git checkout -b feat/your-feature - Commit your changes:
git commit -m "feat: add your feature" - Push and open a Pull Request
Please read CONTRIBUTING.md before submitting.
- Contributors β See everyone who has contributed to StellarKit API
- Code of Conduct β Our community standards
stellarkit-api/
βββ docs/ # Supplementary documentation
βββ examples/ # Runnable usage examples
βββ src/
β βββ config/
β β βββ cacheConfig.js # Cache TTL configuration
β β βββ stellar.js # Stellar SDK + Horizon setup
β βββ middleware/
β β βββ apiKeyAuth.js # API key authentication
β β βββ bodySizeLimit.js # Request body size limiting
β β βββ coerceQueryParams.js # Query param type coercion
β β βββ contentTypeValidator.js
β β βββ errorHandler.js # Centralised error formatting
β β βββ etag.js # ETag response caching headers
β β βββ metricsCollector.js # Request metrics collection
β β βββ normalizeAssetCode.js
β β βββ rateLimiter.js # Rate limiting
β β βββ rejectDuplicateQueryParams.js
β β βββ requestId.js # Request ID injection
β β βββ requestLogger.js # HTTP request logging
β β βββ restrictHttpMethods.js
β β βββ routeCounter.js # Route hit counter
β β βββ sanitize.js # Input sanitisation
β β βββ validateRouteParams.js
β β βββ webhookSignatureAuth.js
β βββ routes/
β β βββ account.js # /account endpoints
β β βββ account.counterparties.js
β β βββ accounts.js # /accounts bulk endpoints
β β βββ accountsBulk.js # Additional bulk account ops
β β βββ asset.js # /asset endpoints
β β βββ assetsOverview.js # /assets overview
β β βββ cacheStats.js # /cache/stats endpoint
β β βββ claimableBalances.js # /claimable-balances endpoints
β β βββ dex.js # /dex endpoints
β β βββ feeEstimate.js # /fee-estimate endpoints
β β βββ liquidityPool.js # /liquidity-pools endpoints
β β βββ metrics.js # /metrics endpoints
β β βββ network.js # /network endpoints
β β βββ networkStatus.js # /network-status endpoint
β β βββ soroban.js # /soroban endpoints
β β βββ stellarToml.js # /stellar-toml endpoint
β β βββ stream.js # /stream SSE endpoints
β β βββ transaction.effects.js
β β βββ transactions.js # /transactions endpoints
β β βββ utils.js # /utils endpoints
β β βββ webhooks.js # /webhooks endpoints
β βββ services/
β β βββ cache.js # In-memory cache service
β β βββ contractEventPoller.js
β β βββ metrics.js # Metrics aggregation
β β βββ trustlineChangeDetector.js
β β βββ webhookDelivery.js
β β βββ webhookRegistry.js
β β βββ webhookService.js
β β βββ webhookStore.js
β βββ utils/
β β βββ accountAge.js
β β βββ asset.js
β β βββ assetHelpers.js
β β βββ assetToml.js
β β βββ cache.js
β β βββ contractDeployment.js
β β βββ contractSpec.js
β β βββ crypto.js
β β βββ effectTypes.js
β β βββ errors.js
β β βββ formatAmount.js
β β βββ formatBalance.js
β β βββ formatLedgerSequence.js
β β βββ formatTransaction.js
β β βββ horizonErrors.js
β β βββ horizonHealth.js
β β βββ horizonStatusMapper.js
β β βββ logger.js
β β βββ mapAccountTrade.js
β β βββ mapFeeEstimate.js
β β βββ mapNetworkStatus.js
β β βββ memo.js
β β βββ operationFormatter.js
β β βββ pagination.js
β β βββ parseStellarAmount.js
β β βββ response.js # Response helpers
β β βββ StellarKitError.js
β β βββ toCamelCase.js
β β βββ tomlResolver.js
β β βββ validators.js # Input validation helpers
β βββ index.js # App entry point
β βββ websocket.js # WebSocket stream handler
βββ tests/
β βββ integration/ # End-to-end integration tests
β β βββ account.test.js
β β βββ dex.test.js
β β βββ network.test.js
β βββ middleware/ # Middleware unit tests
β β βββ contentTypeValidator.test.js
β β βββ errorHandler.test.js
β β βββ rejectDuplicateQueryParams.test.js
β β βββ requestId.test.js
β β βββ restrictHttpMethods.test.js
β β βββ sanitize.test.js
β βββ routes/ # Route-level unit tests
β β βββ feeEstimate.test.js
β βββ stream/ # Streaming endpoint tests
β β βββ ledgers.test.js
β β βββ payments.test.js
β β βββ payments.webhook.test.js
β β βββ transactions.test.js
β βββ utils/ # Utility unit tests
β β βββ contractDeployment.test.js
β β βββ crypto.test.js
β β βββ validateCursor.test.js
β β βββ validators.test.js
β βββ account.*.test.js # Account endpoint tests (60+ files)
β βββ asset.*.test.js # Asset endpoint tests
β βββ claimableBalances.*.test.js
β βββ dex.*.test.js
β βββ network.*.test.js
β βββ soroban.*.test.js
β βββ webhooks.*.test.js
β βββ api.test.js # General API smoke tests
β βββ websocket.test.js # WebSocket stream tests
βββ .env.example
βββ package.json
βββ README.md
The Stellar network includes a built-in decentralized exchange (DEX) that lets anyone trade assets directly on the ledger β no third-party exchange required. Understanding how it works helps you build trading tools, wallets, and payment flows that take full advantage of Stellar's on-chain liquidity.
Trading on the Stellar DEX works through offers β on-ledger orders that say "I will sell X amount of asset A for Y amount of asset B." Every offer is stored on the ledger and remains open until it is filled, cancelled, or the account no longer has sufficient balance.
The order book for a trading pair is made up of two sides:
- Bids β buy orders. These are offers from accounts willing to buy the base asset. The best bid is the highest price a buyer is prepared to pay.
- Asks β sell orders. These are offers from accounts willing to sell the base asset. The best ask is the lowest price a seller will accept.
The difference between the best ask and the best bid is the spread. A tight spread signals a liquid, competitive market. A wide spread means fewer participants and potentially worse execution prices.
A trading pair on the Stellar DEX is simply any two assets. Because every asset on Stellar is identified by its code and issuer (e.g., USDC:GA5Z...), any two assets can form a pair. Native XLM is represented as XLM:native.
There is no central listing process β if two accounts create matching offers for any pair of assets, a market exists. This means the DEX supports thousands of pairs simultaneously, including stablecoins, tokenized commodities, and custom project tokens.
A path payment is a special Stellar operation that lets you send one asset while the recipient receives a different asset. Stellar automatically finds a conversion route through one or more intermediate assets on the DEX, executing the trades atomically in a single transaction.
For example, you can send XLM and have the recipient receive USDC β Stellar handles the swap on-chain. If no direct XLM/USDC market exists, Stellar can route through intermediate assets (e.g., XLM β BTC β USDC) to complete the payment.
Path payments are useful because:
- Cross-currency payments β senders and recipients can each hold their preferred asset without needing to share a common currency.
- Atomic execution β the entire conversion and delivery either succeeds completely or fails with no partial state.
- Best-rate routing β Stellar evaluates available paths and selects the one that delivers the most to the recipient for a given source amount (or costs the sender the least for a fixed destination amount).
- Arbitrage detection β circular paths (asset A β ... β asset A) can reveal price inefficiencies across the DEX.
| Endpoint | Description |
|---|---|
GET /dex/spread/:sellAsset/:buyAsset |
Fetches the live order book for a trading pair and returns the best bid, best ask, spread, mid price, and order book depth. Useful for displaying market data or deciding whether conditions are favorable before submitting a trade. |
GET /dex/arbitrage/:assetCode/:assetIssuer |
Uses Horizon's strict-receive path finding to check whether a circular route exists from an asset back to itself. Returns all discovered paths and flags which ones are profitable (source amount less than destination amount). |
Asset format for DEX endpoints: CODE:ISSUER β for example USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN. Use XLM:native for the native asset.
These endpoints wrap Horizon's order book and path-finding APIs, normalizing the responses into the standard StellarKit envelope so you get consistent success, data, and error fields across all calls.
See ROADMAP.md for the project's planned direction across near-term, medium-term, and long-term horizons β including upcoming endpoints, SDK milestones, and ecosystem integrations.
- Stellar Developers Portal
- Stellar JavaScript SDK
- Horizon API Reference
- Stellar Discord
- Stellar Wave Program
The StellarKit API enforces request limits to protect the service and provide fair access for all clients. By default the API applies the following limit per originating IP address:
- Default: 100 requests per 15 minutes (per IP)
When requests are served, the API includes the following response headers so clients can observe and adapt to limits:
RateLimit-Limit: The maximum number of requests allowed in the current window.RateLimit-Remaining: How many requests remain in the current window.RateLimit-Reset: UNIX epoch timestamp (seconds) when the current window resets.
If a client exceeds the configured limit the API will return HTTP 429 Too Many Requests. Example HTTP headers for a 429 response:
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 1710000000
Content-Type: application/json
Example JSON body returned on rate limit exceed:
{
"success": false,
"error": {
"status": 429,
"message": "Too many requests, rate limit exceeded"
}
}Configuration
Rate limiting behavior can be adjusted via environment variables β no code changes are required. The API supports the following variables (defaults shown):
RATE_LIMIT_MAX_REQUESTSβ Maximum requests per window (default:100)RATE_LIMIT_WINDOW_MINUTESβ Window size in minutes (default:15)
After changing environment variables, restart the service for the new values to take effect.
Client recommendations
- Watch
RateLimit-Remainingand proactively delay requests when it is low. - On
429responses, use theRateLimit-Resettimestamp to wait until the window resets. - Implement retries with exponential backoff and jitter instead of tight loops.
Note: This README section documents runtime behavior only β there are intentionally no code changes in this PR.