# Modeling Banking on Twisp

Design and Implement bank-like core accounting on Twisp.


Source: https://www.twisp.com/docs/guides/neobanking-guide

## Context

Organizations that offer financial products as part of their core product offering have a wide variety of service providers to bring products to market. There are vertical banking integrations such as Unit, which provide turn key treasury, lending and card operations. Other companies are  more specialized, card processors like Marqeta and Lithic and ACH and payments companies like Sila and Stripe.  As a company building on top of these service providers you're often going through a "Crawl, Walk, Run" maturation cycle:

```mermaid
timeline
    title Maturation Cycle of Fintech
    Crawl : Lean on BaaS providers
          : Shallow banking relationships
          : Use case limited
    Walk  : Use specialized processors
          : Deep banking relationships
          : Innovation unlocked
    Run   : In house capability
          : Becoming a bank feasible
          : Highest leverage
```

The goal as a fintech is to prove your product and get to the "Run" stage as fast as possible.  One of the first systems you'll need to build and operate well is a core account system. Twisp is a core accounting system designed to provide a system of record for organizations that build financial products and services.

In this document we'll dive into how to start modeling deposit accounts, credit accounts and their interaction with various payment instruments, which you'll find applicable to any stage of development.

## Scope

In this document we'll cover:

1. Deposit and Credit accounts
3. Card transactions
4. ACH

We will design a number of "system level" accounts for operational and double entry accounting purposes. And we'll build out sample chart of accounts for a business neobanking vertical that we can iterate on toward your use case.

## Chart of Accounts

The chart of accounts in your fintech system is the building block for how you want balances to "roll up" for both end users and for your platform.  It is helpful to think of these charts as separate ones that interact with each other when funds are spent:

1. **End User**: Track end user activity and control how balances "roll up" for end users of our system.
2. **Platform**: Track settlements, revenue and operational concerns of the platform.

### End User

We're going to cover two basic kinds of accounts:

