Your Ledger should track payments made by your product. To do this, you need to represent every account you hold at external financial systems in your Ledger.
.
This section covers the second of two steps to record payments in your Ledger:
To represent external accounts in your Ledger, create a Ledger Account and link it to an External Account.
Any Ledger Line that posts to a linked Ledger Account must match a synced transaction in its corresponding External Account.
To link a Ledger Account to an External Account, set linkedAccount
on a Ledger Account in your Schema:
{
"chartOfAccounts": {
"accounts": [
{
"key": "assets-root",
"name": "Assets",
"type": "asset",
"children": [{
"key": "operating",
"name": "Operating Bank",
"linkedAccount": {
"linkId": "some-link-id",
"externalId": "bank-account-1"
}
}]
}
]
}
}
The linkId
comes from the Link you create in the dashboard. The externalId
is the ID of the account at your external financial system.
The CLI automatically replaces variables with ${ENV_VAR}
syntax when running fragment store-schema
. This lets you use different External Accounts per environment:
{
"chartOfAccounts": {
"accounts": [
{
"key": "assets-root",
"name": "Assets",
"type": "asset",
"children": [{
"key": "operating",
"name": "Operating Bank",
"linkedAccount": {
"linkId": "${BANK_LINK_ID}",
"externalId": "${BANK_ACCOUNT_ID}"
}
}]
}
]
}
}
To link a Ledger Account template to an External Account, parameterize the linkedAccount
field:
{
"chartOfAccounts": {
"accounts": [
{
"key": "assets-root",
"name": "Assets",
"type": "asset",
"children": [{
"key": "operating",
"name": "Operating Bank",
"template": true,
"linkedAccount": {
"linkId": "{{BANK_LINK_ID}}",
"externalId": "{{BANK_ACCOUNT_ID}}"
}
}]
}
]
}
}
These parameters will be required when posting a Ledger Entry to a linked Ledger Account. This can be useful if you're creating bank accounts per customer, for example.
To reconcile a transaction from an external system, follow the same two-step process as when posting Ledger Entries:
Ledger Entries posting to a linked Ledger Account must specify the Tx from the External Account tied to the Ledger Account. This lets FRAGMENT know which transaction to reconcile:
{
"key": "schema-key",
"chartOfAccounts": {...},
"ledgerEntries": {
"types": [
{
"type": "user_funds_account_via_link",
"description": "Funding {{user_id}} for {{funding_amount}}",
"lines": [
{
"account": { "path": "assets/operating" },
"key": "funds_arrive_in_bank",
"tx": {
"externalId": "{{bank_transaction_id}}"
}
},
{
"account": { "path": "liabilities/users:{{user_id}}/available" },
"key": "increase_user_balance"
}
]
}
]
}
}
Notes:
bank_transaction_id
represents the ID of the transaction at the external system.Instead of calling addLedgerEntry
, use the reconcileTx
mutation:
mutation ReconcileTx(
$entry: LedgerEntryInput!
) {
reconcileTx(
entry: $entry
) {
... on ReconcileTxResult {
entry {
type
created
posted
}
lines {
amount
key
description
account {
path
}
}
}
... on Error {
code
message
}
}
}
The parameters look similar to addLedgerEntry
. Specify the Ledger Entry type
that you are using and provide the parameters
defined in the Schema:
{
"entry": {
"type": "user_funding",
"ledger": {
"ik": "quickstart-ledger"
},
"parameters": {
"txId": "tx_12345",
"customerId": "customer-1"
}
}
}
ik
and posted
are optional when posting Ledger Entries with reconcileTx
:
ik
: the Tx.externalId
is used to ensure that reconciling a transaction is idempotentposted
: the timestamp of the Ledger Entry is taken from the Tx to ensure the Ledger mirrors the external systemBook transfers are a common type of money movement which produce two Txs at your bank as part of one payment.
To reconcile multiple Txs using reconcileTx
:
{
"key": "schema-key",
"chartOfAccounts": {...},
"ledgerEntries": {
"types": [
{
"type": "user_funds_account_via_link",
"description": "Funding {{user_id}} for {{funding_amount}}",
"lines": [
{
"key": "funds_arrive_in_operating_bank",
"account": { "path": "assets/operating-bank-account" },
"tx": {
"externalId": "{{bank_transaction_id}}"
}
},
{
"key": "funds_leave_holding_bank",
"account": { "path": "assets/holding-bank-account" },
"tx": {
"externalId": "{{bank_transaction_id}}"
}
}
]
}
]
}
}
Notes:
posted
timestamp.Transactions synced to FRAGMENT but not reconciled to a Ledger are considered unreconciled.
You can query unreconciled transactions in a linked Ledger Account using the unreconciledTxs
field on theLedgerAccount
.
query GetUnreconciledTxs (
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
id
unreconciledTxs {
nodes {
id
description
amount
externalId
externalAccountId
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
The variables specify the path
of the linked Ledger Account you are querying and the Ledger it belongs to.
{
"ledgerAccount": {
"path": "assets/operating",
"ledger": {...}
}
}
unreconciledTxs
is eventually consistent, so if you've recently transacted at a Native Link or just synced manually for a Custom Link, you may not see the transaction in the query results immediately.