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

# Check for duplicate expense

> Probe the firm's books for an existing expense that would collide with a prospective payload. Useful before posting a scanned receipt.

## When to use

Call this **before** [`POST /expenses`](./create) when the source is unattended (OCR, recurring import, supplier sync). The response tells the UI whether to surface a confirmation dialog ("an expense from this supplier with this reference already exists — continue?") instead of silently posting a duplicate.

The endpoint never modifies state. Match resolution mirrors the server-side detector used by the OCR + import flows.

## Request

Send either `supplier_id` (preferred — Romanian companies often share name prefixes) or `supplier_data` with the resolved name/CUI from the receipt. The endpoint **never auto-creates** a supplier; if the supplier\_data block doesn't match an existing row, the supplier match is treated as missing and only `reference`-based matches are considered.

<ParamField body="supplier_id" type="string">
  CzUid of the matched supplier. Preferred when known.
</ParamField>

<ParamField body="supplier_data" type="object">
  Fallback when `supplier_id` is unknown. Resolved by CUI first (with `RO` prefix stripped), then by exact name match.

  * `name` — supplier name as printed on the document
  * `cui` — supplier CUI / VAT number, with or without `RO` prefix
</ParamField>

<ParamField body="reference" type="string">
  Document number (factura, chitanță, bon fiscal). Used for both exact and `likely` cross-supplier matches.
</ParamField>

<ParamField body="date" type="string" format="date">
  Issue date in `YYYY-MM-DD`. Combined with supplier + amount for `strong` matches.
</ParamField>

<ParamField body="amount" type="number">
  Net amount (subtotal). Compared with ±0.02 tolerance to forgive rounding.
</ParamField>

<ParamField body="currency" type="string" default="RON">
  Three-letter ISO code. Defaults to `RON`.
</ParamField>

## Match types

| `match_type` | Trigger                                                           |
| ------------ | ----------------------------------------------------------------- |
| `exact`      | Same supplier + same reference                                    |
| `strong`     | Same supplier + same date + amount within ±0.02                   |
| `likely`     | Same reference under a different supplier (review before posting) |

`exact` and `strong` should usually block; `likely` deserves a confirmation but isn't necessarily a true duplicate (e.g. invoice numbers reset per fiscal year across suppliers).

## Response

`duplicate` is `null` when no candidate matches. When populated, the `id` is the CzUid of the existing expense — fetch it via [`GET /expenses/{id}`](./retrieve) for the full record.

```json theme={null}
{
  "data": {
    "duplicate": {
      "id":         "Q9hjAB",
      "reference":  "65776",
      "date":       "2026-04-25",
      "amount":     147.53,
      "currency":   "RON",
      "match_type": "exact"
    }
  }
}
```

## Errors

* **400** — invalid JSON body or missing required fields when neither `supplier_id` nor `supplier_data.name` is provided
* **401** — missing / invalid bearer token
* **403** — API key lacks `read` permission on expenses


## OpenAPI

````yaml POST /expenses/check-duplicate
openapi: 3.1.0
info:
  title: Contazen API
  version: 1.2.0
  description: >
    Build powerful integrations with the Contazen invoicing platform. The
    Contazen API is organized around REST, 

    has predictable resource-oriented URLs, accepts JSON request bodies, returns
    JSON-encoded responses, 

    and uses standard HTTP response codes, authentication, and verbs.


    ## Authentication

    The API uses Bearer token authentication. Include your API key in the
    Authorization header.


    ### Getting your API Key

    1. Log in to your Contazen account

    2. Navigate to Settings > API

    3. Generate or copy your API key (starts with `sk_live_` for production or
    `sk_test_` for testing)


    ### Using the API Key

    Include your API key in the Authorization header:

    ```

    Authorization: Bearer sk_live_YOUR_API_KEY

    ```


    ### Example Request with cURL

    ```bash

    curl --request GET \
      --url https://api.contazen.ro/v1/clients \
      --header 'Authorization: Bearer sk_live_YOUR_API_KEY' \
      --header 'Accept: application/json'
    ```


    ## Rate Limiting

    - 1000 requests per hour per API key

    - 100 create operations per minute per API key


    Rate limit information is included in response headers:

    - `X-RateLimit-Limit`: Maximum requests allowed

    - `X-RateLimit-Remaining`: Requests remaining

    - `X-RateLimit-Reset`: Reset time (Unix timestamp)


    ## Pagination

    All list endpoints return paginated results with the following format:

    ```json

    {
      "success": true,
      "data": {
        "object": "list",
        "data": [...],
        "has_more": true,
        "total": 245,
        "page": 1,
        "per_page": 50,
        "total_pages": 5
      },
      "meta": {
        "version": "v1",
        "request_id": "req_1a2b3c4d",
        "response_time": "23.45ms"
      }
    }

    ```


    ## Multi-Work-Point Access

    API keys belong to a specific work point but can access data from all work
    points

    within the same parent company.


    ## Error Handling

    The API uses conventional HTTP response codes to indicate success or
    failure. 

    In general: 2xx codes indicate success, 4xx codes indicate an error due to
    the 

    information provided, and 5xx codes indicate an error with Contazen's
    servers.


    ## Expanding Nested Objects

    Many endpoints support the `expand` parameter to include related objects in
    the response.

    This follows the Stripe API pattern. For example:

    - `expand[]=lines` - Include invoice line items

    - `expand[]=payments` - Include payment records

    - `expand[]=client` - Include full client object


    ## Localization

    The API supports multiple languages through:

    - `locale` query parameter (en, ro)

    - `Accept-Language` header

    - Default: English
  contact:
    name: Contazen Support
    email: support@contazen.ro
    url: https://contazen.ro
  license:
    name: Proprietary
    url: https://www.contazen.ro/termeni-si-conditii-de-utilizare/
