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

# Update an invoice

> Update the `metadata` of an issued invoice - a free-form bag of string key/value pairs for your own integration references (external accounting ID, Mews record, sync state…).

An issued invoice is legally immutable: its amounts, lines, and seller/account/contact snapshots are frozen and cannot be changed here. `metadata` is the only writable field, and sending any other field returns `422`. The merge is per key: `metadata: { "ref": "ABC" }` upserts the `ref` key; `metadata: { "ref": null }` deletes it; omitted keys are left untouched.

This endpoint emits no webhook - there is no `invoice.updated` event.



## OpenAPI

````yaml /api-reference/bookingshake-openapi.json patch /invoices/{id}
openapi: 3.0.3
info:
  title: BookingShake API
  description: >-
    The BookingShake API allows you to programmatically create and manage
    events, bookings, and related resources. Integrate BookingShake with your
    applications to automate event creation, retrieve booking sources, spaces,
    statuses, and custom fields.


    **Rate Limiting:** All endpoints are rate limited per API key. POST
    /events/create allows 10 requests per minute, while GET endpoints allow 60
    requests per minute. Rate limit information is provided in response headers
    (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset).
  version: 1.0.0
  contact:
    name: BookingShake Support
    email: support@bookingshake.com
    url: https://bookingshake.com
servers:
  - url: https://api.bookingshake.io/api
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: Events
    description: Create and manage events and bookings
  - name: Resources
    description: Retrieve booking sources, spaces, and statuses
  - name: Fields
    description: Retrieve available custom and default fields
  - name: Invoices
    description: Retrieve issued invoices
  - name: Payments
    description: Retrieve payments
  - name: Contacts
    description: Retrieve contacts (people)
  - name: Products
    description: Retrieve the venue product catalog
paths:
  /invoices/{id}:
    patch:
      tags:
        - Invoices
      summary: Update an invoice
      description: >-
        Update the `metadata` of an issued invoice - a free-form bag of string
        key/value pairs for your own integration references (external accounting
        ID, Mews record, sync state…).


        An issued invoice is legally immutable: its amounts, lines, and
        seller/account/contact snapshots are frozen and cannot be changed here.
        `metadata` is the only writable field, and sending any other field
        returns `422`. The merge is per key: `metadata: { "ref": "ABC" }`
        upserts the `ref` key; `metadata: { "ref": null }` deletes it; omitted
        keys are left untouched.


        This endpoint emits no webhook - there is no `invoice.updated` event.
      operationId: updateInvoice
      parameters:
        - name: id
          in: path
          required: true
          description: >-
            Invoice document ID (the `id` field carried by the invoice.created
            webhook).
          schema:
            type: string
          example: file-789
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateInvoiceRequest'
            example:
              metadata:
                external_ref: MEWS-2026-0042
                synced_at: '2026-06-18'
      responses:
        '200':
          description: >-
            Invoice metadata updated successfully. Returns the full invoice in
            its post-update state.
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Maximum requests allowed per minute (30 for this endpoint)
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Requests remaining in the current window
            X-RateLimit-Reset:
              schema:
                type: integer
              description: Unix timestamp when the rate limit resets
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/Invoice'
              example:
                message: success
                data:
                  id: file-789
                  number: FAC-2026-0042
                  type: balance_invoice
                  type_code: 380
                  status: ongoing
                  pdf_url: https://storage.googleapis.com/.../FAC-2026-0042.pdf
                  metadata:
                    external_ref: MEWS-2026-0042
                    synced_at: '2026-06-18'
        '400':
          description: >-
            Bad request - invalid token, missing invoice id, empty/invalid body,
            or no metadata provided.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                message: no updatable fields provided
        '404':
          description: >-
            Invoice not found. Returned when the invoice does not exist, belongs
            to another venue, or is not an invoice (e.g. a quote).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                message: not found
        '422':
          description: >-
            Unprocessable entity - a field other than `metadata` was sent (legal
            fields are immutable), `metadata` is not a flat object of strings,
            or a limit was exceeded (50 keys, key ≤ 40 chars, value ≤ 500
            chars).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                message: field 'status' is immutable; only metadata is editable
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                message: error
      security:
        - bearerAuth: []
