End Close Reconciliations API
The Reconciliations API from End Close — 4 operation(s) for reconciliations.
The Reconciliations API from End Close — 4 operation(s) for reconciliations.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/end-close:end-close-reconciliations-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: End Close Reconciliations API
description: REST API is used to interact with the End Close platform.
license:
name: MIT
version: 1.0.0
servers:
- url: https://api.endclose.com/v1
security:
- ApiKeyAuth: []
tags:
- name: Reconciliations
paths:
/reconciliations/{reconciliation_id}/records/{record_id}/mark_overdue:
post:
summary: Mark a record as overdue
description: Flags a record as overdue within a specific reconciliation by setting the `overdue_at` timestamp on its reconciliation entry. The reconciliation and record are both named in the path — the subject is the (reconciliation, record) entry, so the same record can be overdue in one reconciliation and matched in another. The record's data stream must be part of the reconciliation. If no entry exists yet for the record and reconciliation, one is created so unmatched records can be flagged as overdue. Records already matched in this reconciliation cannot be marked overdue. Once overdue, the record is picked up by the exceptions sweeper and rolled into the data-stream-scoped exception for that reconciliation.
parameters:
- in: path
name: reconciliation_id
required: true
schema:
type: string
description: The unique identifier of the reconciliation the record should be marked overdue in
- in: path
name: record_id
required: true
schema:
type: string
description: The unique identifier of the record
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
overdue_at:
type: string
format: date-time
description: When the record should be considered overdue. Defaults to the current time.
responses:
'200':
description: The record's entry in the given reconciliation
content:
application/json:
schema:
$ref: '#/components/schemas/ReconciliationEntry'
'401':
description: Unauthorized
'404':
description: Record or reconciliation not found
'409':
description: Record is already matched in this reconciliation and cannot be marked overdue
'422':
description: Record's data stream is not part of the reconciliation, or invalid `overdue_at`
tags:
- Reconciliations
operationId: postReconciliationsByReconciliationIdRecordsByRecordIdMarkOverdue
x-operation-id-source: derived
/reconciliations:
get:
summary: List reconciliations
description: Returns a paginated list of reconciliations with their associated data streams, newest first.
parameters:
- in: query
name: cursor
required: false
schema:
type: string
description: Opaque cursor from a previous response's `next_cursor`. Omit for the first page.
- in: query
name: limit
required: false
schema:
type: integer
minimum: 1
maximum: 200
default: 50
responses:
'200':
description: Paginated list of reconciliations
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Reconciliation'
next_cursor:
type: string
nullable: true
description: Opaque cursor for the next page. Null when no more pages.
limit:
type: integer
tags:
- Reconciliations
operationId: getReconciliations
x-operation-id-source: derived
post:
summary: Create a reconciliation
description: Create a new reconciliation with optional side A and side B data stream associations.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- name
properties:
name:
type: string
run_type:
type: string
enum:
- continuous
- batch
default: continuous
side_a_stream_ids:
type: array
items:
type: string
description: IDs of data streams to assign to side A
side_b_stream_ids:
type: array
items:
type: string
description: IDs of data streams to assign to side B
responses:
'201':
description: Reconciliation created
content:
application/json:
schema:
$ref: '#/components/schemas/Reconciliation'
'422':
description: Validation error
tags:
- Reconciliations
operationId: postReconciliations
x-operation-id-source: derived
/reconciliations/{id}:
get:
summary: Retrieve a reconciliation
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
description: Reconciliation retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/Reconciliation'
'404':
description: Reconciliation not found
tags:
- Reconciliations
operationId: getReconciliationsById
x-operation-id-source: derived
patch:
summary: Update a reconciliation
description: Update reconciliation name, run type, or reassign data streams. If stream IDs are provided, all existing stream associations are replaced.
parameters:
- in: path
name: id
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
run_type:
type: string
enum:
- continuous
- batch
side_a_stream_ids:
type: array
items:
type: string
side_b_stream_ids:
type: array
items:
type: string
responses:
'200':
description: Reconciliation updated
content:
application/json:
schema:
$ref: '#/components/schemas/Reconciliation'
'404':
description: Reconciliation not found
tags:
- Reconciliations
operationId: patchReconciliationsById
x-operation-id-source: derived
delete:
summary: Delete a reconciliation
description: Permanently deletes a reconciliation and all associated rules, matches, and data stream associations.
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'204':
description: Reconciliation deleted successfully
'404':
description: Reconciliation not found
tags:
- Reconciliations
operationId: deleteReconciliationsById
x-operation-id-source: derived
/reconciliations/{id}/agent_status:
get:
summary: Get reconciliation agent status
description: Returns the current status of the reconciliation agent, which automatically creates and refines matching rules. The agent runs automatically when records are uploaded or manually matched — no manual triggering is needed.
parameters:
- in: path
name: id
required: true
schema:
type: string
description: The reconciliation ID
responses:
'200':
description: Agent status
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum:
- idle
- running
- failed
description: Current agent status
last_run_at:
type: string
format: date-time
nullable: true
description: When the agent last ran
progress:
type: array
description: Ordered list of progress steps from the last run
items:
type: object
properties:
step:
type: string
message:
type: string
at:
type: string
format: date-time
reasoning:
type: string
nullable: true
description: AI reasoning from the last rule analysis
rules_count:
type: integer
description: Number of active rules on this reconciliation
unmatched_count:
type: integer
description: Number of unreconciled records across both sides
'404':
description: Reconciliation not found
tags:
- Reconciliations
operationId: getReconciliationsByIdAgentStatus
x-operation-id-source: derived
/reconciliations/{reconciliation_id}/data_streams/{data_stream_id}/findings:
put:
summary: Write findings for a data stream's lines
description: The same upsert as `PUT /reconciliation_exceptions/{id}/findings`, for an engine that runs before the sweeper has opened an exception. Opens the exception for the (reconciliation, data stream) pair if none is open, reuses it otherwise, and returns its id with the result.
parameters:
- in: path
name: reconciliation_id
required: true
schema:
type: string
- in: path
name: data_stream_id
required: true
schema:
type: string
description: The data stream whose records the findings are about. Must be part of the reconciliation.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FindingsUpsertRequest'
responses:
'200':
description: Findings written against the open exception
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/FindingsUpsertResult'
- type: object
properties:
exception_id:
type: string
description: The open exception the findings were written to
'401':
description: Unauthorized
'404':
description: Reconciliation or data stream not found
'422':
description: Data stream is not part of the reconciliation, or `findings` is invalid
tags:
- Reconciliations
operationId: putReconciliationsByReconciliationIdDataStreamsByDataStreamIdFindings
x-operation-id-source: derived
components:
schemas:
FindingInput:
type: object
required:
- note
description: One line of the review as your engine sees it. Identify the record by `record_id` or by `external_id` (resolved within the exception's data stream). `suggestion.record_ids` may be record ids or external ids from either side of the reconciliation; unknown ids reject the finding.
properties:
record_id:
type: string
description: The record's id. Required unless `external_id` is given.
external_id:
type: string
description: The record's external id within the exception's data stream. Rejected when it matches more than one record.
looks_right:
type: boolean
default: false
description: '`true` when the line is correct as it stands and only needs the note. These lines can be confirmed in bulk.'
note:
type: string
description: 'One or two plain sentences: what happened to this line and what was checked.'
category:
type: string
nullable: true
description: A short label for the kind of line, in your own words (e.g. `back-billing`, `monthly minimum`).
suggestion:
type: object
description: What Approve applies. Omit, or use kind `none`, when there is nothing to apply.
properties:
kind:
type: string
enum:
- match
- adjust
- none
default: none
description: '`match`: pair the line with `record_ids` (must balance). `adjust`: pair them and plug the remaining gap with an adjustment carrying `reason`. `none`: nothing to apply.'
record_ids:
type: array
items:
type: string
description: Every other record of the proposed match, either side, as record ids or external ids.
reason:
type: string
description: 'For `adjust`: why a gap remains. Becomes the adjustment''s description.'
text:
type: string
description: The sentence shown next to the Approve button.
difference_cents:
type: integer
description: Informational. Recomputed from the records as |side A| − |side B| whenever `record_ids` is given; only kept as sent for a one-sided `adjust`.
evidence:
type: array
description: Quotes that back the note. A quote with a `url` marks the line as checked against a document in the review.
items:
type: object
required:
- quote
properties:
quote:
type: string
source:
type: string
nullable: true
description: Where the quote is from, e.g. `Services Agreement, Exhibit B p.19`.
url:
type: string
nullable: true
description: 'An http(s) link to the document — for a file in End Close, the file''s `url`. End `#page=N` to open a PDF at that page: the review drawer labels the link “Open p.N” and shows the document inline. Other schemes are dropped.'
precedent:
type: string
nullable: true
description: How the same line was handled before, in one sentence.
labels:
type: object
additionalProperties: true
description: 'Free-form markers your reviewers care about, e.g. `{"carried_forward": true, "colour": "peach"}`. The review page reads `colour`, `colour_cell` and `carried_forward`; anything else is stored and returned untouched.'
Record:
type: object
required:
- date
- data_stream_key
- amount
- direction
properties:
id:
type: integer
amount:
type: integer
description: The monetary amount in cents (e.g., 1234 = $12.34)
currency:
type: string
description: Three-letter ISO 4217 currency code (e.g. USD, EUR). **Optional on create — defaults to `USD` when omitted.** Case-insensitive on input; always returned uppercase.
pattern: ^[A-Za-z]{3}$
default: USD
decimal_places:
type: integer
description: Number of decimal places for this currency (2 for USD)
default: 2
direction:
type: string
enum:
- credit
- debit
description:
type: string
date:
type: string
format: date
metadata:
type: object
additionalProperties: true
default: {}
external_id:
type: string
data_stream_key:
type: string
ReconciliationRun:
type: object
description: A single execution of a reconciliation's batch or continuous matching pipeline.
properties:
id:
type: integer
kind:
type: string
enum:
- batch
- continuous
status:
type: string
enum:
- pending
- running
- completed
- failed
trigger:
type: string
enum:
- manual
- rule_activated
- agent
- record_created
- ingestion
description: What initiated this run. `ingestion` runs are queued automatically once an import lands, so rollup (many_to_one) rules apply to the new records.
total_records:
type: integer
description: Total records considered by the run
processed_records:
type: integer
description: Records processed so far
matched_records:
type: integer
description: Records that were matched during the run
rule_summary:
type: object
nullable: true
description: Per-rule match counts, populated as the run progresses
progress:
type: integer
description: Processing progress as a percentage (0-100)
started_at:
type: string
format: date-time
nullable: true
completed_at:
type: string
format: date-time
nullable: true
DataStream:
type: object
required:
- key
- name
properties:
id:
type: integer
description: Unique numeric identifier
key:
type: string
description: Unique immutable identifier
name:
type: string
description: Human readable name
description:
type: string
description: Optional description of the data stream
type:
type: string
description: The type of data stream (e.g. api, csv, stripe, bank_feed)
program_id:
type: integer
nullable: true
records_count:
type: integer
description: Record count from the ClickHouse mirror
FindingsUpsertRequest:
type: object
required:
- findings
properties:
findings:
type: array
maxItems: 1000
items:
$ref: '#/components/schemas/FindingInput'
ReconciliationEntry:
description: A record's entry in one reconciliation. Match status, escalation, and matched records are all scoped to that reconciliation; a record has one entry per reconciliation it participates in. `id` is the record id.
allOf:
- $ref: '#/components/schemas/Record'
- type: object
properties:
reconciliation_id:
type: integer
reconciliation_name:
type: string
status:
type: string
enum:
- reconciled
- unreconciled
description: Whether the record is matched in this reconciliation. Read-only.
escalated:
type: boolean
description: Unmatched and past its `overdue_at`.
overdue_at:
type: string
format: date-time
nullable: true
matched_records:
type: array
description: Records matched with this record in this reconciliation
items:
type: object
properties:
id:
type: integer
amount:
type: integer
description: Amount in cents
currency:
type: string
description: Three-letter ISO 4217 currency code (e.g. USD, EUR)
default: USD
decimal_places:
type: integer
default: 2
direction:
type: string
enum:
- credit
- debit
description:
type: string
date:
type: string
format: date
external_id:
type: string
data_stream_key:
type: string
reconciliation_id:
type: integer
description: The reconciliation in which this match was made
reconciliation_name:
type: string
description: Name of the reconciliation in which this match was made
days_unreconciled:
type: integer
nullable: true
description: Number of days since the record's date. Null when the record is reconciled.
exception_id:
type: integer
nullable: true
description: Open exception covering this entry's data stream when the entry is escalated. Null otherwise.
Reconciliation:
type: object
required:
- name
properties:
id:
type: integer
name:
type: string
description: Human readable name for the reconciliation
run_type:
type: string
enum:
- continuous
- batch
default: continuous
side_a_streams:
type: array
items:
$ref: '#/components/schemas/DataStream'
description: Data streams on side A of the reconciliation
side_b_streams:
type: array
items:
$ref: '#/components/schemas/DataStream'
description: Data streams on side B of the reconciliation
created_at:
type: string
format: date-time
current_run:
$ref: '#/components/schemas/ReconciliationRun'
nullable: true
description: The currently pending or running batch run, if any
last_run:
$ref: '#/components/schemas/ReconciliationRun'
nullable: true
description: The most recent completed or failed batch run, if any
FindingsUpsertResult:
type: object
description: 'Each finding is validated on its own, so a batch succeeds partially: `upserted` counts the rows written and `errors` names the rejected ones by position.'
properties:
upserted:
type: integer
errors:
type: array
items:
type: object
properties:
index:
type: integer
description: Position of the rejected finding in the request's `findings`.
record_id:
type: string
external_id:
type: string
message:
type: string
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-KEY
x-provenance:
method: harvested
publisher: End Close
source: https://www.endclose.com/docs/openapi.json
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)