To get started developing with FRAGMENT:
Get started by using the MCP or following the guide.
Open the dashboard and create a new MCP Connection. Paste the following prompt into your preferred AI tool:
Use the Fragment MCP to read the quickstart-mcp guide, then follow it end to end.
After this is done you'll have a script that demonstrates the integration against a FRAGMENT Ledger.
A Schema customizes a FRAGMENT Ledger for a specific use-case. Download this toy Schema to begin the quickstart:
{
"key": "quickstart-schema",
"chartOfAccounts": {
"defaultConsistencyConfig": {
"totalBalanceUpdates": "strong"
},
"defaultCurrencyMode": "multi",
"accounts": [
{
"key": "assets",
"type": "asset",
"children": [
{
"key": "receivables"
},
{
"key": "payments",
"currencyMode": "single",
"currency": {
"code": "USD"
},
"payment": {
"enabled": true
}
}
]
},
{
"key": "liabilities",
"type": "liability"
},
{
"key": "income",
"type": "income"
},
{
"key": "expense",
"type": "expense"
}
]
},
"ledgerEntries": {
"types": [
{
"type": "simple-entry",
"lines": [
{
"key": "line-WPZ6bsw08YyW",
"account": {
"path": "assets/receivables"
},
"currency": {
"code": "USD"
},
"amount": "{{gross_amount}}"
},
{
"key": "line-m4spJaQWFqnw",
"account": {
"path": "liabilities"
},
"currency": {
"code": "USD"
},
"amount": "{{gross_amount}}-{{fee_revenue}}"
},
{
"key": "line-bvZiWSE69k4m",
"account": {
"path": "income"
},
"currency": {
"code": "USD"
},
"amount": "{{fee_revenue}}"
}
]
}
]
},
"payments": {
"types": [
{
"type": "quickstart-payment",
"typeVersion": 1,
"status": "active",
"payment": {
"amount": "{{amount}}",
"direction": "payin"
},
"accounting": {
"settled": {
"lines": [
{
"key": "settlement",
"system": "payment_settlement_line",
"account": {
"path": "assets/payments"
},
"currency": {
"code": "USD"
},
"amount": "{{settled_amount}}"
},
{
"key": "fee",
"system": "payment_fee_line",
"account": {
"path": "assets/payments"
},
"currency": {
"code": "USD"
},
"amount": "-{{fragment_fee_amount}}"
},
{
"key": "receivables",
"account": {
"path": "assets/receivables"
},
"currency": {
"code": "USD"
},
"amount": "-{{settled_amount}}"
},
{
"key": "fee-expense",
"account": {
"path": "expense"
},
"currency": {
"code": "USD"
},
"amount": "{{fragment_fee_amount}}"
}
]
}
}
}
]
},
"scenes": [
{
"name": "Simple Scenario",
"events": [
{
"eventType": "entry",
"entry": {
"type": "simple-entry",
"typeVersion": 1,
"parameters": {
"fee_revenue": "250",
"gross_amount": "10000"
}
}
}
]
}
]
}Generate a strongly-typed SDK specific to your Schema using the FRAGMENT CLI.
Install the CLI via NPM or Homebrew:
npm install -g @fragment-dev/clibrew tap fragment-dev/tap &&\
brew install fragment-dev/tap/fragment-cliAuthenticate the CLI against your FRAGMENT workspace:
fragment loginGenerate an SDK for your language:
fragment gen-graphql \
--path=quickstart-schema.jsonc \
--output=queries.graphql &&\
npm install --save @fragment-dev/node-client &&\
npx fragment-node-client-codegen \
--input=queries.graphql \
--outputFilename=fragment-client.tsCreate an API client in the dashboard.
Initialize your FRAGMENT client using the generated SDK and API client credentials:
import {
createFragmentClient
} from '@fragment-dev/node-client';
import {
getSdk
} from './fragment-client';
const fragment = createFragmentClient({
params: {
clientId: "<Client ID>",
clientSecret: "<Client Secret>",
apiUrl: "<API URL>",
authUrl: "<OAuth URL>",
scope: "<OAuth Scope>",
},
getSdk,
});To deploy your Ledger:
import { readFileSync } from 'node:fs';
// Load the Schema you downloaded with `fragment get-schema`.
const schema = JSON.parse(
readFileSync('quickstart-schema.jsonc', 'utf8')
);
const { storeSchema } = await fragment.storeSchema({
schema,
})
const { createLedger } = await fragment.createLedger({
ik: `test-ledger`,
ledger: {
name: `quickstart ledger`,
},
schemaKey: schema.key,
})Post a Ledger Entry and read the balance of the assets/receivables Ledger Account.
import { ReadBalanceConsistencyMode } from '@fragment-dev/node-client/types';
// Post the `simple-entry` Ledger Entry type
// with the required parameters
const { addLedgerEntry } = await fragment.PostSimpleEntry({
ik: `quickstart-entry`,
// The Ledger the Ledger Entry should post to.
ledgerIk: `test-ledger`,
gross_amount: '10000', // $100.00
fee_revenue: '250', // $2.50
})
const { ledgerAccount } = await fragment.getLedgerAccountBalance({
ledgerIk: `test-ledger`,
path: `assets/receivables`,
balanceConsistencyMode: ReadBalanceConsistencyMode.Strong,
})
console.log(ledgerAccount.balance);Collect the assets/receivables balance with a Payment in two steps:
createPayment from your backend.Payment to the Checkout component in your frontend.Create the Payment using the generated SDK. Set amount to the gross_amount of the Ledger Entry you posted:
// Create a Payment of the `quickstart-payment` Payment Type
const { createPayment } = await fragment.CreatePaymentQuickstartPaymentPayin({
ik: `quickstart-payment`,
ledgerIk: `test-ledger`,
amount: '10000', // $100.00
});
if (createPayment.__typename !== 'CreatePaymentResult') {
throw new Error(createPayment.message);
}
// Pass the Payment to your frontend.
const { payment } = createPayment;Install FRAGMENT's frontend SDK in your React app:
npm install --save @fragment-dev/payment-elementsMount the Checkout component inside PaymentElements and pass the created Payment to it:
import {
Checkout,
PaymentElements,
usePayment,
type Payment,
} from '@fragment-dev/payment-elements';
const PayButton = () => {
const { confirm, canConfirm, isConfirming } = usePayment();
return (
<button
type="button"
disabled={!canConfirm || isConfirming}
onClick={() => confirm()}
>
Pay
</button>
);
};
export const CheckoutPage = ({
payment,
email,
}: {
payment: Payment;
email: string;
}) => (
<PaymentElements>
<Checkout
payment={payment}
billingDetails={{ email }}
onConfirmed={() => console.log('Payment confirmed')}
onError={(message) => console.error(message)}
>
<PayButton />
</Checkout>
</PaymentElements>
);Use the test card 4242 4242 4242 4242 with a future expiry date and any three-digit CVC. When the Payment settles, its settled Ledger Entry moves the balance from assets/receivables to assets/payments.
const { ledgerAccount: receivables } = await fragment.getLedgerAccountBalance({
ledgerIk: `test-ledger`,
path: `assets/receivables`,
balanceConsistencyMode: ReadBalanceConsistencyMode.Strong,
});
console.log(receivables.balance);
const { ledgerAccount: payments } = await fragment.getLedgerAccountBalance({
ledgerIk: `test-ledger`,
path: `assets/payments`,
balanceConsistencyMode: ReadBalanceConsistencyMode.Strong,
});
console.log(payments.balance);