components:
  schemas:
    UpdateInvoiceRequest:
      type: object
      description: >-
        The only writable part of an issued invoice. The legal invoice (amounts,
        lines, snapshots) is immutable; sending any field other than `metadata`
        returns 422.
      required:
        - metadata
      additionalProperties: false
      properties:
        metadata:
          type: object
          description: >-
            Free-form integration key/value pairs. Merged per key into the
            existing metadata; pass null as a value to delete that key. Up to 50
            keys per invoice, key ≤ 40 chars, value ≤ 500 chars.
          maxProperties: 50
          additionalProperties:
            type: string
            nullable: true
            maxLength: 500
          example:
            external_ref: MEWS-2026-0042
            synced_at: '2026-06-18'
    Invoice:
      type: object
      description: >-
        An issued invoice. Identical to the `data` block of the invoice.created
        webhook. All amounts are integer cents; dates are `YYYY-MM-DD` strings
        in the `Europe/Paris` timezone; missing values are explicit `null`.
      properties:
        id:
          type: string
          description: Unique invoice document ID
        number:
          type: string
          description: Invoice number as printed on the PDF
        type:
          type: string
          description: Document type
          enum:
            - invoice
            - deposit_invoice
            - balance_invoice
            - credit_note
            - deposit_credit_note
            - balance_credit_note
        type_code:
          type: integer
          description: UNTDID 1001 document type code (380, 386, 381, or 503)
        status:
          type: string
          nullable: true
          enum:
            - ongoing
            - paid
            - canceled
        title:
          type: string
          nullable: true
          description: Title of the related booking
        language:
          type: string
          nullable: true
          description: >-
            Language the document was issued in (e.g. fr, en). null when no
            language was frozen on the document; in that case line labels fall
            back to French.
        currency:
          type: string
          description: Always EUR
        created_at:
          type: integer
          nullable: true
          description: Issue timestamp, Unix milliseconds
        due_date:
          type: string
          nullable: true
          description: Payment due date, YYYY-MM-DD
        service_start_date:
          type: string
          nullable: true
          description: Start of the service period, YYYY-MM-DD
        service_end_date:
          type: string
          nullable: true
          description: End of the service period, YYYY-MM-DD
        purchase_order_number:
          type: string
          nullable: true
          description: Buyer's purchase order reference
        amount_excl_tax:
          type: integer
          description: Total excluding tax of this document, in cents
        amount_incl_tax:
          type: integer
          description: Total including tax of this document, in cents
        taxable_breakdown:
          type: object
          additionalProperties:
            type: integer
          description: Taxable base per VAT rate (key = rate in %, value = cents)
        tax_breakdown:
          type: object
          additionalProperties:
            type: integer
          description: Tax amount per VAT rate (key = rate in %, value = cents)
        global_discount_excl_tax:
          type: integer
          description: >-
            Global discount excluding tax, in cents (not distributed into lines,
            EN 16931 BG-20)
        lines:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceLine'
        booking_id:
          type: string
          nullable: true
          description: >-
            Opaque correlation key of the booking, shared by all invoices and
            payments of the same booking
        quote_id:
          type: string
          nullable: true
          description: ID of the quote this invoice was generated from
        linked_invoice_id:
          type: string
          nullable: true
          description: 'For credit notes: ID of the corrected invoice'
        deposit_invoices:
          type: array
          items:
            $ref: '#/components/schemas/DepositInvoice'
          description: 'For balance invoices: prior deposit invoices deducted'
        account_id:
          type: string
          nullable: true
          description: ID of the buyer account (company)
        contact_id:
          type: string
          nullable: true
          description: ID of the buyer contact
        seller:
          allOf:
            - $ref: '#/components/schemas/InvoiceSeller'
          nullable: true
        account:
          allOf:
            - $ref: '#/components/schemas/InvoiceAccount'
          nullable: true
        contact:
          allOf:
            - $ref: '#/components/schemas/InvoiceContact'
          nullable: true
        pdf_url:
          type: string
          nullable: true
          description: URL of the generated PDF document
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form integration key/value pairs (strings), editable via PATCH
            /invoices/{id}. Empty object when unset. Not carried by the
            invoice.created webhook.
    ErrorResponse:
      type: object
      properties:
        message:
          type: string
          description: Error message describing what went wrong
          example: invalid token
    InvoiceLine:
      type: object
      description: >-
        Invoice line item as printed on the PDF. sum(lines[].total_excl_tax) -
        global_discount_excl_tax = amount_excl_tax (within rounding).
      properties:
        name:
          type: string
          nullable: true
          description: >-
            Line label (EN16931 BT-153 item name). For products: the product
            title; for accommodation: the categories/occupancies label; for
            deposit and deduction lines: a generated label. Localized to the
            invoice `language` (falls back to French). null only if no label can
            be resolved.
        description:
          type: string
          nullable: true
          description: >-
            Free-text line description as entered on the product/room and
            printed on the PDF (EN16931 BT-154 item description). Localized to
            the invoice `language` (falls back to French). null when the line
            has none, and for aggregated and deduction lines.
        accounting_code:
          type: string
          nullable: true
          description: >-
            Accounting code of the line, inherited from the product's
            accounting_tag at generation time. null for aggregated and
            deposit-deduction lines.
        quantity:
          type: string
          description: Decimal string (e.g. "25.00")
        unit:
          type: string
          nullable: true
          description: Unit of measure when applicable (e.g. day for accommodation lines)
        unit_price_excl_tax:
          type: integer
          description: Unit price excluding tax, in cents, before discount
        discount:
          type: integer
          description: Total line discount, in cents (0 if none)
        tax_rate:
          type: string
          description: VAT rate as decimal string (e.g. "20.00")
        total_excl_tax:
          type: integer
          description: >-
            Line net amount in cents (can be negative on balance-invoice
            deduction lines)
    DepositInvoice:
      type: object
      description: A prior deposit invoice deducted from a balance invoice.
      properties:
        id:
          type: string
        number:
          type: string
        date:
          type: string
          description: YYYY-MM-DD
        amount_incl_tax:
          type: integer
          description: In cents
    InvoiceSeller:
      type: object
      description: >-
        Frozen snapshot of the seller (your venue) at issue time. peppol_id is
        the only field read live.
      properties:
        id:
          type: string
          nullable: true
        legal_name:
          type: string
          nullable: true
        company_type:
          type: string
          nullable: true
        company_registration_id:
          type: string
          nullable: true
          description: SIREN
        vat_number:
          type: string
          nullable: true
        share_capital:
          type: string
          nullable: true
          description: Share capital legal mention, verbatim
        company_other_id:
          type: string
          nullable: true
        address_line_1:
          type: string
          nullable: true
        address_line_2:
          type: string
          nullable: true
        postal_code:
          type: string
          nullable: true
        city:
          type: string
          nullable: true
        country:
          type: string
          nullable: true
          description: Verbatim as entered
        country_code:
          type: string
          nullable: true
          description: ISO 3166-1 alpha-2, or null if unresolved
        iban:
          type: string
          nullable: true
        email:
          type: string
          nullable: true
    InvoiceAccount:
      type: object
      description: >-
        Frozen snapshot of the buyer account (company) at issue time. peppol_id
        is read live.
      properties:
        id:
          type: string
          nullable: true
        name:
          type: string
          nullable: true
        legal_name:
          type: string
          nullable: true
        company_type:
          type: string
          nullable: true
        company_registration_id:
          type: string
          nullable: true
          description: SIREN
        siret:
          type: string
          nullable: true
        vat_number:
          type: string
          nullable: true
        rcs_number:
          type: string
          nullable: true
        address_line_1:
          type: string
          nullable: true
        address_line_2:
          type: string
          nullable: true
        postal_code:
          type: string
          nullable: true
        city:
          type: string
          nullable: true
        country:
          type: string
          nullable: true
        country_code:
          type: string
          nullable: true
          description: ISO 3166-1 alpha-2
        billing_address_line_1:
          type: string
          nullable: true
        billing_address_line_2:
          type: string
          nullable: true
        billing_postal_code:
          type: string
          nullable: true
        billing_city:
          type: string
          nullable: true
        billing_country:
          type: string
          nullable: true
        billing_country_code:
          type: string
          nullable: true
          description: ISO 3166-1 alpha-2 for the billing country
        peppol_id:
          type: string
          nullable: true
          description: Peppol participant ID for e-invoicing routing, read live
    InvoiceContact:
      type: object
      description: Frozen snapshot of the buyer contact at issue time.
      properties:
        id:
          type: string
          nullable: true
        first_name:
          type: string
          nullable: true
        last_name:
          type: string
          nullable: true
        email:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        landline_phone:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
        position:
          type: string
          nullable: true
        company:
          type: string
          nullable: true
        address_line_1:
          type: string
          nullable: true
        address_line_2:
          type: string
          nullable: true
        postal_code:
          type: string
          nullable: true
        city:
          type: string
          nullable: true
        country:
          type: string
          nullable: true
        country_code:
          type: string
          nullable: true
          description: ISO 3166-1 alpha-2
    RateLimitResponse:
      type: object
      properties:
        message:
          type: string
          description: Error message
          example: Rate limit exceeded
        data:
          type: object
          properties:
            limit:
              type: integer
              description: Maximum requests allowed per window
              example: 10
            window:
              type: string
              description: Time window duration
              example: 60 seconds
            remaining:
              type: integer
              description: Requests remaining (always 0 on rate limit error)
              example: 0
            resetAt:
              type: string
              format: date-time
              description: ISO 8601 timestamp when the limit resets
              example: '2025-11-17T14:30:00.000Z'
            retryAfter:
              type: integer
              description: Seconds to wait before retrying
              example: 45
  responses:
    RateLimitExceeded:
      description: Rate limit exceeded - too many requests
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Maximum requests allowed per minute
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Requests remaining (always 0 on 429)
        X-RateLimit-Reset:
          schema:
            type: integer
          description: Unix timestamp when the rate limit resets
        Retry-After:
          schema:
            type: integer
          description: Seconds to wait before retrying
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RateLimitResponse'
          example:
            message: Rate limit exceeded
            data:
              limit: 60
              window: 60 seconds
              remaining: 0
              resetAt: '2025-11-17T14:30:00.000Z'
              retryAfter: 45
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: >-
        Bearer authentication using your BookingShake API key. Retrieve your API
        key from Settings > Integrations in your BookingShake dashboard.

````