End Close Records API

The Records API from End Close — 3 operation(s) for records.

OpenAPI Specification

end-close-records-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: End Close Bank Account Balances Records 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: Records
paths:
  /records:
    get:
      summary: List records
      description: 'Returns a paginated list of records, newest first. At least one of `data_stream_key`, `reconciliation_match_id`, `reconciliation_id`, `external_id`, `import_batch_id`, or `bulk_request_id` is required.


        Pagination is cursor-based: pass each response''s `next_cursor` back as `cursor` until `next_cursor` is null. The legacy `offset` parameter and its `has_more`/`offset`/`total_count` response shape have been removed.'
      parameters:
      - in: query
        name: data_stream_key
        required: false
        schema:
          type: string
        description: Filter by data stream key
      - in: query
        name: reconciliation_match_id
        required: false
        schema:
          type: string
        description: Filter to records that belong to the given match
      - in: query
        name: reconciliation_id
        required: false
        schema:
          type: string
        description: Filter to records that have a status row in the given reconciliation
      - in: query
        name: external_id
        required: false
        schema:
          type: string
        description: Filter to records with this exact `external_id`
      - in: query
        name: import_batch_id
        required: false
        schema:
          type: integer
        description: Filter to records created by this import batch
      - in: query
        name: bulk_request_id
        required: false
        schema:
          type: integer
        description: Filter to records created by this bulk request
      - in: query
        name: created_after
        required: false
        schema:
          type: string
          format: date-time
        description: ISO8601 lower bound on `created_at`
      - in: query
        name: created_before
        required: false
        schema:
          type: string
          format: date-time
        description: ISO8601 upper bound on `created_at`
      - in: query
        name: source
        required: false
        schema:
          type: string
          enum:
          - csv_upload
          - nacha_upload
          - bulk_api
        description: Filter via the joined import batch's `source`
      - in: query
        name: status
        required: false
        schema:
          type: string
          enum:
          - matched
          - unmatched
        description: Filter by match status
      - 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 records
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Record'
                  next_cursor:
                    type: string
                    nullable: true
                    description: Opaque cursor for the next page. Null when no more pages.
                  limit:
                    type: integer
        '422':
          description: No scoping filter provided, or invalid `status`, `created_after`, or `created_before`
      tags:
      - Records
    post:
      summary: Create a record
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Record'
      responses:
        '201':
          description: Record created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Record'
      tags:
      - Records
  /records/bulk:
    post:
      summary: Bulk create records
      description: Submit up to 1,000 records for asynchronous processing. Returns immediately with a bulk request ID. Each record is validated and inserted independently, so some records can succeed while others fail. Use the `GET /bulk_requests/{id}` endpoint to poll for results.
      parameters:
      - in: header
        name: Idempotency-Key
        schema:
          type: string
        description: Optional idempotency key. If a bulk request with this key already exists for your environment, the existing request is returned instead of creating a new one.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - records
              properties:
                on_conflict:
                  type: string
                  enum:
                  - skip
                  - error
                  default: skip
                  description: How to handle records whose `external_id` already exists in the target stream. `skip` (default) silently skips duplicates and counts them in `skipped_items`. `error` surfaces duplicates as per-row failures. Only applies to records with `external_id` set.
                records:
                  type: array
                  minItems: 1
                  maxItems: 1000
                  items:
                    type: object
                    required:
                    - date
                    - data_stream_key
                    - amount
                    - direction
                    properties:
                      date:
                        type: string
                        format: date
                        description: The date of the record
                      data_stream_key:
                        type: string
                        description: Key of the data stream this record belongs to
                      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 — defaults to `USD` when omitted.** Case-insensitive on input.
                        pattern: ^[A-Za-z]{3}$
                        default: USD
                      direction:
                        type: string
                        enum:
                        - credit
                        - debit
                        description: Whether this is a credit or debit
                      description:
                        type: string
                        description: Optional description
                      external_id:
                        type: string
                        description: Optional external identifier
                      metadata:
                        type: object
                        additionalProperties: true
                        default: {}
                        description: Arbitrary key-value metadata
      responses:
        '202':
          description: Bulk request accepted for processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkRequestSummary'
        '400':
          description: Invalid `on_conflict` value
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '401':
          description: Unauthorized
        '422':
          description: Invalid request (e.g. records is not an array, empty, or exceeds 1,000 items)
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
      tags:
      - Records
  /records/{id}:
    get:
      summary: Retrieve a record
      description: Retrieve a single record by its unique ID.
      parameters:
      - in: path
        name: id
        required: true
        schema:
          type: string
        description: The unique identifier of the record
      responses:
        '200':
          description: Record retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Record'
        '401':
          description: Unauthorized
        '404':
          description: Record not found
      tags:
      - Records
    patch:
      summary: Update a record
      description: Update a record's fields. The record **must have a status of `unreconciled`**. Records that are partially or fully reconciled cannot be modified.
      parameters:
      - in: path
        name: id
        required: true
        schema:
          type: string
        description: The unique identifier of the record
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  type: integer
                  description: The monetary amount in cents (e.g., 1234 = $12.34)
                direction:
                  type: string
                  enum:
                  - credit
                  - debit
                description:
                  type: string
                date:
                  type: string
                  format: date
                external_id:
                  type: string
                metadata:
                  type: object
                  additionalProperties: true
      responses:
        '200':
          description: Record updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Record'
        '401':
          description: Unauthorized
        '404':
          description: Record not found
        '409':
          description: Record cannot be modified because it has already been reconciled
      tags:
      - Records
    delete:
      summary: Delete a record
      description: Deletes a single record by its ID. The record **must have a status of `unreconciled`**. Records that are partially or fully reconciled cannot be deleted.
      parameters:
      - in: path
        name: id
        required: true
        schema:
          type: string
        description: The unique identifier of the record
      responses:
        '204':
          description: Record deleted successfully
        '401':
          description: Unauthorized
        '404':
          description: Record not found
        '409':
          description: Record cannot be deleted because it is already reconciled or partially reconciled
      tags:
      - Records
components:
  schemas:
    BulkRequestSummary:
      type: object
      description: Summary returned when a bulk request is created or retrieved via idempotency key
      properties:
        id:
          type: integer
          description: Unique identifier for the bulk request
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          - cancelled
          description: Current processing status
        total_items:
          type: integer
          description: Number of records submitted
        processed_items:
          type: integer
          description: Number of records processed so far
        successful_items:
          type: integer
          description: Number of records successfully created
        failed_items:
          type: integer
          description: Number of records that failed
        skipped_items:
          type: integer
          description: 'Number of records skipped due to `on_conflict: skip` matching an existing `external_id`'
        url:
          type: string
          description: Polling URL to check progress (e.g. /v1/bulk_requests/123)
    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
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY