Skip to main content
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 Sources, Records, and Property Definitions. Together, these let you model your financial data, push it into End Close, and track reconciliation status.

Data Sources

A data source 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 source. Each data source has a key (a unique, immutable identifier you define) and a name (a human-readable label). You reference data sources by their key throughout the API.
Example
{
  "key": "stripe_payments",
  "name": "Stripe Payments"
}
Data sources created through the API have a type of api. End Close also supports connecting data sources directly via Stripe, Snowflake, and CSV uploads through the dashboard.
A data source key cannot be changed after creation. Choose a key that clearly identifies the system it represents.

Records

A record is a single financial transaction or entry within a data source. Records are the core unit of reconciliation — End Close matches records from one data source against records from another. Every record requires:
FieldDescription
type_keyThe key of the data source this record belongs to
dateThe date of the transaction (ISO 8601 format)
amountThe monetary value
directionEither 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.
Example
{
  "type_key": "stripe_payments",
  "date": "2026-01-15",
  "amount": 250.00,
  "direction": "credit",
  "description": "Invoice #1042",
  "external_id": "pi_abc123",
  "metadata": {
    "customer_id": "cus_xyz"
  }
}

Reconciliation status

Each record has a status that tracks its reconciliation progress:
  • unreconciled — The record has not been matched. This is the default status when a record is created.
  • partially_reconciled — The record has been matched, but not for its full amount.
  • reconciled — The record has been fully matched against one or more records from another data source.
When a new record is created, End Close automatically evaluates it against your reconciliation rules and attempts to find a match. You can subscribe to webhook events like record.reconciled and record.reconciliation_overdue to react to status changes.
Only records with a status of unreconciled can be deleted. Records that are partially or fully reconciled cannot be removed.

Property Definitions

Property definitions let you extend records with custom fields specific to a data source. For example, a Stripe data source 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 source (identified by type_key) and includes:
FieldDescription
keyA unique identifier for this property within the data source
nameA human-readable label
typeThe data type: string, number, date, datetime, or boolean
optionalWhether the property is required on records (defaults to true)
Example
{
  "key": "customer_email",
  "name": "Customer Email",
  "type": "string",
  "optional": true,
  "type_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 sources (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 updated to reconciled (or partially_reconciled if the amounts don’t fully offset). 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.