- **Deposit Accounts**: DDA accounts are stores of value for banking customers. Debit instruments are hooked up to these accounts and these accounts are considered liabilities to the platform, because the platform owes the deposits to the account holders.
- **Credit Accounts**: Credit accounts are accounts with a line of credit (as we'll see later on, literally a line on an account) coupled with a payable account.  Customers will spend money and then they owe the account issuer funds back by a certain date, and the payable account accrues interest.

Twisp models both accounts similarly:

- An account set to represent the total balance of the account
- A default account to represent debits/credits incurred by the account holder

The difference between the two will be the [Balance Normality](/docs/accounting-core/chart-of-accounts#credit-normal-and-debit-normal) of the accounts involved, and the credit accounts will have an extra account to hold the credit line.

#### Deposit Accounts

The chart of accounts for end users will model a `Customer -> Account -> Card` hiearchical relationship.  This hierarchical relationship we'll model via [Account Sets](/docs/reference/graphql/types/object#account-set).  Each individual entity we'll create via a two objects as a building block for creating the chart of accounts:

1. An [Account Set](/docs/reference/graphql/types/object#account-set) to encapsulate the _total balance_ of the entity in question.
2. A default [Account](/docs/reference/graphql/types/object#account) as a member of the above account set for writing entries to the entity.

```mermaid
graph BT
  SET[/Entity Account Set\]
  DEFAULT[/Entity Default Account\]

  DEFAULT --> SET
```

This building block can be encapsulated in via a GraphQL mutation:

**Request**

```graphql
mutation CreateEntityAccount(
  $accountSetId: UUID!
  $accountId: UUID!
  $code: String!
  $description: String
  $metadata: JSON
  $journalId: UUID! = "00000000-0000-0000-0000-000000000000"
  $accountSetName: String! = "Entity Account Set"
  $accountName: String! = "Entity Default Account"
) {
  createAccountSet(
    input: {
      accountSetId: $accountSetId
      name: $accountSetName
      description: $description
      metadata: $metadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  createAccount(
    input: {
      accountId: $accountId
      name: $accountName
      description: $description
      code: $code
      accountSetIds: [$accountSetId]
      metadata: $metadata
    }
  ) {
    accountId
  }
}
```
**Response**

```json
{
  "data": {
    "createAccountSet": {
      "accountSetId": "37279a24-976e-4a16-805d-953245e5606f"
    },
    "createAccount": {
      "accountId": "08ed9947-6775-47a7-81d3-b1cd84f4455a"
    }
  }
}
```
**Variables**

```json
{
  "accountSetId": "37279a24-976e-4a16-805d-953245e5606f",
  "accountId": "08ed9947-6775-47a7-81d3-b1cd84f4455a",
  "code": "37279a24-976e-4a16-805d-953245e5606f.DEFAULT",
  "description": "Account for Entity",
  "metadata": {}
}
```

Once we have this building block, we can now model the chart of accounts creating and adding to the appropriate account set.

Consider the use case of onboarding a customer, followed by creating a deposit account and issuing a debit card; After onboarding we'd expect to have the following end user chart of accounts:

```mermaid
graph BT
  CUST[/Customer Account Set\]
  CUST_DEF[/Default Customer Account\]
  DEPOSIT[/Deposit Account Set\]
  DEPOSIT_DEF[/Default Deposit Account\]
  CARD[/Card Account Set\]
  CARD_DEF[/Default Card Account\]

  CUST_DEF & DEPOSIT --> CUST
  DEPOSIT_DEF & CARD --> DEPOSIT
  CARD_DEF --> CARD
```

The coordination of creating an account in Twisp can occur in many ways.  For example, it may be in response to webhooks from a BaaS provider:

| Webhook Received   | Actions in Twisp                                           |
|--------------------|------------------------------------------------------------|
| `customer.created` | Create customer account                                    |
| `account.created`  | Create deposit account, add to customer account            |
| `card.created`     | Create card account, add to corresponding deposit account. |

Another might be creating Twisp entities via a state machine process, such as Temporal or Step Functions, coordinating activity with a number of vendors:

**Request**

```graphql
# OnboardCustomerDepositAccountCard does exactly that:
# - Creates  Account Set and Default Account for Customer
# - Creates Account Set and Default Account for Deposit Account
# - Adds Deposit Account to Customer
# - Creates Account Set and Default Account for Card
# - Adds Card to Deposit Account
# This includes adding Unit metadata json. This can be
# broken up into multiple mutations in response to a webhook
# or used as-is in some kind of long running coordinated process
# to onboard a customer.
mutation OnboardCustomerDepositAccountCard(
  $customerAccountSetId: UUID!
  $customerAccountId: UUID!
  $customerAccountCode: String!
  $depositAccountSetId: UUID!
  $depositAccountId: UUID!
  $depositAccountCode: String!
  $cardAccountSetId: UUID!
  $cardAccountId: UUID!
  $cardAccountCode: String!
  $description: String
  $customerMetadata: JSON
  $depositMetadata: JSON
  $cardMetadata: JSON
  $journalId: UUID! = "00000000-0000-0000-0000-000000000000"
  $customerAccountSetName: String! = "Customer Account Set"
  $customerAccountName: String! = "Customer Default Account"
  $depositAccountSetName: String! = "Deposit Account Set"
  $depositAccountName: String! = "Deposit Default Account"
  $cardAccountSetName: String! = "Card Account Set"
  $cardAccountName: String! = "Card Default Account"
) {
  # Onboard Customer
  customerSet: createAccountSet(
    input: {
      accountSetId: $customerAccountSetId
      name: $customerAccountSetName
      description: $description
      metadata: $customerMetadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  customerDefault: createAccount(
    input: {
      accountId: $customerAccountId
      name: $customerAccountName
      description: $description
      code: $customerAccountCode
      accountSetIds: [$customerAccountSetId]
      metadata: $customerMetadata
    }
  ) {
    accountId
  }

  # Onboard Deposit Account
  depositSet: createAccountSet(
    input: {
      accountSetId: $depositAccountSetId
      name: $depositAccountSetName
      description: $description
      metadata: $depositMetadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  depositDefault: createAccount(
    input: {
      accountId: $depositAccountId
      name: $depositAccountName
      description: $description
      code: $depositAccountCode
      metadata: $depositMetadata
    }
  ) {
    accountId
  }
  depositToCustomer: addToAccountSet(
    id: $customerAccountSetId
    member: { memberType: ACCOUNT_SET, memberId: $depositAccountSetId }
  ) {
    accountSetId
  }
  defaultDepositToSet: addToAccountSet(
    id: $depositAccountSetId
    member: { memberType: ACCOUNT, memberId: $depositAccountId }
  ) {
    accountSetId
  }

  # Onboard Card
  cardSet: createAccountSet(
    input: {
      accountSetId: $cardAccountSetId
      name: $cardAccountSetName
      description: $description
      metadata: $cardMetadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  cardDefault: createAccount(
    input: {
      accountId: $cardAccountId
      name: $cardAccountName
      description: $description
      code: $cardAccountCode
      metadata: $cardMetadata
    }
  ) {
    accountId
  }
  cardToDeposit: addToAccountSet(
    id: $depositAccountSetId
    member: { memberType: ACCOUNT_SET, memberId: $cardAccountSetId }
  ) {
    accountSetId
  }
  defaultCardToSet: addToAccountSet(
    id: $cardAccountSetId
    member: { memberType: ACCOUNT, memberId: $cardAccountId }
  ) {
    accountSetId
  }
}
```
**Response**

```json
{
  "data": {
    "customerSet": {
      "accountSetId": "6669bc2c-84c1-4b76-9985-a33adeb00eae"
    },
    "customerDefault": {
      "accountId": "ee5a7fa7-f336-4f70-b7e8-60473562e179"
    },
    "depositSet": {
      "accountSetId": "80659068-3ac1-452a-b2da-2566e95283f8"
    },
    "depositDefault": {
      "accountId": "f0e4d71e-fc44-41ea-8e10-bd4b039885f1"
    },
    "depositToCustomer": {
      "accountSetId": "6669bc2c-84c1-4b76-9985-a33adeb00eae"
    },
    "defaultDepositToSet": {
      "accountSetId": "80659068-3ac1-452a-b2da-2566e95283f8"
    },
    "cardSet": {
      "accountSetId": "f141c872-7c66-4e6e-982c-fa1c45d94766"
    },
    "cardDefault": {
      "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9"
    },
    "cardToDeposit": {
      "accountSetId": "80659068-3ac1-452a-b2da-2566e95283f8"
    },
    "defaultCardToSet": {
      "accountSetId": "f141c872-7c66-4e6e-982c-fa1c45d94766"
    }
  }
}
```
**Variables**

```json
{
  "customerAccountSetId": "6669bc2c-84c1-4b76-9985-a33adeb00eae",
  "customerAccountId": "ee5a7fa7-f336-4f70-b7e8-60473562e179",
  "customerAccountCode": "6669bc2c-84c1-4b76-9985-a33adeb00eae.DEFAULT",
  "customerMetadata": {
    "type": "businessCustomer",
    "id": "1742784",
    "attributes": {
      "createdAt": "2024-03-06T18:53:48.431Z",
      "name": "Michael Parsons",
      "address": {
        "street": "Street name 1",
        "city": "City",
        "state": "CA",
        "postalCode": "11111",
        "country": "US"
      },
      "phone": {
        "countryCode": "1",
        "number": "5555555555"
      },
      "stateOfIncorporation": "CA",
      "ein": "123456789",
      "entityType": "Corporation",
      "contact": {
        "fullName": {
          "first": "Michael",
          "last": "Parsons"
        },
        "email": "michael@twisp.com",
        "phone": {
          "countryCode": "1",
          "number": "5555555555"
        }
      },
      "tags": {},
      "authorizedUsers": [],
      "status": "Active"
    },
    "relationships": {
      "org": {
        "data": {
          "type": "org",
          "id": "4975"
        }
      }
    }
  },
  "depositAccountSetId": "80659068-3ac1-452a-b2da-2566e95283f8",
  "depositAccountId": "f0e4d71e-fc44-41ea-8e10-bd4b039885f1",
  "depositAccountCode": "80659068-3ac1-452a-b2da-2566e95283f8.DEFAULT",
  "depositMetadata": {
    "id": "2890313",
    "type": "depositAccount",
    "attributes": {
      "hold": 0,
      "name": "Michael Parsons",
      "tags": {
        "purpose": "checking"
      },
      "status": "Open",
      "balance": 0,
      "currency": "USD",
      "available": 0,
      "createdAt": "2024-03-13T20:47:56.985Z",
      "updatedAt": "2024-03-13T20:47:56.985Z",
      "routingNumber": "812345678",
      "depositProduct": "checking"
    },
    "relationships": {
      "org": {
        "data": {
          "id": "4975",
          "type": "org"
        }
      },
      "bank": {
        "data": {
          "id": "1",
          "type": "bank"
        }
      },
      "customer": {
        "data": {
          "id": "1742784",
          "type": "customer"
        }
      }
    }
  },
  "cardAccountSetId": "f141c872-7c66-4e6e-982c-fa1c45d94766",
  "cardAccountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "cardAccountCode": "f141c872-7c66-4e6e-982c-fa1c45d94766.DEFAULT",
  "cardMetadata": {
    "id": "1790431",
    "type": "businessDebitCard",
    "attributes": {
      "bin": "424242459",
      "tags": {},
      "email": "richard@piedpiper.com",
      "phone": {
        "number": "5555555555",
        "countryCode": "1"
      },
      "status": "Inactive",
      "address": {
        "city": "Palo Alto",
        "state": "CA",
        "street": "5230 Newell Rd",
        "country": "US",
        "postalCode": "94303"
      },
      "fullName": {
        "last": "Hendricks",
        "first": "Richard"
      },
      "createdAt": "2024-03-13T20:56:00.442Z",
      "dateOfBirth": "2001-08-10",
      "last4Digits": "2860",
      "expirationDate": "2028-03",
      "shippingAddress": {
        "city": "Palo Alto",
        "state": "CA",
        "street": "5230 Newell Rd",
        "country": "US",
        "postalCode": "94303"
      }
    },
    "relationships": {
      "account": {
        "data": {
          "id": "2890313",
          "type": "account"
        }
      },
      "customer": {
        "data": {
          "id": "1742784",
          "type": "customer"
        }
      }
    }
  },
  "description": "Onboard customer, deposit account and card"
}
```

This can be broken down into reusable pieces in case you want to add multiple deposit accounts or cards to a particular customer:

**Request**

```graphql
mutation CreateCustomer(
  $customerAccountSetId: UUID!
  $customerAccountId: UUID!
  $customerAccountCode: String!
  $journalId: UUID! = "00000000-0000-0000-0000-000000000000"
  $customerAccountSetName: String! = "Customer Account Set"
  $customerAccountName: String! = "Customer Default Account"
  $customerMetadata: JSON
  $description: String = "Create a customer."
) {
  customerSet: createAccountSet(
    input: {
      accountSetId: $customerAccountSetId
      name: $customerAccountSetName
      description: $description
      metadata: $customerMetadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  customerDefault: createAccount(
    input: {
      accountId: $customerAccountId
      name: $customerAccountName
      description: $description
      code: $customerAccountCode
      accountSetIds: [$customerAccountSetId]
      metadata: $customerMetadata
    }
  ) {
    accountId
  }
}
```
**Response**

```json
{
  "data": {
    "customerSet": {
      "accountSetId": "83fff3de-3bea-4340-9d92-d099ada571a0"
    },
    "customerDefault": {
      "accountId": "91378e87-7a08-403b-ae47-ad46f7385ede"
    }
  }
}
```
**Variables**

```json
{
  "customerAccountSetId": "83fff3de-3bea-4340-9d92-d099ada571a0",
  "customerAccountId": "91378e87-7a08-403b-ae47-ad46f7385ede",
  "customerAccountCode": "83fff3de-3bea-4340-9d92-d099ada571a0.DEFAULT",
  "customerMetadata": {
    "type": "businessCustomer",
    "id": "1742784",
    "attributes": {
      "createdAt": "2024-03-06T18:53:48.431Z",
      "name": "Brian Parsons",
      "address": {
        "street": "Street name 1",
        "city": "City",
        "state": "CA",
        "postalCode": "11111",
        "country": "US"
      },
      "phone": {
        "countryCode": "1",
        "number": "5555555555"
      },
      "stateOfIncorporation": "CA",
      "ein": "123456789",
      "entityType": "Corporation",
      "contact": {
        "fullName": {
          "first": "Brian",
          "last": "Parsons"
        },
        "email": "brian@twisp.com",
        "phone": {
          "countryCode": "1",
          "number": "5555555555"
        }
      },
      "tags": {},
      "authorizedUsers": [],
      "status": "Active"
    },
    "relationships": {
      "org": {
        "data": {
          "type": "org",
          "id": "4975"
        }
      }
    }
  }
}
```

**Request**

```graphql
mutation CreateDepositAccount(
  $customerAccountSetId: UUID!
  $depositAccountSetId: UUID!
  $depositAccountId: UUID!
  $depositAccountCode: String!
  $journalId: UUID! = "00000000-0000-0000-0000-000000000000"
  $depositAccountSetName: String! = "Deposit Account Set"
  $depositAccountName: String! = "Deposit Default Account"
  $depositMetadata: JSON
  $description: String = "create a deposit account."
) {
  depositSet: createAccountSet(
    input: {
      accountSetId: $depositAccountSetId
      name: $depositAccountSetName
      description: $description
      metadata: $depositMetadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  depositDefault: createAccount(
    input: {
      accountId: $depositAccountId
      name: $depositAccountName
      description: $description
      code: $depositAccountCode
      metadata: $depositMetadata
    }
  ) {
    accountId
  }
  depositToCustomer: addToAccountSet(
    id: $customerAccountSetId
    member: { memberType: ACCOUNT_SET, memberId: $depositAccountSetId }
  ) {
    accountSetId
  }
  defaultDepositToSet: addToAccountSet(
    id: $depositAccountSetId
    member: { memberType: ACCOUNT, memberId: $depositAccountId }
  ) {
    accountSetId
  }
}
```
**Response**

```json
{
  "data": {
    "depositSet": {
      "accountSetId": "8801ced3-e6a3-4af6-b01a-514473051d4e"
    },
    "depositDefault": {
      "accountId": "9963d6d2-2458-4f67-8bed-7604a5e0281e"
    },
    "depositToCustomer": {
      "accountSetId": "83fff3de-3bea-4340-9d92-d099ada571a0"
    },
    "defaultDepositToSet": {
      "accountSetId": "8801ced3-e6a3-4af6-b01a-514473051d4e"
    }
  }
}
```
**Variables**

```json
{
  "customerAccountSetId": "83fff3de-3bea-4340-9d92-d099ada571a0",
  "depositAccountSetId": "8801ced3-e6a3-4af6-b01a-514473051d4e",
  "depositAccountId": "9963d6d2-2458-4f67-8bed-7604a5e0281e",
  "depositAccountCode": "8801ced3-e6a3-4af6-b01a-514473051d4e.DEFAULT",
  "depositMetadata": {
    "id": "2890313",
    "type": "depositAccount",
    "attributes": {
      "hold": 0,
      "name": "Brian Parsons",
      "tags": {
        "purpose": "checking"
      },
      "status": "Open",
      "balance": 0,
      "currency": "USD",
      "available": 0,
      "createdAt": "2024-03-13T20:47:56.985Z",
      "updatedAt": "2024-03-13T20:47:56.985Z",
      "routingNumber": "812345678",
      "depositProduct": "checking"
    },
    "relationships": {
      "org": {
        "data": {
          "id": "4975",
          "type": "org"
        }
      },
      "bank": {
        "data": {
          "id": "1",
          "type": "bank"
        }
      },
      "customer": {
        "data": {
          "id": "1742784",
          "type": "customer"
        }
      }
    }
  }
}
```

**Request**

```graphql
mutation CreateCard(
  $depositAccountSetId: UUID!
  $cardAccountSetId: UUID!
  $cardAccountId: UUID!
  $cardAccountCode: String!
  $cardAccountSetName: String! = "Card Account Set"
  $cardAccountName: String! = "Card Default Account"
  $journalId: UUID! = "00000000-0000-0000-0000-000000000000"
  $cardMetadata: JSON
  $description: String = "Create a card."
) {
  cardSet: createAccountSet(
    input: {
      accountSetId: $cardAccountSetId
      name: $cardAccountSetName
      description: $description
      metadata: $cardMetadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  cardDefault: createAccount(
    input: {
      accountId: $cardAccountId
      name: $cardAccountName
      description: $description
      code: $cardAccountCode
      metadata: $cardMetadata
    }
  ) {
    accountId
  }
  cardToDeposit: addToAccountSet(
    id: $depositAccountSetId
    member: { memberType: ACCOUNT_SET, memberId: $cardAccountSetId }
  ) {
    accountSetId
  }
  defaultCardToSet: addToAccountSet(
    id: $cardAccountSetId
    member: { memberType: ACCOUNT, memberId: $cardAccountId }
  ) {
    accountSetId
  }
}
```
**Response**

```json
{
  "data": {
    "cardSet": {
      "accountSetId": "151d8647-09af-4d5a-ac32-39fcd55d2454"
    },
    "cardDefault": {
      "accountId": "f6318c3e-4996-4d88-ba7a-0f66cb04302b"
    },
    "cardToDeposit": {
      "accountSetId": "8801ced3-e6a3-4af6-b01a-514473051d4e"
    },
    "defaultCardToSet": {
      "accountSetId": "151d8647-09af-4d5a-ac32-39fcd55d2454"
    }
  }
}
```
**Variables**

```json
{
  "depositAccountSetId": "8801ced3-e6a3-4af6-b01a-514473051d4e",
  "cardAccountSetId": "151d8647-09af-4d5a-ac32-39fcd55d2454",
  "cardAccountId": "f6318c3e-4996-4d88-ba7a-0f66cb04302b",
  "cardAccountCode": "151d8647-09af-4d5a-ac32-39fcd55d2454.DEFAULT",
  "cardMetadata": {
    "id": "1790431",
    "type": "businessDebitCard",
    "attributes": {
      "bin": "424242459",
      "tags": {},
      "email": "richard@piedpiper.com",
      "phone": {
        "number": "5555555555",
        "countryCode": "1"
      },
      "status": "Inactive",
      "address": {
        "city": "Palo Alto",
        "state": "CA",
        "street": "5230 Newell Rd",
        "country": "US",
        "postalCode": "94303"
      },
      "fullName": {
        "last": "Hendricks",
        "first": "Richard"
      },
      "createdAt": "2024-03-13T20:56:00.442Z",
      "dateOfBirth": "2001-08-10",
      "last4Digits": "2860",
      "expirationDate": "2028-03",
      "shippingAddress": {
        "city": "Palo Alto",
        "state": "CA",
        "street": "5230 Newell Rd",
        "country": "US",
        "postalCode": "94303"
      }
    },
    "relationships": {
      "account": {
        "data": {
          "id": "2890313",
          "type": "account"
        }
      },
      "customer": {
        "data": {
          "id": "1742784",
          "type": "customer"
        }
      }
    }
  }
}
```

Regardless of the mechanics of how/when new accounts are added, we suggest association of your own internal and third party identifiers on Twisp entities so that you can easily look up items in the future.

> **Tip:**
>
> Picking identifiers for Twisp and ensuring there is enough data in Twisp to look up by Unit identifiers, or your own system internal identifiers is paramount for keeping data consistent.  Twisp provides a few different mechanisms to aid in this:
>
> - Accounts have an `externalId` field that will enforce uniqueness.
> - Accounts and Account Sets have a `metadata` field that's useful for populating with metadata from external systems, especially identifiers
> - Utilize [UUID v5](https://www.sohamkamani.com/uuid-versions-explained/#v5-non-random-uuids) to generate deterministic identifiers for Twisp entities that correspond to their Unit counterparts.

#### Credit Accounts

Credit accounts are modeled slightly differently than deposit accounts:

```mermaid
graph BT
  SET[/Credit Balance Account Set\]
  PAYABLE[/Credit Payable Account Set\]
  DEFAULT[/Credit Default Account\]
  LINE[/Credit Line\]

  DEFAULT --> PAYABLE
  LINE & PAYABLE --> SET
```

In this case a second account, `Credit Line` is added. This account is where we book a single entry to define the limit of the entire credit account.  The other accounts function identically with the
normality of the `Credit Payable` accounts being **Debit Normal**:

| Entry ID | Account | Amount | Direction | Credit Balance | Payable Balance |
|----------|---------|--------|-----------|----------------|-----------------|
| 1        | Line    | $1000  | Credit    | $1000          | $0              |
| 2        | Default | $500   | Debit     | $500           | $500            |
| 3        | Default | $250   | Credit    | $750           | $250            |
| 4        | Default | $10    | Debit     | $740           | $260            |

This gives you two significant balances:

1. The `Credit Balance` set gives you a balance that you can use for authorization decisions.
2. The `Credit Payable` set gives you a balance that is owed to you by the customer.

**Request**

```graphql
mutation CreateCreditAccount(
  $balanceSetId: UUID!
  $payableSetId: UUID!
  $defaultAccountId: UUID!
  $lineAccountId: UUID!
  $defaultCode: String!
  $lineCode: String!
  $metadata: JSON
  $journalId: UUID! = "00000000-0000-0000-0000-000000000000"
) {
  balanceSet: createAccountSet(
    input: {
      accountSetId: $balanceSetId
      name: "Credit Balance"
      description: "Credit balance roll up for this credit account."
      metadata: $metadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  payableSet: createAccountSet(
    input: {
      accountSetId: $payableSetId
      name: "Payable Balance"
      description: "Outstanding balance owed by account holder."
      metadata: $metadata
      journalId: $journalId
    }
  ) {
    accountSetId
  }
  lineAcct: createAccount(
    input: {
      accountId: $lineAccountId
      name: "Credit Line"
      description: "Apply credit limit to this account."
      code: $lineCode
      metadata: $metadata
    }
  ) {
    accountId
  }
  defaultAccount: createAccount(
    input: {
      accountId: $defaultAccountId
      name: "Default"
      description: "Default credit account"
      code: $defaultCode
      metadata: $metadata
    }
  ) {
    accountId
  }
}
```
**Response**

```json
{
  "data": {
    "balanceSet": {
      "accountSetId": "3b270302-a595-4942-a166-d5e2ab8d6a19"
    },
    "payableSet": {
      "accountSetId": "3d0d7d8c-19c7-4835-98ea-979077e0972c"
    },
    "lineAcct": {
      "accountId": "b7ad3970-c408-4a01-83af-8f1523b407b5"
    },
    "defaultAccount": {
      "accountId": "154396fb-5114-4a9b-afb2-9276dab92570"
    }
  }
}
```
**Variables**

```json
{
  "balanceSetId": "3b270302-a595-4942-a166-d5e2ab8d6a19",
  "payableSetId": "3d0d7d8c-19c7-4835-98ea-979077e0972c",
  "defaultAccountId": "154396fb-5114-4a9b-afb2-9276dab92570",
  "lineAccountId": "b7ad3970-c408-4a01-83af-8f1523b407b5",
  "defaultCode": "CREDIT.3b270302-a595-4942-a166-d5e2ab8d6a19.DEFAULT",
  "lineCode": "LINE.3b270302-a595-4942-a166-d5e2ab8d6a19.DEFAULT",
  "metadata": {}
}
```

### Platform Accounts

When operating a fintech, your organization will partner with a bank which will configure one or more actual bank accounts in order to support your operations. These include, but are not limited to:

| Account                 | Description                                                                             |
|-------------------------|-----------------------------------------------------------------------------------------|
| Suspense Account        | An account to post transactions with unknown accounts to.                               |
| ACH Settlement          | Settlement account for ACHs.                                                            |
| Bill Pay Settlement     | Settlement account for Bill Pay.                                                        |
| Foreign Checks Account  | Settlement account for foriegn checks.                                                  |
| Courtesy Credit Account | Operational accounts for crediting accounts via customer service interactions.          |
| Charge Off Account      | Operational account to write off closing balances on uncollectable accounts.            |
| Fraud Losses            | Operational account to write off losses for fraud.                                      |
| Levies & Garnishments   | Account to collect levies and garnishments of funds.                                    |
| Cashiers Check          | Settlement account for cashiers checks.                                                 |
| Card Disputes           | Reserve account for handling card related disputes.                                     |
| ACH Disputes            | Reserve account for handling ACH related disputes.                                      |
| Interchange Revenue     | Revenue account for shared  interchange.                                                |
| Collected Fee Revenue   | Revenue account for fees collected from accounts.                                       |
| FBO                     | "For Benefit Of", omnibus accounts for specific purpose.  For example, virtual wallets. |
| Cash                    | An asset account that represents all funds created in the system.                       |

These accounts are often the "other side" of your double entry accounting and you could have multiple of these accounts across your various banking partners.  For the purpose of this document, we'll consider a system with:

- Cash account for assets
- Card Settlement for a single BIN
- ACH Settlement account for single bank partner
- Suspense Account
- Disputes
- Revenue

> **Tip:**
>
> There will be a few well known identifiers for these settlement accounts that will be pervasively used through the system.
>
> We recommend creating a library with human readable codes that allow fast look ups to use as parameters to tran codes.

**Request**

```graphql
mutation PlatformAccounts {
  cash: createAccount(
    input: {
      accountId: "db07e5cf-6cd7-4629-a952-9613578cd8ea"
      code: "ASSETS.CASH"
      name: "Cash account"
      description: "Cash account representing all assets the platform."
      normalBalanceType: DEBIT
      config: { enableConcurrentPosting: true }
    }
  ) {
    accountId
  }
  cardSettlement: createAccount(
    input: {
      accountId: "fabdce1f-6eb9-4630-9472-6338ed3dc6a2"
      code: "SETTLEMENT.VISA"
      name: "Visa Settlement Account"
      description: "Settlement account to use for Visa cards on bin 41200."
      config: { enableConcurrentPosting: true }
    }
  ) {
    accountId
  }
  achSettlement: createAccount(
    input: {
      accountId: "7c923aed-a5fc-4ded-b2f0-57db45a8b545"
      code: "SETTLEMENT.ACH"
      name: "ACH Settlement Account"
      description: "Settlement account to use for Bank Partner 1."
      config: { enableConcurrentPosting: true }
    }
  ) {
    accountId
  }
  suspenseAccount: createAccount(
    input: {
      accountId: "6e341e23-e35f-488c-b947-b7b8839f4c00"
      code: "SUSPENSE"
      name: "Suspense Account"
      description: "Account to post to when an account doesnt exist or is in a non-postable state."
      config: { enableConcurrentPosting: true }
    }
  ) {
    accountId
  }
  disputes: createAccount(
    input: {
      accountId: "08f304d5-6a63-40b9-a182-bfb732994b15"
      code: "DISPUTES"
      name: "Disputes Account"
      description: "Reserve account for dispute resolution."
      config: { enableConcurrentPosting: true }
    }
  ) {
    accountId
  }
  revenueAccount: createAccount(
    input: {
      accountId: "4d79af07-acd9-4a44-8291-78a573ced41d"
      code: "REVENUE"
      name: "Revenue Account"
      description: "Interchange and other fees collected from customer accounts."
      config: { enableConcurrentPosting: true }
    }
  ) {
    accountId
  }
}
```
**Response**

```json
{
  "data": {
    "cash": {
      "accountId": "db07e5cf-6cd7-4629-a952-9613578cd8ea"
    },
    "cardSettlement": {
      "accountId": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2"
    },
    "achSettlement": {
      "accountId": "7c923aed-a5fc-4ded-b2f0-57db45a8b545"
    },
    "suspenseAccount": {
      "accountId": "6e341e23-e35f-488c-b947-b7b8839f4c00"
    },
    "disputes": {
      "accountId": "08f304d5-6a63-40b9-a182-bfb732994b15"
    },
    "revenueAccount": {
      "accountId": "4d79af07-acd9-4a44-8291-78a573ced41d"
    }
  }
}
```

## Transaction Workflows

When processing transactions, to end users they feel like a singular event. I swipe my card the purchase is made.  However that singular event is often a series
of transactions, depending on how the swipe was made  (Dual vs Single message auth), or if the merchant uses multiple clearings.  Card processing can be challenging as
the underlying protocol allows for a wide variety of behaviors.

The same is true with many other types of transactions, such as ACH's or checks. The logically singular event may have a lifecycle that encompasses many transactions. These lifecycles we call
transaction workflows and here we present a simplified model that you can adapt to your particular card and ach providers.

### Primitives

There are a few different primitives built into Twisp for posting transactions that will help us model these the workflows:

- [Tran Codes](/docs/accounting-core/encoded-transactions) define entries are posted for a particular transaction type.
- [postTransaction](/docs/reference/graphql/mutations#post-transaction) allows you to post a transaction with a specific tran code.
- [voidTransaction](/docs/reference/graphql/mutations#void-transaction) posts the entries required to reverse any transaction.
- [workflows](/docs/reference/graphql/mutations#workflows) allow composition of multiple transaction operations to fulfill specific use cases.

Each of these transaction flows will be composed together of one or more of the above primitives. These workflows are not prescriptive, but are intended to illustrate the concepts to the point where they can be adapted to your own use case and production usage.

## Card Authorizations and Transactions

The ISO-8583 specification defines how merchants and issuers interact with each other via card networks.  This communication protocol is implemented by a wide variety of vendors, and for the
purposes of this document we're going to explore the key workflows required, define the [tran codes](/docs/accounting-core/encoded-transactions) required to post transaction and illustrate how to
utilize those tran codes to fulfill card authorization work flows.

### Tran Codes

At the heart of processing transactions in Twisp are the Tran Codes required to make journal entries.  Here is a set of tran codes that allow you to completely model card authorization and settlement/clearing.

| Code              | Description                                                 |
|-------------------|-------------------------------------------------------------|
| CARD_HOLD         | Post at pending layer between settlement and card accounts. |
| CARD_SETTLE       | Post at settled layer between settlement and card accounts. |
| CARD_HOLD_VOID    | Optional $0 entries at pending layer                        |
| CARD_HOLD_REPLACE | Identical to CARD_HOLD, but provides labeling differences   |
| CARD_DECLINE      | Optional $0 entries at pending layer for declines           |

**Request**

```graphql
mutation CardTranCodes(
  $cardHold: TranCodeInput!
  $cardHoldVoid: TranCodeInput!
  $cardHoldReplace: TranCodeInput!
  $cardSettle: TranCodeInput!
  $cardDecline: TranCodeInput!
) {
  cardHold: createTranCode(input: $cardHold) {
    ...TC
  }

  cardHoldVoid: createTranCode(input: $cardHoldVoid) {
    ...TC
  }

  cardHoldReplace: createTranCode(input: $cardHoldReplace) {
    ...TC
  }

  cardSettle: createTranCode(input: $cardSettle) {
    ...TC
  }

  cardDecline: createTranCode(input: $cardDecline) {
    ...TC
  }
}

fragment TC on TranCode {
  tranCodeId
  code
  description
  params {
    name
    type
    default
    description
  }
  transaction {
    effective
    journalId
    correlationId
    externalId
    description
    metadata
  }
  entries {
    entryType
    accountId
    layer
    direction
    units
    currency
    description
    metadata
    condition
  }
}
```
**Response**

```json
{
  "data": {
    "cardHold": {
      "tranCodeId": "9f4f3293-539d-4c81-b3b9-3c8d94fa67ba",
      "code": "CARD_HOLD",
      "description": "Place an authorization hold on an account for the amount.",
      "params": [
        {
          "name": "account",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccount",
          "type": "UUID",
          "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
          "description": "The settlement account to use."
        },
        {
          "name": "journal",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "STRING",
          "default": null,
          "description": "The decimal amount of the hold."
        },
        {
          "name": "currency",
          "type": "STRING",
          "default": "USD",
          "description": "The currency of the hold amount."
        },
        {
          "name": "direction",
          "type": "STRING",
          "default": "DEBIT",
          "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
        },
        {
          "name": "correlation",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "Effective date for the transaction."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journal",
        "correlationId": "params.correlation",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'CARD_HOLD_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
          "accountId": "uuid(params.account)",
          "layer": "PENDING",
          "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
          "units": "params.amount",
          "currency": "params.currency",
          "description": "'Card hold placed on account in parameters.'",
          "metadata": "{}",
          "condition": null
        },
        {
          "entryType": "'CARD_HOLD_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
          "accountId": "uuid(params.settlementAccount)",
          "layer": "PENDING",
          "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
          "units": "params.amount",
          "currency": "params.currency",
          "description": "'Card hold placed in settlement account.'",
          "metadata": "{}",
          "condition": null
        }
      ]
    },
    "cardHoldVoid": {
      "tranCodeId": "218f19fc-e283-4f5b-90f6-02fd99e48e5c",
      "code": "CARD_HOLD_VOID",
      "description": "Posts $0 entries to an account indicating a card hold was voided. Use in conjuction with voidTransaction.",
      "params": [
        {
          "name": "account",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccount",
          "type": "UUID",
          "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
          "description": "The settlement account to use."
        },
        {
          "name": "journal",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "STRING",
          "default": null,
          "description": "The decimal amount of the hold."
        },
        {
          "name": "currency",
          "type": "STRING",
          "default": "USD",
          "description": "The currency of the hold amount."
        },
        {
          "name": "direction",
          "type": "STRING",
          "default": "DEBIT",
          "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
        },
        {
          "name": "correlation",
          "type": "STRING",
          "default": null,
          "description": "'Correlation identifier to group related transactions.'"
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "Effective date for the transaction."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journal",
        "correlationId": "params.correlation",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'CARD_HOLD_VOID_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
          "accountId": "uuid(params.account)",
          "layer": "PENDING",
          "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
          "units": "decimal('0')",
          "currency": "params.currency",
          "description": "'Card hold placed on account in parameters.'",
          "metadata": "{}",
          "condition": null
        },
        {
          "entryType": "'CARD_HOLD_VOID_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
          "accountId": "uuid(params.settlementAccount)",
          "layer": "PENDING",
          "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
          "units": "decimal('0')",
          "currency": "params.currency",
          "description": "'Card hold placed in settlement account.'",
          "metadata": "{}",
          "condition": null
        }
      ]
    },
    "cardHoldReplace": {
      "tranCodeId": "b0b6cb20-7c9d-4e48-8179-caa9c06e44d7",
      "code": "CARD_HOLD_REPLACE",
      "description": "Posts a hold at pending layer indicating the hold amount changed to this value. Use in conjuction with voidTransaction.",
      "params": [
        {
          "name": "account",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccount",
          "type": "UUID",
          "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
          "description": "The settlement account to use."
        },
        {
          "name": "journal",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "STRING",
          "default": null,
          "description": "The decimal amount of the hold."
        },
        {
          "name": "currency",
          "type": "STRING",
          "default": "USD",
          "description": "The currency of the hold amount."
        },
        {
          "name": "direction",
          "type": "STRING",
          "default": "DEBIT",
          "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
        },
        {
          "name": "correlation",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "Effective date for the transaction."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journal",
        "correlationId": "params.correlation",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'CARD_HOLD_REPLACE_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
          "accountId": "uuid(params.account)",
          "layer": "PENDING",
          "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
          "units": "params.amount",
          "currency": "params.currency",
          "description": "'Card hold placed on account in parameters.'",
          "metadata": "{}",
          "condition": null
        },
        {
          "entryType": "'CARD_HOLD_REPLACE_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
          "accountId": "uuid(params.settlementAccount)",
          "layer": "PENDING",
          "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
          "units": "params.amount",
          "currency": "params.currency",
          "description": "'Card hold placed in settlement account.'",
          "metadata": "{}",
          "condition": null
        }
      ]
    },
    "cardSettle": {
      "tranCodeId": "2e1f3ed4-0f0e-467a-82f7-715c2bcd97ef",
      "code": "CARD_SETTLE",
      "description": "Post a card settlement at the settled layer.",
      "params": [
        {
          "name": "account",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccount",
          "type": "UUID",
          "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
          "description": "The settlement account to use."
        },
        {
          "name": "journal",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "STRING",
          "default": null,
          "description": "The decimal amount of the hold."
        },
        {
          "name": "currency",
          "type": "STRING",
          "default": "USD",
          "description": "The currency of the hold amount."
        },
        {
          "name": "direction",
          "type": "STRING",
          "default": "DEBIT",
          "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
        },
        {
          "name": "correlation",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "Effective date for the transaction."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journal",
        "correlationId": "params.correlation",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'CARD_SETTLE_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
          "accountId": "uuid(params.account)",
          "layer": "SETTLED",
          "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
          "units": "params.amount",
          "currency": "params.currency",
          "description": "'Card hold placed on account in parameters.'",
          "metadata": "{}",
          "condition": null
        },
        {
          "entryType": "'CARD_SETTLE_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
          "accountId": "uuid(params.settlementAccount)",
          "layer": "SETTLED",
          "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
          "units": "params.amount",
          "currency": "params.currency",
          "description": "'Card hold placed in settlement account.'",
          "metadata": "{}",
          "condition": null
        }
      ]
    },
    "cardDecline": {
      "tranCodeId": "2b954d71-01a8-4021-82a1-c78aa1b607bd",
      "code": "CARD_DECLINE",
      "description": "Note a card decline by posting a $0 transaction. Use in conjuction with voidTransaction.",
      "params": [
        {
          "name": "account",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccount",
          "type": "UUID",
          "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
          "description": "The settlement account to use."
        },
        {
          "name": "journal",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "STRING",
          "default": null,
          "description": "The decimal amount of the hold."
        },
        {
          "name": "currency",
          "type": "STRING",
          "default": "USD",
          "description": "The currency of the hold amount."
        },
        {
          "name": "direction",
          "type": "STRING",
          "default": "DEBIT",
          "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
        },
        {
          "name": "correlation",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "Effective date for the transaction."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journal",
        "correlationId": "params.correlation",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'CARD_DECLINE_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
          "accountId": "uuid(params.account)",
          "layer": "PENDING",
          "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
          "units": "decimal('0')",
          "currency": "params.currency",
          "description": "'Card hold placed on account in parameters.'",
          "metadata": "{}",
          "condition": null
        },
        {
          "entryType": "'CARD_DECLINE_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
          "accountId": "uuid(params.settlementAccount)",
          "layer": "PENDING",
          "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
          "units": "decimal('0')",
          "currency": "params.currency",
          "description": "'Card hold placed in settlement account.'",
          "metadata": "{}",
          "condition": null
        }
      ]
    }
  }
}
```
**Variables**

```json
{
  "cardHold": {
    "tranCodeId": "9f4f3293-539d-4c81-b3b9-3c8d94fa67ba",
    "code": "CARD_HOLD",
    "description": "Place an authorization hold on an account for the amount.",
    "params": [
      {
        "name": "account",
        "type": "UUID",
        "default": null,
        "description": "The account to place the hold on."
      },
      {
        "name": "settlementAccount",
        "type": "UUID",
        "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
        "description": "The settlement account to use."
      },
      {
        "name": "journal",
        "type": "UUID",
        "default": "00000000-0000-0000-0000-000000000000",
        "description": "The journal to post transactions to."
      },
      {
        "name": "amount",
        "type": "STRING",
        "default": null,
        "description": "The decimal amount of the hold."
      },
      {
        "name": "currency",
        "type": "STRING",
        "default": "USD",
        "description": "The currency of the hold amount."
      },
      {
        "name": "direction",
        "type": "STRING",
        "default": "DEBIT",
        "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
      },
      {
        "name": "correlation",
        "type": "STRING",
        "default": null,
        "description": "Correlation identifier to group related transactions."
      },
      {
        "name": "effective",
        "type": "DATE",
        "default": null,
        "description": "Effective date for the transaction."
      },
      {
        "name": "metadata",
        "type": "JSON",
        "default": "{}",
        "description": "Effective date for the transaction."
      }
    ],
    "transaction": {
      "effective": "params.effective",
      "journalId": "params.journal",
      "correlationId": "params.correlation",
      "externalId": "''",
      "description": "''",
      "metadata": "params.metadata"
    },
    "entries": [
      {
        "entryType": "'CARD_HOLD_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
        "accountId": "uuid(params.account)",
        "layer": "PENDING",
        "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
        "units": "params.amount",
        "currency": "params.currency",
        "description": "'Card hold placed on account in parameters.'",
        "metadata": "{}",
        "condition": null
      },
      {
        "entryType": "'CARD_HOLD_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
        "accountId": "uuid(params.settlementAccount)",
        "layer": "PENDING",
        "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
        "units": "params.amount",
        "currency": "params.currency",
        "description": "'Card hold placed in settlement account.'",
        "metadata": "{}",
        "condition": null
      }
    ]
  },
  "cardHoldVoid": {
    "tranCodeId": "218f19fc-e283-4f5b-90f6-02fd99e48e5c",
    "code": "CARD_HOLD_VOID",
    "description": "Posts $0 entries to an account indicating a card hold was voided. Use in conjuction with voidTransaction.",
    "params": [
      {
        "name": "account",
        "type": "UUID",
        "default": null,
        "description": "The account to place the hold on."
      },
      {
        "name": "settlementAccount",
        "type": "UUID",
        "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
        "description": "The settlement account to use."
      },
      {
        "name": "journal",
        "type": "UUID",
        "default": "00000000-0000-0000-0000-000000000000",
        "description": "The journal to post transactions to."
      },
      {
        "name": "amount",
        "type": "STRING",
        "default": null,
        "description": "The decimal amount of the hold."
      },
      {
        "name": "currency",
        "type": "STRING",
        "default": "USD",
        "description": "The currency of the hold amount."
      },
      {
        "name": "direction",
        "type": "STRING",
        "default": "DEBIT",
        "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
      },
      {
        "name": "correlation",
        "type": "STRING",
        "default": null,
        "description": "'Correlation identifier to group related transactions.'"
      },
      {
        "name": "effective",
        "type": "DATE",
        "default": null,
        "description": "Effective date for the transaction."
      },
      {
        "name": "metadata",
        "type": "JSON",
        "default": "{}",
        "description": "Effective date for the transaction."
      }
    ],
    "transaction": {
      "effective": "params.effective",
      "journalId": "params.journal",
      "correlationId": "params.correlation",
      "externalId": "''",
      "description": "''",
      "metadata": "params.metadata"
    },
    "entries": [
      {
        "entryType": "'CARD_HOLD_VOID_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
        "accountId": "uuid(params.account)",
        "layer": "PENDING",
        "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
        "units": "decimal('0')",
        "currency": "params.currency",
        "description": "'Card hold placed on account in parameters.'",
        "metadata": "{}",
        "condition": null
      },
      {
        "entryType": "'CARD_HOLD_VOID_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
        "accountId": "uuid(params.settlementAccount)",
        "layer": "PENDING",
        "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
        "units": "decimal('0')",
        "currency": "params.currency",
        "description": "'Card hold placed in settlement account.'",
        "metadata": "{}",
        "condition": null
      }
    ]
  },
  "cardHoldReplace": {
    "tranCodeId": "b0b6cb20-7c9d-4e48-8179-caa9c06e44d7",
    "code": "CARD_HOLD_REPLACE",
    "description": "Posts a hold at pending layer indicating the hold amount changed to this value. Use in conjuction with voidTransaction.",
    "params": [
      {
        "name": "account",
        "type": "UUID",
        "default": null,
        "description": "The account to place the hold on."
      },
      {
        "name": "settlementAccount",
        "type": "UUID",
        "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
        "description": "The settlement account to use."
      },
      {
        "name": "journal",
        "type": "UUID",
        "default": "00000000-0000-0000-0000-000000000000",
        "description": "The journal to post transactions to."
      },
      {
        "name": "amount",
        "type": "STRING",
        "default": null,
        "description": "The decimal amount of the hold."
      },
      {
        "name": "currency",
        "type": "STRING",
        "default": "USD",
        "description": "The currency of the hold amount."
      },
      {
        "name": "direction",
        "type": "STRING",
        "default": "DEBIT",
        "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
      },
      {
        "name": "correlation",
        "type": "STRING",
        "default": null,
        "description": "Correlation identifier to group related transactions."
      },
      {
        "name": "effective",
        "type": "DATE",
        "default": null,
        "description": "Effective date for the transaction."
      },
      {
        "name": "metadata",
        "type": "JSON",
        "default": "{}",
        "description": "Effective date for the transaction."
      }
    ],
    "transaction": {
      "effective": "params.effective",
      "journalId": "params.journal",
      "correlationId": "params.correlation",
      "externalId": "''",
      "description": "''",
      "metadata": "params.metadata"
    },
    "entries": [
      {
        "entryType": "'CARD_HOLD_REPLACE_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
        "accountId": "uuid(params.account)",
        "layer": "PENDING",
        "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
        "units": "params.amount",
        "currency": "params.currency",
        "description": "'Card hold placed on account in parameters.'",
        "metadata": "{}",
        "condition": null
      },
      {
        "entryType": "'CARD_HOLD_REPLACE_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
        "accountId": "uuid(params.settlementAccount)",
        "layer": "PENDING",
        "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
        "units": "params.amount",
        "currency": "params.currency",
        "description": "'Card hold placed in settlement account.'",
        "metadata": "{}",
        "condition": null
      }
    ]
  },
  "cardSettle": {
    "tranCodeId": "2e1f3ed4-0f0e-467a-82f7-715c2bcd97ef",
    "code": "CARD_SETTLE",
    "description": "Post a card settlement at the settled layer.",
    "params": [
      {
        "name": "account",
        "type": "UUID",
        "default": null,
        "description": "The account to place the hold on."
      },
      {
        "name": "settlementAccount",
        "type": "UUID",
        "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
        "description": "The settlement account to use."
      },
      {
        "name": "journal",
        "type": "UUID",
        "default": "00000000-0000-0000-0000-000000000000",
        "description": "The journal to post transactions to."
      },
      {
        "name": "amount",
        "type": "STRING",
        "default": null,
        "description": "The decimal amount of the hold."
      },
      {
        "name": "currency",
        "type": "STRING",
        "default": "USD",
        "description": "The currency of the hold amount."
      },
      {
        "name": "direction",
        "type": "STRING",
        "default": "DEBIT",
        "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
      },
      {
        "name": "correlation",
        "type": "STRING",
        "default": null,
        "description": "Correlation identifier to group related transactions."
      },
      {
        "name": "effective",
        "type": "DATE",
        "default": null,
        "description": "Effective date for the transaction."
      },
      {
        "name": "metadata",
        "type": "JSON",
        "default": "{}",
        "description": "Effective date for the transaction."
      }
    ],
    "transaction": {
      "effective": "params.effective",
      "journalId": "params.journal",
      "correlationId": "params.correlation",
      "externalId": "''",
      "description": "''",
      "metadata": "params.metadata"
    },
    "entries": [
      {
        "entryType": "'CARD_SETTLE_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
        "accountId": "uuid(params.account)",
        "layer": "SETTLED",
        "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
        "units": "params.amount",
        "currency": "params.currency",
        "description": "'Card hold placed on account in parameters.'",
        "metadata": "{}",
        "condition": null
      },
      {
        "entryType": "'CARD_SETTLE_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
        "accountId": "uuid(params.settlementAccount)",
        "layer": "SETTLED",
        "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
        "units": "params.amount",
        "currency": "params.currency",
        "description": "'Card hold placed in settlement account.'",
        "metadata": "{}",
        "condition": null
      }
    ]
  },
  "cardDecline": {
    "tranCodeId": "2b954d71-01a8-4021-82a1-c78aa1b607bd",
    "code": "CARD_DECLINE",
    "description": "Note a card decline by posting a $0 transaction. Use in conjuction with voidTransaction.",
    "params": [
      {
        "name": "account",
        "type": "UUID",
        "default": null,
        "description": "The account to place the hold on."
      },
      {
        "name": "settlementAccount",
        "type": "UUID",
        "default": "fabdce1f-6eb9-4630-9472-6338ed3dc6a2",
        "description": "The settlement account to use."
      },
      {
        "name": "journal",
        "type": "UUID",
        "default": "00000000-0000-0000-0000-000000000000",
        "description": "The journal to post transactions to."
      },
      {
        "name": "amount",
        "type": "STRING",
        "default": null,
        "description": "The decimal amount of the hold."
      },
      {
        "name": "currency",
        "type": "STRING",
        "default": "USD",
        "description": "The currency of the hold amount."
      },
      {
        "name": "direction",
        "type": "STRING",
        "default": "DEBIT",
        "description": "CREDIT or DEBIT direction of hold. Usually DEBIT."
      },
      {
        "name": "correlation",
        "type": "STRING",
        "default": null,
        "description": "Correlation identifier to group related transactions."
      },
      {
        "name": "effective",
        "type": "DATE",
        "default": null,
        "description": "Effective date for the transaction."
      },
      {
        "name": "metadata",
        "type": "JSON",
        "default": "{}",
        "description": "Effective date for the transaction."
      }
    ],
    "transaction": {
      "effective": "params.effective",
      "journalId": "params.journal",
      "correlationId": "params.correlation",
      "externalId": "''",
      "description": "''",
      "metadata": "params.metadata"
    },
    "entries": [
      {
        "entryType": "'CARD_DECLINE_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
        "accountId": "uuid(params.account)",
        "layer": "PENDING",
        "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
        "units": "decimal('0')",
        "currency": "params.currency",
        "description": "'Card hold placed on account in parameters.'",
        "metadata": "{}",
        "condition": null
      },
      {
        "entryType": "'CARD_DECLINE_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
        "accountId": "uuid(params.settlementAccount)",
        "layer": "PENDING",
        "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
        "units": "decimal('0')",
        "currency": "params.currency",
        "description": "'Card hold placed in settlement account.'",
        "metadata": "{}",
        "condition": null
      }
    ]
  }
}
```

### Card Authorization Workflows

Card flows in Twisp can be modeled entirely with `postTransaction` and `voidTransaction` which are the most common primitives you'll use in Twisp.  Together with the set of card tran codes, you can build out very simple card flows that allow you to accurately track the balances and entries required for a card transaction lifecycle.

Using the account we onboarded earlier, we'll post the transactions for each use case and print the resulting balances.

#### Authorization Approval

You receive an authorization request and/or an advice for $10 that an authorization was approved.

| Event        | Operation       | Tran Code | Description                    |
|--------------|-----------------|-----------|--------------------------------|
| auth.request | postTransaction | CARD_HOLD | post $ amount to pending layer |
| auth.created | voidTransaction | n/a       | void previous transaction      |
| ...          | postTransaction | CARD_HOLD | post $ amount to pending layer |

**Request**

```graphql
mutation CardAuthorizationApproval(
  $initialAuthorizationId: UUID!
  $authorizationId: UUID!
  $accountId: UUID!
  $correlation: String
  $amount: Decimal!
  $effective: Date
  $initAuthHook: JSON
  $authHook: JSON
) {
  # Received initial authorization webhook
  initialAuthorization: postTransaction(
    input: {
      transactionId: $initialAuthorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $initAuthHook
      }
    }
  ) {
    transactionId
  }

  # Recieved approved webhook
  voidInitialAuthorization: voidTransaction(id: $initialAuthorizationId) {
    transactionId
  }

  authorization: postTransaction(
    input: {
      transactionId: $authorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $authHook
      }
    }
  ) {
    transactionId
  }
}
```
**Response**

```json
{
  "data": {
    "authorization": {
      "transactionId": "81832b7a-8881-48fe-b309-3bff1fcfc986"
    },
    "initialAuthorization": {
      "transactionId": "2f05a4d4-07c5-42c1-a567-438737b7a0ab"
    },
    "voidInitialAuthorization": {
      "transactionId": "988c1dce-ad47-52e3-8d37-4d79b60c8e66"
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "initialAuthorizationId": "2f05a4d4-07c5-42c1-a567-438737b7a0ab",
  "authorizationId": "81832b7a-8881-48fe-b309-3bff1fcfc986",
  "correlation": "2f05a4d4-07c5-42c1-a567-438737b7a0ab",
  "effective": "2022-10-01",
  "initAuthHook": "{\"status\":\"AUTHORIZATION\",\"amount\":1000,\"acquirer_fee\":100,\"authorization_amount\":1000,\"settled_amount\":0,\"events\":[],\"created\":\"2022-10-01T00:00:00Z\",\"token\":\"2f05a4d4-07c5-42c1-a567-438737b7a0ab\"}",
  "authHook": "{\n      \"status\": \"PENDING\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"81832b7a-8881-48fe-b309-3bff1fcfc986\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"ef867c4d-53fc-49e5-ba8c-342209eb9b5c\"\n    }"
}
```

**Request**

```graphql
query CheckBalance($accountId: UUID! = "7a17b0f1-b04f-46a4-ba45-d52a861c21d9") {
  balance(accountId: $accountId) {
    settled: available(layer: SETTLED) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
    pending: available(layer: PENDING) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "balance": {
      "settled": {
        "normalBalance": {
          "formatted": "$0.00"
        }
      },
      "pending": {
        "normalBalance": {
          "formatted": "-$10.00"
        }
      }
    }
  }
}
```

#### Authorization Decline

You decide to decline an authorization request or receive an advice that an authorization was declined for $10.

| Event        | Operation       | Tran Code      | Description                                 |
|--------------|-----------------|----------------|---------------------------------------------|
| auth.created | postTransaction | CARD_HOLD      | post $ amount to pending layer              |
| ...          | check balance   | n/a            | balance exceeds threshold                   |
| ...          | voidTransaction | n/a            | void transaction                            |
| ...          | postTransaction | CARD_HOLD_VOID | optionally Post $0 entry indicating no hold |

**Request**

```graphql
mutation CardAuthorizationDecline(
  $initialAuthorizationId: UUID!
  $declineId: UUID!
  $accountId: UUID!
  $correlation: String
  $amount: Decimal!
  $effective: Date
  $initAuthHook: JSON
  $declineHook: JSON
) {
  # Received initial authorization webhook
  # and return resulting balances.
  initialAuthorization: postTransaction(
    input: {
      transactionId: $initialAuthorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $initAuthHook
      }
    }
  ) {
    transactionId
    entries(first: 4) {
      nodes {
        balance(type: PREPARED) {
          available(layer: PENDING) {
            normalBalance {
              units
            }
          }
        }
      }
    }
  }

  # Declined transaction, later recieved declined webhook
  voidInitialAuthorization: voidTransaction(id: $initialAuthorizationId) {
    transactionId
  }

  decline: postTransaction(
    input: {
      transactionId: $declineId
      tranCode: "CARD_DECLINE"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $declineHook
      }
    }
  ) {
    transactionId
  }
}
```
**Response**

```json
{
  "data": {
    "decline": {
      "transactionId": "3318a65f-2245-4058-bd6c-9bee76f8b0af"
    },
    "initialAuthorization": {
      "entries": {
        "nodes": [
          {
            "balance": {
              "available": {
                "normalBalance": {
                  "units": "-20.00"
                }
              }
            }
          },
          {
            "balance": {
              "available": {
                "normalBalance": {
                  "units": "10.00"
                }
              }
            }
          }
        ]
      },
      "transactionId": "67734487-03fc-4451-b9f3-c89fce63ab8f"
    },
    "voidInitialAuthorization": {
      "transactionId": "de376aa4-0163-5294-a9d2-d44389fb24b5"
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "initialAuthorizationId": "67734487-03fc-4451-b9f3-c89fce63ab8f",
  "declineId": "3318a65f-2245-4058-bd6c-9bee76f8b0af",
  "correlation": "67734487-03fc-4451-b9f3-c89fce63ab8f",
  "effective": "2022-10-01",
  "initAuthHook": "{\n      \"status\": \"AUTHORIZATION\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"67734487-03fc-4451-b9f3-c89fce63ab8f\"\n    }",
  "declineHook": "{\n      \"status\": \"DECLINED\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"UNAUTHORIZED_MERCHANT\",\n          \"token\": \"3318a65f-2245-4058-bd6c-9bee76f8b0af\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"67734487-03fc-4451-b9f3-c89fce63ab8f\"\n    }"
}
```

**Request**

```graphql
query CheckBalance($accountId: UUID! = "7a17b0f1-b04f-46a4-ba45-d52a861c21d9") {
  balance(accountId: $accountId) {
    settled: available(layer: SETTLED) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
    pending: available(layer: PENDING) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "balance": {
      "settled": {
        "normalBalance": {
          "formatted": "$0.00"
        }
      },
      "pending": {
        "normalBalance": {
          "formatted": "-$10.00"
        }
      }
    }
  }
}
```

#### Authorization Update

An authorization is approved for $10 and then updated to $1.

| Event        | Operation       | Tran Code         | Description                        |
|--------------|-----------------|-------------------|------------------------------------|
| auth.created | postTransaction | CARD_HOLD         | post $ amount to pending layer     |
| auth.update  | voidTransaction | n/a               | void prior transaction             |
| ...          | postTransaction | CARD_HOLD_REPLACE | post new $ amount to pending layer |

**Request**

```graphql
mutation CardAuthorizationUpdate(
  $initialAuthorizationId: UUID!
  $authorizationId: UUID!
  $updateId: UUID!
  $accountId: UUID!
  $correlation: String
  $amount: Decimal!
  $updateAmount: Decimal
  $effective: Date
  $initAuthHook: JSON
  $authHook: JSON
  $updateHook: JSON
) {
  # Received initial authorization webhook
  initialAuthorization: postTransaction(
    input: {
      transactionId: $initialAuthorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $initAuthHook
      }
    }
  ) {
    transactionId
  }

  # Recieved approved webhook
  voidInitialAuthorization: voidTransaction(id: $initialAuthorizationId) {
    transactionId
  }

  authorization: postTransaction(
    input: {
      transactionId: $authorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $authHook
      }
    }
  ) {
    transactionId
  }

  # Received update webhook
  voidApprovedAuth: voidTransaction(id: $authorizationId) {
    transactionId
  }

  update: postTransaction(
    input: {
      transactionId: $updateId
      tranCode: "CARD_HOLD_REPLACE"
      params: {
        account: $accountId
        amount: $updateAmount
        correlation: $correlation
        effective: $effective
        metadata: $updateHook
      }
    }
  ) {
    transactionId
  }
}
```
**Response**

```json
{
  "data": {
    "authorization": {
      "transactionId": "79c336e6-8782-4df5-9992-c7c9bab0ad4e"
    },
    "initialAuthorization": {
      "transactionId": "449afa1d-95dd-406f-9d72-c8b4396055f9"
    },
    "update": {
      "transactionId": "c97c23d5-02c1-4361-b371-f1e40c50a73f"
    },
    "voidApprovedAuth": {
      "transactionId": "48494e7e-553d-540e-a1aa-a2f3533c29b3"
    },
    "voidInitialAuthorization": {
      "transactionId": "7d672168-0883-5f58-9fb7-6f1f89e42e48"
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "updateAmount": "1.00",
  "updateId": "c97c23d5-02c1-4361-b371-f1e40c50a73f",
  "initialAuthorizationId": "449afa1d-95dd-406f-9d72-c8b4396055f9",
  "authorizationId": "79c336e6-8782-4df5-9992-c7c9bab0ad4e",
  "correlation": "449afa1d-95dd-406f-9d72-c8b4396055f9",
  "effective": "2022-10-01",
  "initAuthHook": "{\n      \"status\": \"AUTHORIZATION\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"449afa1d-95dd-406f-9d72-c8b4396055f9\"\n    }",
  "authHook": "{\n      \"status\": \"PENDING\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"79c336e6-8782-4df5-9992-c7c9bab0ad4e\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"449afa1d-95dd-406f-9d72-c8b4396055f9\"\n    }",
  "updateHook": "{\n      \"status\": \"PENDING\",\n      \"amount\": 100,\n      \"acquirer_fee\": 0,\n      \"authorization_amount\": 100,\n      \"settled_amount\": 0,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"79c336e6-8782-4df5-9992-c7c9bab0ad4e\"\n        },\n        {\n          \"amount\": -900,\n          \"type\": \"VOID\",\n          \"result\": \"APPROVED\",\n          \"token\": \"c97c23d5-02c1-4361-b371-f1e40c50a73f\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"449afa1d-95dd-406f-9d72-c8b4396055f9\"\n    }"
}
```

**Request**

```graphql
query CheckBalance($accountId: UUID! = "7a17b0f1-b04f-46a4-ba45-d52a861c21d9") {
  balance(accountId: $accountId) {
    settled: available(layer: SETTLED) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
    pending: available(layer: PENDING) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "balance": {
      "settled": {
        "normalBalance": {
          "formatted": "$0.00"
        }
      },
      "pending": {
        "normalBalance": {
          "formatted": "-$11.00"
        }
      }
    }
  }
}
```

#### Authorization Cancelation

The authorization is created for $10 that expires or is canceled by the merchant.

| Event        | Operation       | Tran Code    | Description                                   |
|--------------|-----------------|--------------|-----------------------------------------------|
| auth.created | postTransaction | CARD_HOLD    | post $ amount to pending layer                |
| auth.cancel  | voidTransaction | n/a          | void prior transaction                        |

**Request**

```graphql
mutation CardAuthorizationCancel(
  $initialAuthorizationId: UUID!
  $authorizationId: UUID!
  $expireId: UUID!
  $accountId: UUID!
  $correlation: String
  $amount: Decimal!
  $effective: Date
  $initAuthHook: JSON
  $authHook: JSON
  $expireHook: JSON
) {
  # Received initial authorization webhook
  initialAuthorization: postTransaction(
    input: {
      transactionId: $initialAuthorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $initAuthHook
      }
    }
  ) {
    transactionId
  }

  # Recieved approved webhook
  voidInitialAuthorization: voidTransaction(id: $initialAuthorizationId) {
    transactionId
  }

  authorization: postTransaction(
    input: {
      transactionId: $authorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $authHook
      }
    }
  ) {
    transactionId
  }

  # Recieved card expiry webhook
  voidAuthorization: voidTransaction(id: $authorizationId) {
    transactionId
  }

  expire: postTransaction(
    input: {
      transactionId: $expireId
      tranCode: "CARD_HOLD_VOID"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $expireHook
      }
    }
  ) {
    transactionId
  }
}
```
**Response**

```json
{
  "data": {
    "authorization": {
      "transactionId": "b73a6058-d423-4543-9aba-0ff54c4e0c27"
    },
    "expire": {
      "transactionId": "db083442-d2a3-45a9-abe5-24023fdb10fb"
    },
    "initialAuthorization": {
      "transactionId": "a9551772-ca3d-4dc2-9da2-0d74c1ac1c7c"
    },
    "voidAuthorization": {
      "transactionId": "9fe6671e-aba5-5b4c-a986-739271521c8a"
    },
    "voidInitialAuthorization": {
      "transactionId": "14984ed2-b2b6-551f-b9c8-32b32c1f2590"
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "initialAuthorizationId": "a9551772-ca3d-4dc2-9da2-0d74c1ac1c7c",
  "authorizationId": "b73a6058-d423-4543-9aba-0ff54c4e0c27",
  "expireId": "db083442-d2a3-45a9-abe5-24023fdb10fb",
  "correlation": "a9551772-ca3d-4dc2-9da2-0d74c1ac1c7c",
  "effective": "2022-10-01",
  "initAuthHook": "{\n      \"status\": \"AUTHORIZATION\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"a9551772-ca3d-4dc2-9da2-0d74c1ac1c7c\"\n    }",
  "authHook": "{\n      \"status\": \"PENDING\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"b73a6058-d423-4543-9aba-0ff54c4e0c27\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"a9551772-ca3d-4dc2-9da2-0d74c1ac1c7c\"\n    }",
  "expireHook": "{\n      \"status\": \"VOIDED\",\n      \"amount\": 0,\n      \"acquirer_fee\": 0,\n      \"authorization_amount\": 0,\n      \"settled_amount\": 0,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"b73a6058-d423-4543-9aba-0ff54c4e0c27\"\n        },\n        {\n          \"amount\": -1000,\n          \"type\": \"AUTHORIZATION_EXPIRY\",\n          \"result\": \"APPROVED\",\n          \"token\": \"db083442-d2a3-45a9-abe5-24023fdb10fb\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"a9551772-ca3d-4dc2-9da2-0d74c1ac1c7c\"\n    }"
}
```

**Request**

```graphql
query CheckBalance($accountId: UUID! = "7a17b0f1-b04f-46a4-ba45-d52a861c21d9") {
  balance(accountId: $accountId) {
    settled: available(layer: SETTLED) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
    pending: available(layer: PENDING) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "balance": {
      "settled": {
        "normalBalance": {
          "formatted": "$0.00"
        }
      },
      "pending": {
        "normalBalance": {
          "formatted": "-$11.00"
        }
      }
    }
  }
}
```

#### Settlement (amount >= auth)

A settlement of an existing authorization whose amount is greater than the hold amount.  In this case a $10 settlement is applied to the account.

| Event        | Operation       | Tran Code      | Description                                 |
|--------------|-----------------|----------------|---------------------------------------------|
| auth.created | postTransaction | CARD_HOLD      | post $ amount to pending layer              |
| tx.created   | postTransaction | CARD_SETTLE    | post $ amount to settled layer              |
| ...          | voidTransaction | n/a            | void prior authorization transaction        |
| ...          | postTransaction | CARD_HOLD_VOID | optionally Post $0 entry indicating no hold |

**Request**

```graphql
mutation CardSettlement(
  $initialAuthorizationId: UUID!
  $authorizationId: UUID!
  $settleId: UUID!
  $accountId: UUID!
  $correlation: String
  $amount: Decimal!
  $effective: Date
  $initAuthHook: JSON
  $authHook: JSON
  $settleHook: JSON
) {
  # Received initial authorization webhook
  initialAuthorization: postTransaction(
    input: {
      transactionId: $initialAuthorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $initAuthHook
      }
    }
  ) {
    transactionId
  }

  # Recieved approved webhook
  voidInitialAuthorization: voidTransaction(id: $initialAuthorizationId) {
    transactionId
  }

  authorization: postTransaction(
    input: {
      transactionId: $authorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $authHook
      }
    }
  ) {
    transactionId
  }

  # Recieved clearing webhook
  voidAuthorization: voidTransaction(id: $authorizationId) {
    transactionId
  }

  clearing: postTransaction(
    input: {
      transactionId: $settleId
      tranCode: "CARD_SETTLE"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $settleHook
      }
    }
  ) {
    transactionId
  }
}
```
**Response**

```json
{
  "data": {
    "authorization": {
      "transactionId": "5e20e176-82bd-49b4-955c-c059b153b5db"
    },
    "clearing": {
      "transactionId": "108449c6-122c-43a4-936c-228056e8ee58"
    },
    "initialAuthorization": {
      "transactionId": "3b8937a2-bf03-4bd4-83e8-ededf56118e9"
    },
    "voidAuthorization": {
      "transactionId": "19c18c18-5a6d-505c-846b-08debddde872"
    },
    "voidInitialAuthorization": {
      "transactionId": "6a27101a-b1c4-5f54-a510-59fcf5667fe2"
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "settleId": "108449c6-122c-43a4-936c-228056e8ee58",
  "initialAuthorizationId": "3b8937a2-bf03-4bd4-83e8-ededf56118e9",
  "authorizationId": "5e20e176-82bd-49b4-955c-c059b153b5db",
  "correlation": "3b8937a2-bf03-4bd4-83e8-ededf56118e9",
  "effective": "2022-10-01",
  "initAuthHook": "{\n      \"status\": \"AUTHORIZATION\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"3b8937a2-bf03-4bd4-83e8-ededf56118e9\"\n    }",
  "authHook": "{\n      \"status\": \"PENDING\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"5e20e176-82bd-49b4-955c-c059b153b5db\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"3b8937a2-bf03-4bd4-83e8-ededf56118e9\"\n    }",
  "settleHook": "{\n      \"status\": \"SETTLED\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 0,\n      \"authorization_amount\": 0,\n      \"settled_amount\": 1000,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"5e20e176-82bd-49b4-955c-c059b153b5db\"\n        },\n        {\n          \"amount\": 1000,\n          \"type\": \"CLEARING\",\n          \"result\": \"APPROVED\",\n          \"token\": \"108449c6-122c-43a4-936c-228056e8ee58\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"3b8937a2-bf03-4bd4-83e8-ededf56118e9\"\n    }"
}
```

**Request**

```graphql
query CheckBalance($accountId: UUID! = "7a17b0f1-b04f-46a4-ba45-d52a861c21d9") {
  balance(accountId: $accountId) {
    settled: available(layer: SETTLED) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
    pending: available(layer: PENDING) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "balance": {
      "settled": {
        "normalBalance": {
          "formatted": "-$10.00"
        }
      },
      "pending": {
        "normalBalance": {
          "formatted": "-$21.00"
        }
      }
    }
  }
}
```

#### Multi-settlement (amount < auth)

Some processors always drop holds with a settlement. Others will adjust hold amount and allow for additional settlements. You'll map your implementation
to match the card providers.

| Event        | Operation       | Tran Code         | Description                                 |
|--------------|-----------------|-------------------|---------------------------------------------|
| auth.created | postTransaction | CARD_HOLD         | post $ amount to pending layer              |
| tx.created   | postTransaction | CARD_SETTLE       | post $ amount to settled layer              |
| ...          | voidTransaction | n/a               | void prior authorization transaction        |
| ...          | postTransaction | CARD_HOLD_VOID    | optionally Post $0 entry indicating no hold |
| auth.updated | voidTransaction | n/a               | optionally void prior $0 hold               |
| ...          | postTransaction | CARD_HOLD_REPLACE | optionally post new hold                    |

**Request**

```graphql
mutation CardPartialSettlement(
  $initialAuthorizationId: UUID!
  $authorizationId: UUID!
  $partialSettleId: UUID!
  $accountId: UUID!
  $correlation: String
  $amount: Decimal!
  $replaceAmount: Decimal!
  $settleAmount: Decimal!
  $effective: Date
  $initAuthHook: JSON
  $authHook: JSON
  $settleHook: JSON
) {
  # Received initial authorization webhook
  initialAuthorization: postTransaction(
    input: {
      transactionId: $initialAuthorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $initAuthHook
      }
    }
  ) {
    transactionId
  }

  # Recieved approved webhook
  voidInitialAuthorization: voidTransaction(id: $initialAuthorizationId) {
    transactionId
  }

  authorization: postTransaction(
    input: {
      transactionId: $authorizationId
      tranCode: "CARD_HOLD"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $authHook
      }
    }
  ) {
    transactionId
  }

  # Recieved partial settlement webhook
  voidAuthorization: voidTransaction(id: $authorizationId) {
    transactionId
  }

  updateHold: postTransaction(
    input: {
      transactionId: $partialSettleId
      tranCode: "CARD_HOLD_REPLACE"
      params: {
        account: $accountId
        amount: $replaceAmount
        correlation: $correlation
        effective: $effective
        metadata: $settleHook
      }
    }
  ) {
    transactionId
  }

  partialSettle: postTransaction(
    input: {
      transactionId: "6daad172-6ae7-4ddd-843c-e5e0455fb6da"
      tranCode: "CARD_SETTLE"
      params: {
        account: $accountId
        amount: $settleAmount
        correlation: $correlation
        effective: $effective
        metadata: $settleHook
      }
    }
  ) {
    transactionId
  }
}
```
**Response**

```json
{
  "data": {
    "authorization": {
      "transactionId": "9588d5a5-26a2-4ed0-84bb-384f4097c7f5"
    },
    "initialAuthorization": {
      "transactionId": "3175506b-d828-4deb-ae6b-5aabeebd438d"
    },
    "partialSettle": {
      "transactionId": "6daad172-6ae7-4ddd-843c-e5e0455fb6da"
    },
    "updateHold": {
      "transactionId": "3c9faea9-1807-4867-967a-0fadd0b18521"
    },
    "voidAuthorization": {
      "transactionId": "bcbf86b3-101c-5605-b872-6587d381c477"
    },
    "voidInitialAuthorization": {
      "transactionId": "4f87f582-d440-558b-801d-4176f0056cc8"
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "replaceAmount": "9.00",
  "settleAmount": "1.00",
  "initialAuthorizationId": "3175506b-d828-4deb-ae6b-5aabeebd438d",
  "authorizationId": "9588d5a5-26a2-4ed0-84bb-384f4097c7f5",
  "partialSettleId": "3c9faea9-1807-4867-967a-0fadd0b18521",
  "correlation": "3175506b-d828-4deb-ae6b-5aabeebd438d",
  "effective": "2022-10-01",
  "initAuthHook": "{\n      \"status\": \"AUTHORIZATION\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"3175506b-d828-4deb-ae6b-5aabeebd438d\"\n    }",
  "authHook": "{\n      \"status\": \"PENDING\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 100,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 0,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"9588d5a5-26a2-4ed0-84bb-384f4097c7f5\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"3175506b-d828-4deb-ae6b-5aabeebd438d\"\n    }",
  "settleHook": "{\n      \"status\": \"SETTLED\",\n      \"amount\": 100,\n      \"acquirer_fee\": 0,\n      \"authorization_amount\": 900,\n      \"settled_amount\": 100,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"AUTHORIZATION\",\n          \"result\": \"APPROVED\",\n          \"token\": \"9588d5a5-26a2-4ed0-84bb-384f4097c7f5\"\n        },\n        {\n          \"amount\": 100,\n          \"type\": \"CLEARING\",\n          \"result\": \"APPROVED\",\n          \"token\": \"3c9faea9-1807-4867-967a-0fadd0b18521\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"3175506b-d828-4deb-ae6b-5aabeebd438d\"\n    }"
}
```

**Request**

```graphql
query CheckBalance($accountId: UUID! = "7a17b0f1-b04f-46a4-ba45-d52a861c21d9") {
  balance(accountId: $accountId) {
    settled: available(layer: SETTLED) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
    pending: available(layer: PENDING) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "balance": {
      "settled": {
        "normalBalance": {
          "formatted": "-$11.00"
        }
      },
      "pending": {
        "normalBalance": {
          "formatted": "-$31.00"
        }
      }
    }
  }
}
```

#### Settlement (no Auth)

Receive a transaction without a matching hold.

| Event        | Operation       | Tran Code   | Description                                 |
|--------------|-----------------|-------------|---------------------------------------------|
| tx.created   | postTransaction | CARD_SETTLE | post $ amount to settled layer              |

**Request**

```graphql
mutation CardForcePost(
  $settlementId: UUID!
  $accountId: UUID!
  $correlation: String
  $amount: Decimal!
  $effective: Date
  $settleHook: JSON
) {
  # Received clearing webhook.
  forcePost: postTransaction(
    input: {
      transactionId: $settlementId
      tranCode: "CARD_SETTLE"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $settleHook
      }
    }
  ) {
    transactionId
  }
}
```
**Response**

```json
{
  "data": {
    "forcePost": {
      "transactionId": "d0150140-0ef1-4b89-8c23-7ad537006329"
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "settlementId": "d0150140-0ef1-4b89-8c23-7ad537006329",
  "correlation": "3a47f3fc-de3b-44b9-aea2-74e0c02e1fb8",
  "effective": "2022-10-01",
  "settleHook": "{\n      \"status\": \"SETTLED\",\n      \"amount\": 1000,\n      \"acquirer_fee\": 0,\n      \"authorization_amount\": 1000,\n      \"settled_amount\": 1000,\n      \"events\": [\n        {\n          \"amount\": 1000,\n          \"type\": \"CLEARING\",\n          \"result\": \"APPROVED\",\n          \"token\": \"d0150140-0ef1-4b89-8c23-7ad537006329\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"3a47f3fc-de3b-44b9-aea2-74e0c02e1fb8\"\n    }"
}
```

**Request**

```graphql
query CheckBalance($accountId: UUID! = "7a17b0f1-b04f-46a4-ba45-d52a861c21d9") {
  balance(accountId: $accountId) {
    settled: available(layer: SETTLED) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
    pending: available(layer: PENDING) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "balance": {
      "settled": {
        "normalBalance": {
          "formatted": "-$21.00"
        }
      },
      "pending": {
        "normalBalance": {
          "formatted": "-$41.00"
        }
      }
    }
  }
}
```

#### Return

Receive a return transaction.

| Event        | Operation       | Tran Code   | Description                                 |
|--------------|-----------------|-------------|---------------------------------------------|
| tx.created   | postTransaction | CARD_SETTLE | post $ amount to settled layer              |

**Request**

```graphql
mutation CardReturn(
  $settlementId: UUID!
  $accountId: UUID!
  $correlation: String
  $direction: String
  $amount: Decimal!
  $effective: Date
  $settleHook: JSON
) {
  # Received clearing webhook.
  forcePost: postTransaction(
    input: {
      transactionId: $settlementId
      tranCode: "CARD_SETTLE"
      params: {
        account: $accountId
        amount: $amount
        correlation: $correlation
        effective: $effective
        metadata: $settleHook
        direction: $direction
      }
    }
  ) {
    transactionId
  }
}
```
**Response**

```json
{
  "data": {
    "forcePost": {
      "transactionId": "fa5cb793-0739-4eb8-8db2-9b452ed71930"
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "direction": "CREDIT",
  "settlementId": "fa5cb793-0739-4eb8-8db2-9b452ed71930",
  "correlation": "265a9120-e42a-4c02-b3dc-eb80a2e3cf00",
  "effective": "2022-10-01",
  "settleHook": "{\n      \"status\": \"SETTLED\",\n      \"amount\": -1000,\n      \"acquirer_fee\": 0,\n      \"authorization_amount\": -1000,\n      \"settled_amount\": -1000,\n      \"events\": [\n        {\n          \"amount\": -1000,\n          \"type\": \"RETURN\",\n          \"result\": \"APPROVED\",\n          \"token\": \"fa5cb793-0739-4eb8-8db2-9b452ed71930\"\n        }\n      ],\n      \"created\": \"2022-10-01T00:00:00Z\",\n      \"token\": \"265a9120-e42a-4c02-b3dc-eb80a2e3cf00\"\n    }"
}
```

**Request**

```graphql
query CheckBalance($accountId: UUID! = "7a17b0f1-b04f-46a4-ba45-d52a861c21d9") {
  balance(accountId: $accountId) {
    settled: available(layer: SETTLED) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
    pending: available(layer: PENDING) {
      normalBalance {
        formatted(as: { locale: "en-US" })
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "balance": {
      "settled": {
        "normalBalance": {
          "formatted": "-$11.00"
        }
      },
      "pending": {
        "normalBalance": {
          "formatted": "-$31.00"
        }
      }
    }
  }
}
```

## ACH

The Automated Clearing House is a service provided by the Federal Reserve for conducting electronic funds transfers.  There are two modes of operation when dealing with ACH:

- Receiving Deposit Financial Institution (RDFI): External FI's are crediting/debiting your accounts with theirs
- Originating Deposit Financial Institution (ODFI): You are initiating credits/debits with external accounts

Twisp has a number of built in tran codes and workflows to handle both use cases.

### Tran Codes

**Request**

```graphql
query ACHTranCodes {
  achEncumbranceCancelDebit: tranCode(
    id: "7b24410d-6dbc-44cd-8779-a1bfa827868a"
  ) {
    ...TC
  }
  achEncumbranceCancelReversalCredit: tranCode(
    id: "b7976c0e-2e4c-4e99-a48f-86384f3dddf6"
  ) {
    ...TC
  }
  achEncumbranceCredit: tranCode(id: "8fe41dca-190a-4c84-adc9-78952ac70a54") {
    ...TC
  }
  achEncumbranceDebit: tranCode(id: "0b83d0d4-b580-4056-a094-74ef393328b7") {
    ...TC
  }
  achEncumbranceReturnDebit: tranCode(
    id: "cde02e54-e725-46bc-9b61-5511c93058a7"
  ) {
    ...TC
  }
  achEncumbranceReturnCredit: tranCode(
    id: "4c4d9599-1caa-4632-a6fb-ca1ae3a2b836"
  ) {
    ...TC
  }
  achEncumbranceReversalDebit: tranCode(
    id: "cd7b997c-526c-4b8f-ac56-8c6de009dc25"
  ) {
    ...TC
  }
  achEncumbranceReversalCredit: tranCode(
    id: "f57ba3a2-ccfa-47de-ae81-1a8167639fe3"
  ) {
    ...TC
  }
  achFeeDebit: tranCode(id: "d3b64ee6-0815-4d06-aa9b-906bc48cbc19") {
    ...TC
  }
  achFeeReimburseCredit: tranCode(id: "49b0f890-75e7-4b94-920b-54328c02b2ca") {
    ...TC
  }
  achPendingDebit: tranCode(id: "e19dfe3f-6513-425a-b9a3-870f91303cc8") {
    ...TC
  }
  achPendingCancelCredit: tranCode(id: "c66725d7-c115-4339-89e9-69b6a6ae97bd") {
    ...TC
  }
  achPendingCancelReversalDebit: tranCode(
    id: "f83a1768-06a1-4a6b-a472-6e9b9c7dbe75"
  ) {
    ...TC
  }
  achPendingReversalDebit: tranCode(
    id: "21036f96-bc05-4526-8004-e63ff6955d0a"
  ) {
    ...TC
  }
  achSettleCredit: tranCode(id: "d918eb34-1ef9-4437-a82b-46c169f63e41") {
    ...TC
  }
  achSettleDebit: tranCode(id: "5af51352-84ad-4534-aacf-4e68c2ed2e2b") {
    ...TC
  }
  achSettleReturnCredit: tranCode(id: "90e09ed8-ae9c-46f2-9be8-2e09b4a5de35") {
    ...TC
  }
  achSettleReturnDebit: tranCode(id: "2b11b428-54ed-429c-97d9-b9a4e3ef6007") {
    ...TC
  }
}
fragment TC on TranCode {
  tranCodeId
  code
  description
  params {
    name
    type
    default
    description
  }
  transaction {
    effective
    journalId
    correlationId
    externalId
    description
    metadata
  }
  entries {
    entryType
    accountId
    layer
    direction
    units
    currency
    description
    metadata
    condition
  }
}
```
**Response**

```json
{
  "data": {
    "achEncumbranceCancelDebit": {
      "tranCodeId": "7b24410d-6dbc-44cd-8779-a1bfa827868a",
      "code": "SYS_ACH_ENCUMBRANCE_CANCEL_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_ENCUMBRANCE_CANCEL_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "ENCUMBRANCE",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_ENCUMBRANCE_CANCEL_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "ENCUMBRANCE",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achEncumbranceCancelReversalCredit": {
      "tranCodeId": "b7976c0e-2e4c-4e99-a48f-86384f3dddf6",
      "code": "SYS_ACH_ENCUMBRANCE_CANCEL_REVERSAL_CR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_ENCUMBRANCE_CANCEL_CR'",
          "accountId": "uuid(params.accountId)",
          "layer": "ENCUMBRANCE",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_ENCUMBRANCE_CANCEL_DR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "ENCUMBRANCE",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achEncumbranceCredit": {
      "tranCodeId": "8fe41dca-190a-4c84-adc9-78952ac70a54",
      "code": "SYS_ACH_ENCUMBRANCE_CR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_ENCUMBRANCE_CR'",
          "accountId": "uuid(params.accountId)",
          "layer": "ENCUMBRANCE",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_ENCUMBRANCE_DR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "ENCUMBRANCE",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achEncumbranceDebit": {
      "tranCodeId": "0b83d0d4-b580-4056-a094-74ef393328b7",
      "code": "SYS_ACH_ENCUMBRANCE_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_ENCUMBRANCE_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "ENCUMBRANCE",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_ENCUMBRANCE_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "ENCUMBRANCE",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achEncumbranceReturnDebit": {
      "tranCodeId": "cde02e54-e725-46bc-9b61-5511c93058a7",
      "code": "SYS_ACH_ENCUMBRANCE_RETURN_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_ENCUMBRANCE_RETURN_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "ENCUMBRANCE",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_ENCUMBRANCE_RETURN_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "ENCUMBRANCE",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achEncumbranceReturnCredit": {
      "tranCodeId": "4c4d9599-1caa-4632-a6fb-ca1ae3a2b836",
      "code": "SYS_ACH_ENCUMBRANCE_RETURN_CR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_ENCUMBRANCE_RETURN_CR'",
          "accountId": "uuid(params.accountId)",
          "layer": "ENCUMBRANCE",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_ENCUMBRANCE_RETURN_DR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "ENCUMBRANCE",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achEncumbranceReversalDebit": {
      "tranCodeId": "cd7b997c-526c-4b8f-ac56-8c6de009dc25",
      "code": "SYS_ACH_ENCUMBRANCE_REVERSAL_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_ENCUMBRANCE_REVERSAL_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "ENCUMBRANCE",
          "direction": "DEBIT",
          "units": "decimal.Neg(params.amount)",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_ENCUMBRANCE_REVERSAL_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "ENCUMBRANCE",
          "direction": "CREDIT",
          "units": "decimal.Neg(params.amount)",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achEncumbranceReversalCredit": {
      "tranCodeId": "f57ba3a2-ccfa-47de-ae81-1a8167639fe3",
      "code": "SYS_ACH_ENCUMBRANCE_REVERSAL_CR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_ENCUMBRANCE_REVERSAL_CR'",
          "accountId": "uuid(params.accountId)",
          "layer": "ENCUMBRANCE",
          "direction": "CREDIT",
          "units": "decimal.Neg(params.amount)",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_ENCUMBRANCE_REVERSAL_DR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "ENCUMBRANCE",
          "direction": "DEBIT",
          "units": "decimal.Neg(params.amount)",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achFeeDebit": {
      "tranCodeId": "d3b64ee6-0815-4d06-aa9b-906bc48cbc19",
      "code": "SYS_ACH_FEE_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_FEE_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "SETTLED",
          "direction": "DEBIT",
          "units": "params.feeAmount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_FEE_CR'",
          "accountId": "uuid(params.feeAccountId)",
          "layer": "SETTLED",
          "direction": "CREDIT",
          "units": "params.feeAmount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achFeeReimburseCredit": {
      "tranCodeId": "49b0f890-75e7-4b94-920b-54328c02b2ca",
      "code": "SYS_ACH_FEE_REIMBURSE_CR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_FEE_REIMBURSE_CR'",
          "accountId": "uuid(params.accountId)",
          "layer": "SETTLED",
          "direction": "CREDIT",
          "units": "params.feeAmount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_FEE_REIMBURSE_DR'",
          "accountId": "uuid(params.feeAccountId)",
          "layer": "SETTLED",
          "direction": "DEBIT",
          "units": "params.feeAmount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achPendingDebit": {
      "tranCodeId": "e19dfe3f-6513-425a-b9a3-870f91303cc8",
      "code": "SYS_ACH_PENDING_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_PENDING_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "PENDING",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_PENDING_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "PENDING",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achPendingCancelCredit": {
      "tranCodeId": "c66725d7-c115-4339-89e9-69b6a6ae97bd",
      "code": "SYS_ACH_PENDING_CANCEL_CR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_PENDING_CANCEL_CR'",
          "accountId": "uuid(params.accountId)",
          "layer": "PENDING",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_PENDING_CANCEL_DR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "PENDING",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achPendingCancelReversalDebit": {
      "tranCodeId": "f83a1768-06a1-4a6b-a472-6e9b9c7dbe75",
      "code": "SYS_ACH_PENDING_CANCEL_REVERSAL_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_PENDING_CANCEL_REVERSAL_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "PENDING",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_PENDING_CANCEL_REVERSAL_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "PENDING",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achPendingReversalDebit": {
      "tranCodeId": "21036f96-bc05-4526-8004-e63ff6955d0a",
      "code": "SYS_ACH_PENDING_REVERSAL_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_PENDING_REVERSAL_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "PENDING",
          "direction": "DEBIT",
          "units": "decimal.Neg(params.amount)",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_PENDING_REVERSAL_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "PENDING",
          "direction": "CREDIT",
          "units": "decimal.Neg(params.amount)",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achSettleCredit": {
      "tranCodeId": "d918eb34-1ef9-4437-a82b-46c169f63e41",
      "code": "SYS_ACH_SETTLE_CR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_SETTLE_CR'",
          "accountId": "uuid(params.accountId)",
          "layer": "SETTLED",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_SETTLE_DR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "SETTLED",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achSettleDebit": {
      "tranCodeId": "5af51352-84ad-4534-aacf-4e68c2ed2e2b",
      "code": "SYS_ACH_SETTLE_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_SETTLE_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "SETTLED",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_SETTLE_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "SETTLED",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achSettleReturnCredit": {
      "tranCodeId": "90e09ed8-ae9c-46f2-9be8-2e09b4a5de35",
      "code": "SYS_ACH_SETTLE_RETURN_CR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_SETTLE_RETURN_CR'",
          "accountId": "uuid(params.accountId)",
          "layer": "SETTLED",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_SETTLE_RETURN_DR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "SETTLED",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    },
    "achSettleReturnDebit": {
      "tranCodeId": "2b11b428-54ed-429c-97d9-b9a4e3ef6007",
      "code": "SYS_ACH_SETTLE_RETURN_DR",
      "description": "",
      "params": [
        {
          "name": "accountId",
          "type": "UUID",
          "default": null,
          "description": "The account to place the hold on."
        },
        {
          "name": "settlementAccountId",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "feeAccountId",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "Optional fee account to use."
        },
        {
          "name": "feeAmount",
          "type": "DECIMAL",
          "default": "0",
          "description": "Optional decimal amount of the fee."
        },
        {
          "name": "journalId",
          "type": "UUID",
          "default": null,
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "DECIMAL",
          "default": null,
          "description": "The decimal amount."
        },
        {
          "name": "correlationId",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the transaction."
        },
        {
          "name": "entryMetadata",
          "type": "JSON",
          "default": "{}",
          "description": "metadata for the entry of accountId."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journalId",
        "correlationId": "params.correlationId",
        "externalId": "''",
        "description": "''",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'ACH_SETTLE_RETURN_DR'",
          "accountId": "uuid(params.accountId)",
          "layer": "SETTLED",
          "direction": "DEBIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        },
        {
          "entryType": "'ACH_SETTLE_RETURN_CR'",
          "accountId": "uuid(params.settlementAccountId)",
          "layer": "SETTLED",
          "direction": "CREDIT",
          "units": "params.amount",
          "currency": "'USD'",
          "description": "''",
          "metadata": "params.entryMetadata",
          "condition": null
        }
      ]
    }
  }
}
```

### Workflows

In addition to the built-in tran codes, Twisp offers a number of workflows that will post & void transactions as appropriate for each stage of the ACH transaction lifecycle.  These are built on top of the [executeTask](/docs/reference/graphql/mutations#workflow.execute-task) workflow invocation.

Below we will look at sample graphql for invocation of the workflow and describe the various tasks available for each type of workflow.

#### ODFI Push

| Task          | Valid From             | Description                                                                                 |
|---------------|------------------------|---------------------------------------------------------------------------------------------|
| CREATE        |                        | Debit customers account at `PENDING` layer, funds leaving in next ACH batch.                |
| SUBMIT        | CREATE                 | Void the `PENDING` transaction and post settlement, funds are sent to external institution. |
| RETURN        | SUBMIT                 | External institution returned the funds for some reason. e.g. Account is closed.            |
| CANCEL        | CREATE                 | Cancel the ACH transaction before the batch window is reached.                              |
| CONTINUE      | CANCEL, REIMBURSE_FEE  | Undo the cancellation.                                                                      |
| REIMBURSE_FEE | CREATE, SUBMIT, RETURN | Reimburse optional fee to the customer.                                                                                            |

**Request**

```graphql
mutation ODFIPush(
  $accountId: UUID!
  $journalId: UUID!
  $settlementAccountId: UUID!
  $feeAccountId: UUID!
) {
  # Push is scheduled
  create: workflow {
    executeTask(
      input: {
        task: "CREATE"
        workflowId: "934498b5-b4f1-46c4-ad79-868939dc39e8"
        executionId: "34d499dd-d061-42f4-af42-c051c8d4109e"
        params: {
          accountId: $accountId
          feeAccountId: $feeAccountId # optional fee accountId for fees
          settlementAccountId: $settlementAccountId
          journalId: $journalId
          amount: "1.00"
          # optional fee amount
          feeAmount: "0.50"
          effective: "2023-01-01"
          metadata: "{}"
        }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  # Fee can be reimbursed after CREATE
  # reimburse: workflow {
  #   executeTask(
  #     input: {
  #       task: "REIMBURSE_FEE"
  #       workflowId: "934498b5-b4f1-46c4-ad79-868939dc39e8"
  #       executionId: "34d499dd-d061-42f4-af42-c051c8d4109e"
  #       params: {
  #         effective: "2023-01-01"
  #         metadata: "{}"
  #       }
  #     }
  #    ) {
  #      transactions {
  #        transactionId
  #      }
  #    }
  # }

  # cancel will reimburse fee if not reimbursed yet

  # cancel: workflow {
  #   executeTask(
  #     input: {
  #       task: "CANCEL"
  #       workflowId: "934498b5-b4f1-46c4-ad79-868939dc39e8"
  #       executionId: "34d499dd-d061-42f4-af42-c051c8d4109e"
  #       params: {
  #         effective: "2023-01-01"
  #         metadata: "{}"
  #       }
  #     }
  #    ) {
  #      transactions {
  #        transactionId
  #      }
  #    }
  # }

  # continue allows workflow to progress to submit
  # the fee will still apply depending on whether a REIMBURSE_FEE occurred

  # continue: workflow {
  #   executeTask(
  #     input: {
  #       task: "CONTINUE"
  #       workflowId: "934498b5-b4f1-46c4-ad79-868939dc39e8"
  #       executionId: "34d499dd-d061-42f4-af42-c051c8d4109e"
  #       params: {
  #         effective: "2023-01-01"
  #         metadata: "{}"
  #       }
  #     }
  #    ) {
  #      transactions {
  #        transactionId
  #      }
  #    }
  # }

  # submit means in an ach file on the way to Fed.
  submit: workflow {
    executeTask(
      input: {
        task: "SUBMIT"
        workflowId: "934498b5-b4f1-46c4-ad79-868939dc39e8"
        executionId: "34d499dd-d061-42f4-af42-c051c8d4109e"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  # fee can be reimbursed after SUBMIT

  # reimburse: workflow {
  #   executeTask(
  #     input: {
  #       task: "REIMBURSE_FEE"
  #       workflowId: "934498b5-b4f1-46c4-ad79-868939dc39e8"
  #       executionId: "34d499dd-d061-42f4-af42-c051c8d4109e"
  #       params: {
  #         effective: "2023-01-01"
  #         metadata: "{}"
  #       }
  #     }
  #    ) {
  #      transactions {
  #        transactionId
  #      }
  #    }
  # }

  # The external institution returned the ACH.
  return: workflow {
    executeTask(
      input: {
        task: "RETURN"
        workflowId: "934498b5-b4f1-46c4-ad79-868939dc39e8"
        executionId: "34d499dd-d061-42f4-af42-c051c8d4109e"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  # fee can be reimbursed after RETURN

  # reimburse: workflow {
  #   execute(
  #     input: {
  #       task: "REIMBURSE_FEE"
  #       workflowId: "934498b5-b4f1-46c4-ad79-868939dc39e8"
  #       executionId: "34d499dd-d061-42f4-af42-c051c8d4109e"
  #       params: {
  #         effective: "2023-01-01"
  #         metadata: "{}"
  #       }
  #     }
  #   )
  # }
}
```
**Response**

```json
{
  "data": {
    "create": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_PENDING_DR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_PENDING_CR"
                }
              ]
            }
          },
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "0.50"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_FEE_DR"
                },
                {
                  "amount": {
                    "units": "0.50"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_FEE_CR"
                }
              ]
            }
          }
        ]
      }
    },
    "return": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_SETTLE_RETURN_CR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_SETTLE_RETURN_DR"
                }
              ]
            }
          }
        ]
      }
    },
    "submit": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_SETTLE_DR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_SETTLE_CR"
                }
              ]
            }
          },
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_PENDING_REVERSAL_DR"
                },
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_PENDING_REVERSAL_CR"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
```
**Variables**

```json
{
  "accountId": "f0e4d71e-fc44-41ea-8e10-bd4b039885f1",
  "journalId": "00000000-0000-0000-0000-000000000000",
  "settlementAccountId": "7c923aed-a5fc-4ded-b2f0-57db45a8b545",
  "feeAccountId": "4d79af07-acd9-4a44-8291-78a573ced41d"
}
```

#### ODFI Pull

| State  | Valid From     | Description                                                                        |
|--------|----------------|------------------------------------------------------------------------------------|
| CREATE |                | Credit customer account from an external account at `ENCUMBRANCE` layer.           |
| CANCEL | CREATE         | Cancel transfer if before ACH batch cutoff.                                        |
| SUBMIT | CREATE         | Submit transfer in ACH file. Post at `PENDING` layer until settlement.             |
| SETTLE | SUBMIT         | After 3 days without return, post transfer to `SETTLED` layer.                     |
| RETURN | SUBMIT, SETTLE | If received a return, send funds from customer account back to settlement account. |

**Request**

```graphql
mutation ODFIPull(
  $accountId: UUID!
  $journalId: UUID!
  $settlementAccountId: UUID!
) {
  # Transfer will happen in next batch. Funds credited at ENCUMBRANCE layer
  create: workflow {
    executeTask(
      input: {
        task: "CREATE"
        workflowId: "064e3b76-6072-451e-aace-5a7be3704ee2"
        executionId: "3d4875e5-119d-47fe-9a5c-a0064ba8c5a8"
        params: {
          accountId: $accountId
          settlementAccountId: $settlementAccountId
          journalId: $journalId
          amount: "1.00"
          effective: "2023-01-01"
          metadata: "{}"
        }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  # Can cancel after create

  # cancel: workflow {
  #   executeTask(
  #     input: {
  #       task: "CANCEL"
  #       workflowId: "064e3b76-6072-451e-aace-5a7be3704ee2"
  #       executionId: "3d4875e5-119d-47fe-9a5c-a0064ba8c5a8"
  #       params: {
  #         effective: "2023-01-01"
  #         metadata: "{}"
  #       }
  #     }
  #   ) {
  #     transactions {
  #      transactionId
  #     }
  #   }
  # }

  # Can undo cancellation

  # continue: workflow {
  #   executeTask(
  #     input: {
  #       task: "CONTINUE"
  #       workflowId: "064e3b76-6072-451e-aace-5a7be3704ee2"
  #       executionId: "3d4875e5-119d-47fe-9a5c-a0064ba8c5a8"
  #       params: {
  #         effective: "2023-01-01"
  #         metadata: "{}"
  #       }
  #     }
  #   ) {
  #    transactions {
  #      transactionId
  #    }
  #  }
  # }

  # Transfer is in the ACH file. Funds are credited at PENDING layer.
  submit: workflow {
    executeTask(
      input: {
        task: "SUBMIT"
        workflowId: "064e3b76-6072-451e-aace-5a7be3704ee2"
        executionId: "3d4875e5-119d-47fe-9a5c-a0064ba8c5a8"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  # Invoked after three days without return. Funds are credited at SETTLED layer.
  settle: workflow {
    executeTask(
      input: {
        task: "SETTLE"
        workflowId: "064e3b76-6072-451e-aace-5a7be3704ee2"
        executionId: "3d4875e5-119d-47fe-9a5c-a0064ba8c5a8"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  # A return is recieved, move funds back to settlement account.
  return: workflow {
    executeTask(
      input: {
        task: "RETURN"
        workflowId: "064e3b76-6072-451e-aace-5a7be3704ee2"
        executionId: "3d4875e5-119d-47fe-9a5c-a0064ba8c5a8"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "create": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_ENCUMBRANCE_CR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_ENCUMBRANCE_DR"
                }
              ]
            }
          }
        ]
      }
    },
    "return": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_SETTLE_RETURN_DR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_SETTLE_RETURN_CR"
                }
              ]
            }
          }
        ]
      }
    },
    "settle": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_ENCUMBRANCE_REVERSAL_CR"
                },
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_ENCUMBRANCE_REVERSAL_DR"
                }
              ]
            }
          },
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_SETTLE_CR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_SETTLE_DR"
                }
              ]
            }
          }
        ]
      }
    },
    "submit": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_ENCUMBRANCE_REVERSAL_CR"
                },
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_ENCUMBRANCE_REVERSAL_DR"
                }
              ]
            }
          },
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_ENCUMBRANCE_CR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_ENCUMBRANCE_DR"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
```
**Variables**

```json
{
  "accountId": "f0e4d71e-fc44-41ea-8e10-bd4b039885f1",
  "journalId": "00000000-0000-0000-0000-000000000000",
  "settlementAccountId": "7c923aed-a5fc-4ded-b2f0-57db45a8b545",
  "feeAccountId": "4d79af07-acd9-4a44-8291-78a573ced41d"
}
```

#### RDFI Credit

| State  | Valid From     | Description                                                     |
|--------|----------------|-----------------------------------------------------------------|
| CREATE |                | Creates an encumbrance credit, funds will deposit into account. |
| SETTLE | CREATE         | Funds are now settled.                                          |
| RETURN | SETTLE, CREATE | Returned funds to originating institution.                      |

**Request**

```graphql
mutation RDFICredit(
  $accountId: UUID!
  $journalId: UUID!
  $settlementAccountId: UUID!
) {
  # ACH is in file effective for future, put in PENDING layer
  create: workflow {
    executeTask(
      input: {
        task: "CREATE"
        workflowId: "44d71180-6db2-437e-9083-6ba672f41ba2"
        executionId: "779b773c-f7a3-41f3-905b-5934dcda8932"
        params: {
          accountId: $accountId
          settlementAccountId: $settlementAccountId
          journalId: $journalId
          amount: "1.00"
          effective: "2023-01-01"
          metadata: "{}"
        }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  # Reached the effective date, put into SETTLED layer.
  settle: workflow {
    executeTask(
      input: {
        task: "SETTLE"
        workflowId: "44d71180-6db2-437e-9083-6ba672f41ba2"
        executionId: "779b773c-f7a3-41f3-905b-5934dcda8932"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  # Initiate a return of funds to the settlement account.
  return: workflow {
    executeTask(
      input: {
        task: "RETURN"
        workflowId: "44d71180-6db2-437e-9083-6ba672f41ba2"
        executionId: "779b773c-f7a3-41f3-905b-5934dcda8932"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "create": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_ENCUMBRANCE_CR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_ENCUMBRANCE_DR"
                }
              ]
            }
          }
        ]
      }
    },
    "return": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_SETTLE_RETURN_DR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_SETTLE_RETURN_CR"
                }
              ]
            }
          }
        ]
      }
    },
    "settle": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_ENCUMBRANCE_REVERSAL_CR"
                },
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_ENCUMBRANCE_REVERSAL_DR"
                }
              ]
            }
          },
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_SETTLE_CR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_SETTLE_DR"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
```
**Variables**

```json
{
  "accountId": "f0e4d71e-fc44-41ea-8e10-bd4b039885f1",
  "journalId": "00000000-0000-0000-0000-000000000000",
  "settlementAccountId": "7c923aed-a5fc-4ded-b2f0-57db45a8b545",
  "feeAccountId": "4d79af07-acd9-4a44-8291-78a573ced41d"
}
```

#### RDFI Debit

| State  | Valid From     | Description                                                   |
|--------|----------------|---------------------------------------------------------------|
| CREATE |                | Creates and encumbrance debit, funds will debit from account. |
| SETTLE | CREATE         | Funds are now settled.                                        |
| RETURN | CREATE, SETTLE | Initiated a return, funds credit back to customer account.    |

**Request**

```graphql
mutation RDFIDebit(
  $accountId: UUID!
  $journalId: UUID!
  $settlementAccountId: UUID!
) {
  create: workflow {
    executeTask(
      input: {
        task: "CREATE"
        workflowId: "c9085474-0b55-4bda-a279-04535d7cb8b7"
        executionId: "e3271c9d-cdcf-4f38-af96-a3916219f611"
        params: {
          accountId: $accountId
          settlementAccountId: $settlementAccountId
          journalId: $journalId
          amount: "1.00"
          effective: "2023-01-01"
          metadata: "{}"
        }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  settle: workflow {
    executeTask(
      input: {
        task: "SETTLE"
        workflowId: "c9085474-0b55-4bda-a279-04535d7cb8b7"
        executionId: "e3271c9d-cdcf-4f38-af96-a3916219f611"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  return: workflow {
    executeTask(
      input: {
        task: "RETURN"
        workflowId: "c9085474-0b55-4bda-a279-04535d7cb8b7"
        executionId: "e3271c9d-cdcf-4f38-af96-a3916219f611"
        params: { effective: "2023-01-01", metadata: "{}" }
      }
    ) {
      transactions {
        entries(first: 4) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "create": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_ENCUMBRANCE_DR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_ENCUMBRANCE_CR"
                }
              ]
            }
          }
        ]
      }
    },
    "return": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_SETTLE_RETURN_CR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_SETTLE_RETURN_DR"
                }
              ]
            }
          }
        ]
      }
    },
    "settle": {
      "executeTask": {
        "transactions": [
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_ENCUMBRANCE_REVERSAL_DR"
                },
                {
                  "amount": {
                    "units": "-1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_ENCUMBRANCE_REVERSAL_CR"
                }
              ]
            }
          },
          {
            "entries": {
              "nodes": [
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "DEBIT",
                  "entryType": "ACH_SETTLE_DR"
                },
                {
                  "amount": {
                    "units": "1.00"
                  },
                  "direction": "CREDIT",
                  "entryType": "ACH_SETTLE_CR"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
```
**Variables**

```json
{
  "accountId": "f0e4d71e-fc44-41ea-8e10-bd4b039885f1",
  "journalId": "00000000-0000-0000-0000-000000000000",
  "settlementAccountId": "7c923aed-a5fc-4ded-b2f0-57db45a8b545",
  "feeAccountId": "4d79af07-acd9-4a44-8291-78a573ced41d"
}
```

## Clearing Settlements

The cash account is an important one for double entry accounting. This is account is the mechanism for getting money from the outside world into and out of your system.  In our case there are several accounts that may interact with the outside world and change the total cash position of the system:

- Settlement Accounts
  - Cards
  - ACH
- Revenue accounts
- Disputes and other operational accounts

These accounts will be "cleared" in bulk with the aggregate amount at the time of clearing.  Let's say you have $2M in card debits on a particular day across 2 transactions. Where your starting cash balance is $100M

| DR                 | CR              | Balances                    |
|--------------------|-----------------|-----------------------------|
| $2M Card Settle    | $2M Cash        | Card Settle ($2M), Cash $98 |
| $1M Deposit Acct 1 | $1M Card Settle | Card Settle($1M)            |
| $1m Deposit Acct 2 | $1M Card Settle | Card Settle $0              |

This bulk clearing to get funds on/off the platform should be conducted with it's own tran codes.  These settlement accounts are often backed by an account at a bank, and so the balances of these accounts should be reconciled with your representation of them in your accounting system.

**Request**

```graphql
mutation ClearingTranCode($clearing: TranCodeInput!) {
  createTranCode(input: $clearing) {
    ...TC
  }
}

fragment TC on TranCode {
  tranCodeId
  code
  description
  params {
    name
    type
    default
    description
  }
  transaction {
    effective
    journalId
    correlationId
    externalId
    description
    metadata
  }
  entries {
    entryType
    accountId
    layer
    direction
    units
    currency
    description
    metadata
    condition
  }
}
```
**Response**

```json
{
  "data": {
    "createTranCode": {
      "tranCodeId": "2cc6935d-ca90-40a6-8420-b9054775d6b8",
      "code": "CLEARING",
      "description": "Clear funds between cash and settlement accounts.",
      "params": [
        {
          "name": "settlementAccount",
          "type": "UUID",
          "default": null,
          "description": "The settlement account to use."
        },
        {
          "name": "cashAccount",
          "type": "UUID",
          "default": "db07e5cf-6cd7-4629-a952-9613578cd8ea",
          "description": "The cash account to use."
        },
        {
          "name": "journal",
          "type": "UUID",
          "default": "00000000-0000-0000-0000-000000000000",
          "description": "The journal to post transactions to."
        },
        {
          "name": "amount",
          "type": "STRING",
          "default": null,
          "description": "The amount to clear."
        },
        {
          "name": "currency",
          "type": "STRING",
          "default": "USD",
          "description": "The currency of the clearance."
        },
        {
          "name": "direction",
          "type": "STRING",
          "default": "DEBIT",
          "description": "CREDIT or DEBIT direction of clearing. DEBIT raises cash account balance. CREDIT lowers."
        },
        {
          "name": "correlation",
          "type": "STRING",
          "default": null,
          "description": "Correlation identifier to group related transactions."
        },
        {
          "name": "effective",
          "type": "DATE",
          "default": null,
          "description": "Effective date for the transaction."
        },
        {
          "name": "metadata",
          "type": "JSON",
          "default": "{}",
          "description": "Effective date for the transaction."
        },
        {
          "name": "description",
          "type": "STRING",
          "default": "Clearing settlement.",
          "description": "describe this transaction."
        }
      ],
      "transaction": {
        "effective": "params.effective",
        "journalId": "params.journal",
        "correlationId": "params.correlation",
        "externalId": "''",
        "description": "params.description",
        "metadata": "params.metadata"
      },
      "entries": [
        {
          "entryType": "'CLEARING_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
          "accountId": "uuid(params.cashAccount)",
          "layer": "SETTLED",
          "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
          "units": "params.amount",
          "currency": "params.currency",
          "description": "params.description",
          "metadata": "{}",
          "condition": null
        },
        {
          "entryType": "'CLEARING_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
          "accountId": "uuid(params.settlementAccount)",
          "layer": "SETTLED",
          "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
          "units": "params.amount",
          "currency": "params.currency",
          "description": "params.description",
          "metadata": "{}",
          "condition": null
        }
      ]
    }
  }
}
```
**Variables**

```json
{
  "clearing": {
    "tranCodeId": "2cc6935d-ca90-40a6-8420-b9054775d6b8",
    "code": "CLEARING",
    "description": "Clear funds between cash and settlement accounts.",
    "params": [
      {
        "name": "settlementAccount",
        "type": "UUID",
        "default": null,
        "description": "The settlement account to use."
      },
      {
        "name": "cashAccount",
        "type": "UUID",
        "default": "db07e5cf-6cd7-4629-a952-9613578cd8ea",
        "description": "The cash account to use."
      },
      {
        "name": "journal",
        "type": "UUID",
        "default": "00000000-0000-0000-0000-000000000000",
        "description": "The journal to post transactions to."
      },
      {
        "name": "amount",
        "type": "STRING",
        "default": null,
        "description": "The amount to clear."
      },
      {
        "name": "currency",
        "type": "STRING",
        "default": "USD",
        "description": "The currency of the clearance."
      },
      {
        "name": "direction",
        "type": "STRING",
        "default": "DEBIT",
        "description": "CREDIT or DEBIT direction of clearing. DEBIT raises cash account balance. CREDIT lowers."
      },
      {
        "name": "correlation",
        "type": "STRING",
        "default": null,
        "description": "Correlation identifier to group related transactions."
      },
      {
        "name": "effective",
        "type": "DATE",
        "default": null,
        "description": "Effective date for the transaction."
      },
      {
        "name": "metadata",
        "type": "JSON",
        "default": "{}",
        "description": "Effective date for the transaction."
      },
      {
        "name": "description",
        "type": "STRING",
        "default": "Clearing settlement.",
        "description": "describe this transaction."
      }
    ],
    "transaction": {
      "effective": "params.effective",
      "journalId": "params.journal",
      "correlationId": "params.correlation",
      "externalId": "''",
      "description": "params.description",
      "metadata": "params.metadata"
    },
    "entries": [
      {
        "entryType": "'CLEARING_'+string(params.direction == 'DEBIT' ? 'DR' : 'CR')",
        "accountId": "uuid(params.cashAccount)",
        "layer": "SETTLED",
        "direction": "params.direction == 'DEBIT' ? DEBIT : CREDIT",
        "units": "params.amount",
        "currency": "params.currency",
        "description": "params.description",
        "metadata": "{}",
        "condition": null
      },
      {
        "entryType": "'CLEARING_'+ string(params.direction == 'DEBIT' ? 'CR' : 'DR')",
        "accountId": "uuid(params.settlementAccount)",
        "layer": "SETTLED",
        "direction": "params.direction == 'DEBIT' ? CREDIT : DEBIT",
        "units": "params.amount",
        "currency": "params.currency",
        "description": "params.description",
        "metadata": "{}",
        "condition": null
      }
    ]
  }
}
```

## Advanced Topics

As we've seen, Tran Codes are a powerful abstraction to encapsulate accounting concerns inside of Twisp.  We also explored one workflow that Twisp offers for ACH transactions, to automatically handle posting and voiding transactions to a customers account for each part of an ACH lifecycle.

Twisp offers several other workflows that may be useful for interacting with the accounting core. In this section we'll briefly examine each one.

### Void And Post Workflow

The Void and Post workflow is a powerful mechanism for modeling a transaction that may change layers and amounts over time.  In essence a single transaction identifier, the `executionId` passed to the workflow, will void the prior transaction created by the workflow and create a new transaction with the tran code you've provided to the workflow.

This allows for some powerful transaction modeling. Consider the earlier section on card holds. In that you may be composing together two graphql queries:

- `voidTransaction` to void the "prior authorization"
- `postTransaction` to post the new authorization value

With the void and post workflow, we can use a single identifier for the "authorization" and update it without needing to keep track of multiple transaction ids.  Consider this example which posts an authorization and then updates it.

**Request**

```graphql
mutation VoidAndPost(
  $authorizationId: UUID!
  $accountId: UUID!
  $correlation: String
  $amount: Decimal!
  $updatedAmount: Decimal!
  $effective: Date
) {
  originalAuth: workflow {
    executeTask(
      input: {
        workflowId: "c97010ac-f703-4112-8bb3-493ec0c2dfd4"
        executionId: $authorizationId
        task: "VOID_AND_POST"
        params: {
          tranCode: "CARD_HOLD"
          account: $accountId
          amount: $amount
          correlation: $correlation
          effective: $effective
        }
      }
    ) {
      transactions {
        transactionId
        entries(first: 10) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }

  updatedAuth: workflow {
    executeTask(
      input: {
        workflowId: "c97010ac-f703-4112-8bb3-493ec0c2dfd4"
        executionId: $authorizationId
        task: "VOID_AND_POST"
        params: {
          tranCode: "CARD_HOLD"
          account: $accountId
          amount: $updatedAmount
          correlation: $correlation
          effective: $effective
        }
      }
    ) {
      transactions {
        transactionId
        entries(first: 10) {
          nodes {
            entryType
            direction
            amount {
              units
            }
          }
        }
      }
    }
  }
}
```
**Response**

```json
{
  "data": {
    "originalAuth": {
      "executeTask": {
        "transactions": [
          {
            "transactionId": "edcc3942-3c4f-5d40-8fa7-0a2cbc068631",
            "entries": {
              "nodes": [
                {
                  "entryType": "CARD_HOLD_DR",
                  "direction": "DEBIT",
                  "amount": {
                    "units": "10.00"
                  }
                },
                {
                  "entryType": "CARD_HOLD_CR",
                  "direction": "CREDIT",
                  "amount": {
                    "units": "10.00"
                  }
                }
              ]
            }
          }
        ]
      }
    },
    "updatedAuth": {
      "executeTask": {
        "transactions": [
          {
            "transactionId": "fed601a6-ce71-5760-8dbc-5ec5e392ff29",
            "entries": {
              "nodes": [
                {
                  "entryType": "CARD_HOLD_DR_VOID",
                  "direction": "DEBIT",
                  "amount": {
                    "units": "-10.00"
                  }
                },
                {
                  "entryType": "CARD_HOLD_CR_VOID",
                  "direction": "CREDIT",
                  "amount": {
                    "units": "-10.00"
                  }
                }
              ]
            }
          },
          {
            "transactionId": "bdcdac07-29fc-5f5f-9e65-9b9a37241c9c",
            "entries": {
              "nodes": [
                {
                  "entryType": "CARD_HOLD_DR",
                  "direction": "DEBIT",
                  "amount": {
                    "units": "15.00"
                  }
                },
                {
                  "entryType": "CARD_HOLD_CR",
                  "direction": "CREDIT",
                  "amount": {
                    "units": "15.00"
                  }
                }
              ]
            }
          }
        ]
      }
    }
  }
}
```
**Variables**

```json
{
  "accountId": "7a17b0f1-b04f-46a4-ba45-d52a861c21d9",
  "amount": "10.00",
  "updatedAmount": "15.00",
  "authorizationId": "a60f3df6-a1e8-4c04-bac2-bc9d15e94bc3",
  "correlation": "2f05a4d4-07c5-42c1-a567-438737b7a0ab",
  "effective": "2022-10-01"
}
```

### States Language Workflow

GraphQL is an extremely expressive querying language, however sometimes it requires multiple interactions to serve a request. Take for example the card authorization use case:

- Optimistically post transaction
- Check if any balances are violated
- Void if one of the balances is violated
- Indicate in response if transaction is Approved or Declined

There could possibly be 2-3 network calls to Twisp to fulfill this use case with just the GraphQL api interacting with your application. However, if you want to accomplish all of this _transactionally_ in Twisp, we support defining state machines using [States Language](https://states-language.net/) that allows you to cooridnate multiple api calls.

In the following example:

- post a `CARD_HOLD` optimistically to a card account
- check the balance of the parent deposit account set
- if the balance is less than zero we void
- return either a `Declined` or `Approved` message based on the balance

> **Tip:**
>
> This feature is not yet GA but we're looking to ship in the next few days.

**Request**

```graphql
mutation PostCheckAndVoid(
  $authorizationVariables: JSON!
  $machine: StateMachine!
) {
  workflow {
    executeStatesLanguage(
      input: { input: $authorizationVariables, machine: $machine }
    ) {
      output
    }
  }
}
```
**Response**

```json
{
  "data": {
    "workflow": {
      "executeStatesLanguage": {
        "output": {
          "message": "Declined",
          "variables": {
            "balance": "-291.00",
            "hasBalance": true,
            "shouldVoid": true,
            "transactionId": "772269e7-4c11-4375-bc3d-587fed54b2ea",
            "voided": {
              "voidTransaction": {
                "transactionId": "a97b893f-cf69-54f8-ac51-afa5d6f789ff"
              }
            }
          }
        }
      }
    }
  }
}
```
**Variables**

```json
{
  "machine": {
    "Id": "c4edf3bd-ae11-490f-98bc-f3d9547bc516",
    "Name": "PostAndVoid",
    "AwsStatesLanguage": {
      "Comment": "Post a transaction and void if balance is lt zero.",
      "StartAt": "Post",
      "States": {
        "Post": {
          "Type": "Task",
          "Resource": "arn:twisp:workflow:::financial/v1/graphql",
          "Parameters": {
            "query": "mutation Auth(\n  $authorizationId: UUID!\n  $accountId: UUID!\n  $correlation: String\n  $amount: Decimal!\n  $effective: Date\n){\n  postTransaction(\n    input:{\n      transactionId: $authorizationId\n      tranCode: \"CARD_HOLD\"\n      params: {\n        account: $accountId\n        amount: $amount\n        correlation: $correlation\n        effective: $effective\n        metadata: \"{}\"\n    }\n  }\n) {\n  transactionId\n}}\n",
            "variables": {
              "authorizationId.$": "$.authorizationId",
              "accountId.$": "$.accountId",
              "amount.$": "$.amount",
              "correlation.$": "$.correlation",
              "effective.$": "$.effective"
            }
          },
          "ResultSelector": {
            "transactionId.$": "$.postTransaction.transactionId"
          },
          "ResultPath": "$.variables.posted",
          "Next": "CheckBalance"
        },
        "CheckBalance": {
          "Type": "Task",
          "Resource": "arn:twisp:workflow:::financial/v1/graphql",
          "Parameters": {
            "query": "query CheckBalance($accountId: UUID!) {\n  account(\n    id: $accountId\n  ) {\n    sets(first:1) {\n      nodes {\n        sets(first:1) {\n          nodes {\n            balance {\n              available(layer:PENDING) {\n                normalBalance {\n                  units\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }}\n",
            "variables.$": "$.variables"
          },
          "ResultPath": "$.balance",
          "Next": "FormatResult"
        },
        "FormatResult": {
          "Type": "Task",
          "Resource": "arn:twisp:workflow:::cel",
          "Parameters": {
            "variables": {
              "hasBalance": "size(context.workflows.this.CheckBalance.balance.account.sets.nodes) > 0 && size(context.workflows.this.CheckBalance.balance.account.sets.nodes[0].sets.nodes) > 0",
              "balance": "this.hasBalance ? context.workflows.this.CheckBalance.balance.account.sets.nodes[0].sets.nodes[0].balance.available.normalBalance.units : decimal('0')",
              "shouldVoid": "decimal(this.balance) <= decimal('0')",
              "transactionId": "context.workflows.this.CheckBalance.variables.posted.transactionId"
            }
          },
          "Next": "ShouldVoid"
        },
        "ShouldVoid": {
          "Type": "Choice",
          "Default": "Approved",
          "Choices": [
            {
              "Variable": "$.variables.shouldVoid",
              "BooleanEquals": true,
              "Next": "Void"
            }
          ]
        },
        "Void": {
          "Type": "Task",
          "Resource": "arn:twisp:workflow:::financial/v1/graphql",
          "Parameters": {
            "query": "mutation VoidTransaction($transactionId: UUID!) {\n  voidTransaction(id: $transactionId) { transactionId }\n}\n",
            "variables.$": "$.variables"
          },
          "ResultPath": "$.variables.voided",
          "Next": "Declined"
        },
        "Approved": {
          "Type": "Pass",
          "Parameters": {
            "message": "Approved",
            "variables.$": "$.variables"
          },
          "End": true
        },
        "Declined": {
          "Type": "Pass",
          "Parameters": {
            "message": "Declined",
            "variables.$": "$.variables"
          },
          "End": true
        }
      }
    }
  },
  "authorizationVariables": {
    "accountId": "f0e4d71e-fc44-41ea-8e10-bd4b039885f1",
    "amount": "10.00",
    "authorizationId": "772269e7-4c11-4375-bc3d-587fed54b2ea",
    "correlation": "2f05a4d4-07c5-42c1-a567-438737b7a0ab",
    "effective": "2022-10-01"
  }
}
```

### Custom Balance Computations

By default Twisp rolls up balances on a number of dimensions:

- journal
- account
- currency

Twisp offers the ability to compute balances on additional dimensions. For example, often fintechs will put limits in per MCC code or perhaps on daily, weekly, monthly or yearly spending limits.  These are supported in Twisp via [Balance Calculations](/docs/reference/graphql/mutations#create-calculation).  Once you've created a balance calcuation, you may look up balance on that calculation via the balances endpoint by supplying the `calculationId` and `dimension` values you're interested in. For example, for the above calculation:

```graphql
query GetJan12020EffectiveBalance($accountId: UUID!) {
  balance(
    accountId: $accountId
    currency: "USD"
    calculationId: "5867b5dd-fc69-416c-80f5-62e8a53610d5"
    dimension: {
        effectiveDate: "2020-01-01"
    }
  ) {
    available(layer:PENDING) {
        normalBalance {
            units
        }
    }
  }
}
```
