End Close Reconciliation Exceptions API
The Reconciliation Exceptions API from End Close — 2 operation(s) for reconciliation exceptions.
The Reconciliation Exceptions API from End Close — 2 operation(s) for reconciliation exceptions.
openapi: 3.1.0
info:
title: End Close Bank Account Balances Reconciliation Exceptions 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: Reconciliation Exceptions
paths:
/reconciliation_exceptions:
get:
summary: List reconciliation exceptions
description: Returns a paginated list of exceptions, optionally filtered by reconciliation or status. Each row includes data-stream metadata and an aggregates summary so you can render a queue without a follow-up request per row.
parameters:
- in: query
name: reconciliation_id
schema:
type: string
description: Filter by reconciliation
- in: query
name: status
schema:
type: string
enum:
- open
- investigating
- dismissed
- resolved
description: Filter by exception status
- in: query
name: limit
schema:
type: integer
minimum: 1
maximum: 100
default: 25
- in: query
name: offset
schema:
type: integer
description: Pagination offset
responses:
'200':
description: Paginated list of exceptions
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/ReconciliationException'
has_more:
type: boolean
offset:
type: number
'401':
description: Unauthorized
tags:
- Reconciliation Exceptions
post:
summary: Create a reconciliation exception
description: Create an exception for a reconciliation and data stream. Only one `open` or `investigating` exception can exist per (data stream, reconciliation) pair at a time. `title` defaults to `"{data_stream_name} — overdue records"`, and `status` defaults to `open`. The system automatically creates exceptions via its overdue sweeper — use this endpoint when you want to open one manually.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- reconciliation_id
- data_stream_id
properties:
reconciliation_id:
type: string
description: Reconciliation the exception belongs to
data_stream_id:
type: string
description: Data stream the exception is scoped to. Must belong to the reconciliation.
title:
type: string
description:
type: string
status:
type: string
enum:
- open
- investigating
- dismissed
- resolved
default: open
responses:
'201':
description: Exception created
content:
application/json:
schema:
$ref: '#/components/schemas/ReconciliationException'
'401':
description: Unauthorized
'404':
description: Reconciliation or data stream not found
'422':
description: Validation failed, or a duplicate open/investigating exception already exists for this (data stream, reconciliation)
tags:
- Reconciliation Exceptions
/reconciliation_exceptions/{id}:
get:
summary: Retrieve a reconciliation exception
description: Returns the exception with assignees, comments, recent investigation sessions, `aggregates` for the entire overdue slice, and `filtered_aggregates` restricted to the supplied filter query parameters. All filter parameters are optional.
parameters:
- in: path
name: id
required: true
schema:
type: string
- in: query
name: amount_min
schema:
type: integer
description: Include records with signed amount >= amount_min (cents)
- in: query
name: amount_max
schema:
type: integer
description: Include records with signed amount <= amount_max (cents)
- in: query
name: date_from
schema:
type: string
format: date
description: Include records with transaction date >= date_from
- in: query
name: date_to
schema:
type: string
format: date
description: Include records with transaction date <= date_to
- in: query
name: direction
schema:
type: string
enum:
- debit
- credit
description: Include only debits (amount < 0) or credits (amount > 0)
- in: query
name: counterparty
schema:
type: string
description: Case-insensitive substring match on record description
- in: query
name: age_bucket
schema:
type: string
enum:
- lt_7d
- 7_30d
- 30_90d
- gt_90d
description: Convenience age filter on time since `overdue_at`
responses:
'200':
description: Exception retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/ReconciliationException'
'401':
description: Unauthorized
'404':
description: Exception not found
tags:
- Reconciliation Exceptions
patch:
summary: Update a reconciliation exception
description: Update the title, description, or status of an exception.
parameters:
- in: path
name: id
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
description:
type: string
status:
type: string
enum:
- open
- investigating
- dismissed
- resolved
responses:
'200':
description: Exception updated
content:
application/json:
schema:
$ref: '#/components/schemas/ReconciliationException'
'404':
description: Exception not found
tags:
- Reconciliation Exceptions
delete:
summary: Delete a reconciliation exception
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'204':
description: Exception deleted successfully
'404':
description: Exception not found
tags:
- Reconciliation Exceptions
components:
schemas:
ReconciliationException:
type: object
required:
- title
- reconciliation_id
- data_stream_id
description: A reconciliation exception represents unmatched overdue records that need human attention. Exceptions are scoped to a (reconciliation, data_stream) tuple and managed by the sweeper job — record membership is computed on read from the set of unmatched records whose `overdue_at` has passed.
properties:
id:
type: integer
reconciliation_id:
type: integer
description: The reconciliation this exception belongs to
reconciliation_name:
type: string
description: Name of the parent reconciliation
data_stream_id:
type: integer
description: The data stream this exception is scoped to
data_stream_name:
type: string
description: Human-readable name of the scoped data stream
data_stream_key:
type: string
description: Immutable key of the scoped data stream
title:
type: string
description:
type: string
status:
type: string
enum:
- open
- investigating
- dismissed
- resolved
default: open
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
opened_at:
type: string
format: date-time
nullable: true
description: When the exception most recently transitioned into an open state. Distinct from `created_at` so reopening is tracked cleanly.
closed_at:
type: string
format: date-time
nullable: true
description: When the exception most recently transitioned into a resolved or dismissed state. Cleared on reopen.
assignees:
type: array
items:
type: object
properties:
id:
type: integer
workos_user_id:
type: string
decimal_places:
type: integer
description: Number of decimal places (2 for USD)
default: 2
aggregates:
allOf:
- $ref: '#/components/schemas/ExceptionAggregates'
description: Whole-exception aggregates over the current unmatched overdue slice.
filtered_aggregates:
allOf:
- $ref: '#/components/schemas/ExceptionAggregates'
description: Aggregates restricted to the filter query parameters. Equals `aggregates` when no filter is supplied. Only present on the show response.
comments:
type: array
description: Comments on this exception, oldest first
items:
type: object
properties:
id:
type: integer
body:
type: string
author_workos_id:
type: string
mentions:
type: array
items:
type: integer
description: User IDs mentioned in the comment
created_at:
type: string
format: date-time
investigation:
allOf:
- $ref: '#/components/schemas/AgentInvestigationSession'
nullable: true
description: The most recent agent investigation session for this exception, if any.
investigation_sessions:
type: array
description: Up to the five most recent investigation sessions, newest first. Exceptions may accumulate multiple sessions as the overdue set evolves.
items:
$ref: '#/components/schemas/AgentInvestigationSession'
AgentInvestigationSession:
type: object
description: An agent-run investigation into an exception's record slice.
properties:
id:
type: integer
status:
type: string
description: Investigation status (e.g. pending, running, completed, failed)
outcome:
type: string
nullable: true
enum:
- match_found
- no_match
- needs_review
- null
description: Standardized outcome of a completed investigation. `match_found` = confident candidate matches; `no_match` = thorough search returned nothing; `needs_review` = candidates found but signals are weak. Null when the session is not yet completed or failed.
recommendation_text:
type: string
nullable: true
description: Agent's recommendation once the investigation completes
confidence_score:
type: number
nullable: true
description: Agent confidence in its recommendation (0.0-1.0)
candidate_records_searched:
type: integer
nullable: true
description: Number of candidate records the agent evaluated
suggested_record_ids:
type: array
nullable: true
items:
type: integer
description: Records the agent suggests linking to this exception
filter_params:
type: object
nullable: true
additionalProperties: true
description: Filter parameters the session was scoped to, if any. Matches the filter shape on `GET /reconciliation_exceptions/{id}`.
completed_at:
type: string
format: date-time
nullable: true
created_at:
type: string
format: date-time
ExceptionAggregates:
type: object
description: Summary statistics for the (filtered) set of unmatched overdue records behind an exception.
properties:
record_count:
type: integer
description: Number of matching overdue unmatched records
total_amount:
type: integer
description: Sum of signed amounts in cents (debits are negative)
debit_count:
type: integer
description: Count of records with amount < 0
debit_sum:
type: integer
description: Sum of debit amounts in cents (non-positive)
credit_count:
type: integer
description: Count of records with amount > 0
credit_sum:
type: integer
description: Sum of credit amounts in cents (non-negative)
avg_age_days:
type: number
description: Average age in days since each record's `overdue_at`
oldest_at:
type: string
format: date-time
nullable: true
description: Transaction date of the oldest record in the slice
newest_at:
type: string
format: date-time
nullable: true
description: Transaction date of the newest record in the slice
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-KEY