Fragment is the Ledger API for engineers that move money. Stop wrangling payment tables, debugging balance errors and hacking together data pipelines. Start shipping the features that make a difference.
Using npm:
npm install @fragment-dev/node-clientUsing yarn:
yarn add @fragment-dev/node-clientTo instantiate a client, call createFragmentClient. You can generate credentials using the Fragment dashboard.
import { createFragmentClient } from "@fragment-dev/node-client";
const fragment = createFragmentClient({
params: {
apiUrl: "api url from dashboard",
clientId: "client id from dashboard",
clientSecret: "client secret from dashboard",
scope: "scope from dashboard",
authUrl: "auth url from dashboard",
},
});Read the Using custom queries section to learn how to use your own GraphQL queries with the SDK.
To post a Ledger Entry defined in your schema:
await fragment.addLedgerEntry({
ik: "some-ik",
ledgerIk: "your-ledger-ik",
type: "user_funds_account",
posted: "1968-01-01T16:45:00Z",
parameters: {
user_id: "user-1",
funding_amount: "200",
},
});To post a Ledger Entry with lines defined at runtime:
await fragment.addLedgerEntryRuntime({
ik: "some-ik",
ledgerIk: "your-ledger-ik",
posted: "1968-01-01T16:45:00Z",
type: "funding_runtime",
lines: [
{
account: { path: "assets/banks/user-cash" },
key: "funds_arrive_in_bank",
amount: "100",
},
{
account: { path: "liabilities/users:user-1/available" },
key: "increase_user_balance",
amount: "100",
},
],
tags: [{ key: "service", value: "funding-service" }],
groups: [
{ key: "user", value: "user-1" },
{ key: "workflow", value: "wf-123" },
],
});When your Schema defines Ledger Entry types with lines, the SDK generates type-specific methods for posting those entries. These methods follow the naming convention Post<EntryType> where the entry type name is converted to PascalCase.
For example, an entry type user-funds-account generates a method PostUserFundsAccount:
await fragment.PostUserFundsAccount({
ik: "some-ik",
ledgerIk: "your-ledger-ik",
amount: "200",
});The SDK handles different naming conventions:
- Hyphenated:
user-funds-account→PostUserFundsAccount - CamelCase:
fundingSettlement→PostFundingSettlement - Underscore:
payment_processing→PostPaymentProcessing
When your schema defines multiple versions of the same entry type using typeVersion, the SDK generates separate methods for each version. Version 1 uses the base method name, and subsequent versions append _v2, _v3, etc.
For example, an entry type user-funds-account with typeVersion: 1 and typeVersion: 2 generates:
PostUserFundsAccountfor version 1PostUserFundsAccount_v2for version 2
// Post version 1 entry
await fragment.PostUserFundsAccount({
ik: "entry-ik-1",
ledgerIk: "your-ledger-ik",
amount: "200",
});
// Post version 2 entry (with additional feeAmount parameter)
await fragment.PostUserFundsAccount_v2({
ik: "entry-ik-2",
ledgerIk: "your-ledger-ik",
amount: "200",
feeAmount: "10",
});Each version can have different parameters and line structures, and the generated methods will reflect those differences.
To sync transaction using a Custom Link:
import { CurrencyCode } from "@fragment-dev/node-client";
await fragment.syncCustomAccounts({
linkId: "custom-link-id",
accounts: [
{
externalId: "operating-account",
name: "Operating Bank Account",
currency: {
code: CurrencyCode.Usd,
},
},
],
});
await fragment.syncCustomTxs({
linkId: "custom-link-id",
txs: [
{
externalId: "tx-123",
description: "Test user funding",
account: {
externalId: "operating-account",
linkId: "custom-link-id",
},
amount: "100",
currency: {
code: CurrencyCode.Usd,
},
posted: "1968-01-01",
},
],
});To reconcile a transaction:
await fragment.reconcileTx({
ledgerIk: "your-ledger-ik",
type: "funding_settlement",
parameters: {
user_id: "user-1",
net_amount: "99",
fee_amount: "1",
link_id: "stripe",
link_account_id: "stripe-balance",
link_tx_id: "tx_456",
},
});To reconcile a Ledger Entry with lines defined at runtime:
await fragment.reconcileTxRuntime({
ledgerIk: "your-ledger-ik",
type: "funding_settlement_runtime",
lines: [
{
key: "funds_arrive_at_stripe",
account: { path: "assets/banks/stripe" },
amount: "100",
tx: {
externalId: "tx_456",
},
},
{
key: "increase_user_balance",
account: { path: "liabilities/users:user-1/available" },
amount: "100",
},
],
tags: [{ key: "service", value: "funding-service" }],
groups: [
{ key: "user", value: "user-1" },
{ key: "workflow", value: "wf-123" },
],
});const { schema } = await fragment.getSchema({
key: schemaKey,
});const { ledger } = await fragment.getLedger({
ik: "your-ledger-ik",
});const { ledgerEntry } = await fragment.getLedgerEntry({
ik: "card_swipe_a",
ledgerIk: "your-ledger-ik",
});To get a Ledger Account with its balances:
const { ledgerAccount } = await fragment.getLedgerAccountBalance({
ledgerIk: "your-ledger-ik",
path: "assets/receivables/user:user-1",
});To get a Ledger Account with its lines:
const { ledgerAccount } = await fragment.getLedgerAccountLines({
ledgerIk: "your-ledger-ik",
path: "assets/receivables/user:user-1",
});To retrieve the Ledger Accounts in a Ledger:
const result = await fragment.listLedgerAccounts({
ledgerIk: "your-ledger-ik",
});
assert(result.ledger?.ledgerAccounts?.nodes, "Failed to list ledger accounts");To retrieve Ledger Accounts with balances:
const result = await fragment.listLedgerAccountBalances({
ledgerIk: "your-ledger-ik",
});
assert(result.ledger?.ledgerAccounts?.nodes, "Failed to list ledger accounts");To retrieve multi-currency Ledger Accounts with balances:
const result = await fragment.listMultiCurrencyLedgerAccountBalances({
ledgerIk: "your-ledger-ik",
});
assert(result.ledger?.ledgerAccounts?.nodes, "Failed to list ledger accounts");While the SDK comes with GraphQL queries out of the box, you may want to customize these queries for your product. In order to do that:
- Define your custom GraphQL queries in a GraphQL file. For example, in
custom-queries.graphql:
mutation getSchemaName($key: SafeString!) {
schema(schema: { key: $key }) {
key
name
}
}- Run
fragment-node-client-codegento generate the client for your custom queries.
Using npx:
npx fragment-node-client-codegen -i custom-queries.graphql -o src/fragment-client.tsUsing yarn:
yarn fragment-node-client-codegen -i custom-queries.graphql -o src/fragment-client.ts- Pass the
getSdkfunction from the generated file tocreateFragmentClientto use your custom query!
import { createFragmentClient } from "@fragment-dev/node-client";
import { getSdk } from './src/fragment-client.ts';
const fragment = createFragmentClient({
params: {
apiUrl: "api url from dashboard",
clientId: "client id from dashboard",
clientSecret: "client secret from dashboard",
scope: "scope from dashboard",
authUrl: "auth url from dashboard",
},
getSdk,
});
// The returned client includes the pre-defined queries as well.
await fragment.storeSchema({ ... });
await fragment.getSchemaName({ key: "a-schema-key" });