servers:
  - url: https://api.contazen.ro/v1
    description: Production API server
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: API authentication and test endpoints
  - name: Clients
    description: Manage your customers (B2B and B2C)
  - name: Invoices
    description: Create and manage invoices, proformas, and receipts
  - name: Products
    description: Manage your product and service catalog
  - name: Expenses
    description: Track and manage business expenses
  - name: Expense Categories
    description: Organize expenses with categories
  - name: Suppliers
    description: Manage expense suppliers and vendors
  - name: Settings
    description: API settings and configuration
  - name: Payments
    description: Payments received against invoices
  - name: Receipts
    description: Cash receipts (chitanțe) — standalone or paired with an invoice
  - name: Company Lookup
    description: Romanian company lookup (ANAF / VIES)
  - name: Invoice Series
    description: Manage invoice numbering series
  - name: Bank Accounts
    description: Manage IBAN bank accounts
  - name: E-Factura
    description: Romanian e-invoicing status and configuration
  - name: Supplier Bills
    description: Supplier invoices imported from the ANAF SPV inbox
  - name: VAT Rates
    description: Firm-scoped custom VAT rates on top of the Romanian catalog
  - name: Currencies
    description: Currencies enabled for the firm's bill templates
  - name: Languages
    description: Languages enabled for the firm's bill templates
  - name: Conta
    description: |
      Public ANAF data for the firm's CUI: fiscal profile (TVA scope, RTVAI,
      split TVA, status, e-Factura registration, CAEN) and annual balance
      sheets (cifra de afaceri, profit, capitaluri, datorii, salariați).

      Powered by the public ANAF webservices (no OAuth required for these
      endpoints). The data is cached locally and refreshed on demand via
      the `/sync` actions.
paths:
  /expenses/check-duplicate:
    post:
      tags:
        - Expenses
      summary: Pre-check for duplicate expense
      description: |
        Probe the firm's books for an existing expense that would collide
        with the prospective payload (same supplier + reference, or same
        supplier + date + amount within tolerance). Useful before posting a
        scanned receipt to surface a confirmation dialog.

        Returns `{ duplicate: null }` when nothing matches, or a payload
        describing the existing row otherwise. Match types:
        - `exact` — supplier + reference
        - `strong` — supplier + date + amount (±0.02)
        - `likely` — reference collision across suppliers
      operationId: checkExpenseDuplicate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                supplier_id:
                  type: string
                  description: Supplier CzUid (preferred) or omit and send `supplier_data`.
                supplier_data:
                  type: object
                  properties:
                    name:
                      type: string
                    cui:
                      type: string
                reference:
                  type: string
                date:
                  type: string
                  format: date
                amount:
                  type: number
                currency:
                  type: string
                  default: RON
      responses:
        '200':
          description: Duplicate check result
          content:
            application/json:
              schema:
                type: object
                properties:
                  duplicate:
                    nullable: true
                    type: object
                    properties:
                      id:
                        type: string
                      reference:
                        type: string
                        nullable: true
                      date:
                        type: string
                        format: date
                      amount:
                        type: number
                      currency:
                        type: string
                      match_type:
                        type: string
                        enum:
                          - exact
                          - strong
                          - likely
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Use your API key (sk_live_xxx or sk_test_xxx)

````