> ## Documentation Index
> Fetch the complete documentation index at: https://endclose.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Concepts

> Learn about the core resources in End Close

End Close is a reconciliation platform that helps you match financial records across different systems. You push data from your various sources into End Close, define rules for how records should match, and the platform automatically reconciles them.

The API is organized around three core resources: **Data Streams**, **Records**, and **Property Definitions**. Together, these let you model your financial data, push it into End Close, and track reconciliation status.

## Data Streams

A data stream represents a system or feed that produces financial records — for example, your bank, your payment processor, or an internal ledger. Every record in End Close belongs to exactly one data stream.

Each data stream has a `key` (a unique, immutable identifier you define) and a `name` (a human-readable label). You reference data streams by their `key` throughout the API.

```json Example theme={null}
{
  "key": "stripe_payments",
  "name": "Stripe Payments"
}
```

Data streams created through the API have a type of `api`. End Close also supports connecting data streams directly via Stripe, Snowflake, and CSV uploads through the dashboard.

<Note>
  A data stream `key` cannot be changed after creation. Choose a key that clearly identifies the system it represents.
</Note>

## Records

A record is a single financial transaction or entry within a data stream. Records are the core unit of reconciliation — End Close matches records from one data stream against records from another.

Every record requires:

| Field             | Description                                         |
| ----------------- | --------------------------------------------------- |
| `data_stream_key` | The `key` of the data stream this record belongs to |
| `date`            | The date of the transaction (ISO 8601 format)       |
| `amount`          | The monetary value                                  |
| `direction`       | Either `credit` or `debit`                          |

You can also include a `description`, an `external_id` (your own identifier for cross-referencing), and a `metadata` object for any additional structured data.

```json Example theme={null}
{
  "data_stream_key": "stripe_payments",
  "date": "2026-01-15",
  "amount": 250.00,
  "direction": "credit",
  "currency": "USD",
  "description": "Invoice #1042",
  "external_id": "pi_abc123",
  "metadata": {
    "customer_id": "cus_xyz"
  }
}
```

### Currency

Records carry a three-letter ISO 4217 `currency` code (e.g. `USD`, `EUR`, `GBP`). The field is optional on create — **if you omit it, the record is stored as `USD`**. Input is case-insensitive and normalized to uppercase, so `"usd"` and `"USD"` are equivalent. Responses always include the `currency` field.

### Reconciliation status

Each record has a `status` that reflects whether it has been matched:

* **`unreconciled`** — The record has not been matched. This is the default when a record is created.
* **`reconciled`** — The record has been matched against one or more records from another data stream.

Status is derived automatically from reconciliation matches. When a new record is created, End Close evaluates it against your reconciliation rules and attempts to find a match. You can subscribe to [webhook events](/docs/webhooks/getting_started) like `record.reconciled` and `record.reconciliation_overdue` to react to status changes.

<Warning>
  Only unreconciled records can be deleted. Reconciled records cannot be removed.
</Warning>

## Property Definitions

Property definitions let you extend records with custom fields specific to a data stream. For example, a Stripe data stream might have a `customer_email` property, while a bank feed might have a `check_number` property.

Each property definition is scoped to a single data stream (identified by `data_stream_key`) and includes:

| Field      | Description                                                         |
| ---------- | ------------------------------------------------------------------- |
| `key`      | A unique identifier for this property within the data stream        |
| `name`     | A human-readable label                                              |
| `type`     | The data type: `string`, `number`, `date`, `datetime`, or `boolean` |
| `optional` | Whether the property is required on records (defaults to `true`)    |

```json Example theme={null}
{
  "key": "customer_email",
  "name": "Customer Email",
  "type": "string",
  "optional": true,
  "data_stream_key": "stripe_payments"
}
```

Custom property values are stored in the `metadata` field of each record. Defining property definitions allows End Close to validate and display these fields in the dashboard.

## How reconciliation works

Reconciliation in End Close is configured through the dashboard. You create a **reconciliation** that links two sides of data streams (Side A and Side B), then define **rules** that control how records are matched across those sides.

When a new record is created, End Close automatically runs it against the applicable reconciliation rules. If a match is found, both records are marked as `reconciled`. If no match is found, the record stays `unreconciled` until a matching counterpart arrives.

You can monitor reconciliation results through the dashboard or by subscribing to [webhook events](/docs/webhooks/getting_started).
