# Sync transactions

Source: https://fragment.dev/guides/sync-payments

[Documentation index](https://fragment.dev/llms.txt)

<a id="sync-payments"></a>

Transactions made by your product need to be recorded into your Ledger.

This section covers the first of two steps to record transactions in your Ledger:
1. Sync transactions from external financial systems into Fragment using Links.
2. Once synced, you can [reconcile](https://fragment.dev/markdown/guides/reconcile-payments.md) them in your Ledger.

[Visual: links. View on the HTML page.](https://fragment.dev/guides/sync-payments)

<a id="basics"></a>

## Basics

There are two types of Links:
  - Native Links: built-in integrations that automatically sync periodically, via webhook and just-in-time during reconciliation.
  - Custom Links: a set of APIs that let you build a sync process with any external financial system.

For each account in your external financial system, there's a corresponding External Account. External Accounts have a Tx for each transaction in that account.

[Visual: externalAccounts. View on the HTML page.](https://fragment.dev/guides/sync-payments)

After you set up a Link, create a Ledger Account in your Ledger [linked](https://fragment.dev/markdown/guides/reconcile-payments.md#linked-ledger-accounts) to each External Account.

<a id="increase-link"></a>

## Increase Link

To create a Native Link with [Increase](https://increase.com/):

1. Create a Link in the [dashboard](https://dashboard.fragment.dev/go/links/add/increase) and select Increase.
1. Select either your Increase sandbox or production environment.
1. When redirected to Increase, approve the connection.

<a id="stripe-link"></a>

## Stripe Link

To create a Native Link with [Stripe](https://stripe.com/):

1. Create a Link in the [dashboard](https://dashboard.fragment.dev/go/links/add/stripe) and select Stripe.
2. Select either your Stripe test or live environment.
3. When redirected to Stripe, approve the connection.

<a id="stripe-link-handling-fees"></a>

### Handling fees

Every [Balance Transaction](https://docs.stripe.com/api/balance_transactions) at Stripe has two amount fields:

1. The gross amount of the transaction
2. The fee paid for the transaction, to Stripe

To handle this, Stripe Links create two Txs for each Balance Transaction at Stripe: one for the gross amount and the other for the fee. This allows you to account for these amounts independently in your Ledger. The external IDs for these Txs are:

1. `{{stripe_tx_id}}_gross` for the gross amount Tx
2. `{{stripe_tx_id}}_fee` for the fee amount Tx

For example, a Stripe Balance Transaction with ID `txn_123` will result in two Txs in Fragment with external IDs `txn_123_gross` and `txn_123_fee`. You can [reconcile both](https://fragment.dev/markdown/guides/reconcile-payments.md#reconciling-multiple-txs) of these in a single `reconcileTx` call.

<a id="stripe-link-stripe-connect"></a>

### Stripe Connect

To enable Stripe Connect, create a Restricted Access Key (RAK) with the following permissions:

1. Balance - `Read` for both Permissions and Connect Permissions
2. Balance Transaction Sources - `Read` for both Permissions and Connect Permissions
3. Balance Transfers - `Read` for both Permissions and Connect Permissions
4. All Connect Resources - `Read`
5. All Webhook Resources - `Write`. This is used to setup webhooks to Fragment.

Once you have the RAK:

1. Navigate to the [Links](https://dashboard.fragment.dev/go/links) page in the Dashboard
2. Select the Stripe Link
3. Navigate to the `Details` page
4. Submit the RAK you've just generated. You're all setup!

<a id="unit-link"></a>

## Unit Link

To create a Native Link with [Unit](https://unit.co/):

1. Create a API Key at Unit with `accounts` and `transactions` scopes.
1. Create a Link in the [dashboard](https://dashboard.fragment.dev/go/links/add/unit) and select Unit.
1. Enter your Unit Org ID and API Key.

Note: You must be pre-approved by Unit to enable the Native Link.

<a id="custom-link"></a>

## Custom Link

Custom Links allow you to build your own integration between Fragment and any external financial system. Instead of syncing automatically like a Native Link, you sync External Accounts and Txs by calling the API.

Your sync process can periodically enumerate transactions and accounts in your external system or be triggered by webhook.

<a id="custom-link-onboarding"></a>

### Onboarding

You can either create a Link in the [dashboard](https://dashboard.fragment.dev/go/links/add/custom) or using `createCustomLink`:

```graphql title="createCustomLink mutation"
mutation NewCustomLink($name: String!, $ik: SafeString!) {
  createCustomLink(name: $name, ik: $ik) {
    __typename
    ... on CreateCustomLinkResult {
      link {
        id
        name
      }
      isIkReplay
    }
    ... on Error {
      code
      message
    }
  }
}
```

```json title="createCustomLink variables"
{
	"name": "JPM Chase",
	"ik": "dev-chase"
}
```

<a id="custom-link-sync-accounts"></a>

### Sync accounts

If you only have a few accounts, sync them manually as part of bootstrapping your Ledger. 

Otherwise, sync accounts as you create them at the external system. Trigger the sync process either periodically, by webhook, or both.

Once you have a set of accounts to sync, call `syncCustomAccounts`: 

```graphql title="syncCustomAccounts mutation"
mutation CreateBankAccounts(
  $link: LinkMatchInput!
  $accounts: [CustomAccountInput!]!
  ) {
  syncCustomAccounts(link: $link, accounts: $accounts) {
    __typename
    ... on SyncCustomAccountsResult {
      accounts {
        id
        externalId
        name
      }
    }
    ... on Error {
      code
      message
    }
  }
}
```

```json title="syncCustomAccounts variables"
{
  "link": {
    "id": "some-link-id"
  },
  "accounts": [
    {
      "externalId": "bank-account-1",
      "name": "Operational Account"
    },
    {
      "externalId": "bank-account-2",
      "name": "Reserve Account"
    }
  ]
}
```

You should ensure that `externalId` is a stable and unique identifier for each account, within the scope of its Link. This ensures that syncing is idempotent. `externalId` is typically set to the ID of the account at the external system.

Calling `syncCustomAccounts` with a different `name` for an existing `externalId` updates the name of the External Account.

<a id="custom-link-sync-txs"></a>

### Sync Txs

Settled transactions at external financial systems need to be synced to Fragment.

You may also want to sync and reconcile when your product creates a transaction. You should only sync transactions that are settled, not pending or declined.

Once you have a set of transactions to sync, call `syncCustomTxs`: 

```graphql title="syncCustomTxs mutation"
mutation SyncTransactions(
  $link: LinkMatchInput!
  $txs: [CustomTxInput!]!
) {
  syncCustomTxs(link: $link, txs: $txs) {
    __typename
    ... on SyncCustomTxsResult {
      txs {
        id
        externalId
        amount
        date
        description
      }
    }
    ... on Error {
      code
      message
    }
  }
}
```

```json title="syncCustomTxs variables"
{
  "link": { "id": "some-link-id" },
  "txs": [
    {
      "account": {
        "externalId": "bank-account-1"
      },
      "externalId": "tx-1",
      "description": "Processed ACH batch",
      "amount": "-100",
      "posted": "1968-01-01"
    },
    {
      "account": {
        "externalId": "bank-account-2"
      },
      "externalId": "tx-2",
      "description": "Received RTP payment",
      "amount": "100",
      "posted": "1968-01-01T16:45:00Z"
    }
  ]
}
```

You should ensure that `externalId` is a stable and unique identifier for each transaction, within the scope of its account. This identifier enforces idempotentency. 

This identifier is typically the ID of the transaction at the external system. Use the lowest level transaction ID available, not the ID of a higher level construct, like a payment that may be linked to multiple transactions. 
You can sync transactions from different accounts in the same API call, but they must all belong to the same Custom Link.

Calling `syncCustomTxs` with a different `description` for an existing `externalId` updates the description on the existing Tx. `amount` and `posted` timestamp are immutable and cannot be updated. Instead, you can [delete](https://fragment.dev/markdown/guides/sync-payments.md#custom-link-delete-txs) the existing Tx and resync it with the updated fields.

<a id="custom-link-delete-txs"></a>

### Delete Txs

To delete Txs on a Custom Link, call `deleteCustomTxs` with the Fragment IDs of the Txs you want to delete:

```graphql title="deleteCustomTxs mutation"
mutation DeleteCustomTxs($txs: [ID!]!) {
  deleteCustomTxs(txs: $txs) {
    __typename
    ... on DeleteCustomTxsResult {
      txs {
        tx {
          id
          externalId
          posted
          amount
          sequence
          isDeleted
          deletedAt
        }
      } 
    }
    ... on Error {
      code
      message
    }
  }
}
```

You must pass the Fragment ID, not the transaction's External ID used at the external system. The Fragment ID, serves as the idempotency key for this operation. Subsequent calls to `deleteCustomTxs` with the same Fragment ID, will return a success response.

Once a Tx is deleted, you can call `syncCustomTxs` with the same `externalId` and different values. By deleting and resyncing, you can update immutable fields like `amount` and `posted`. The newly synced Tx will have a different Fragment ID, to the original Tx. Calling `deleteCustomTxs` again with the original Fragment ID, will return a success response, but will not delete the newly synced Tx.

Notes:
- You cannot delete Txs that have been reconciled.
- You can delete up to 100 Txs in a single call.
- You can only delete and resync the same Tx External ID up to 10 times.
