openapi: 3.1.0
# The Advanta funder API, as implemented in services/supabase/functions/funder-api
# (index.ts, extras.ts, auth.ts) and the database functions it calls. Every path, method,
# field and error code here is checked against the code by scripts/api/check-openapi.mjs.
# Public rendering: https://www.advanta.capital/developers
info:
  title: Advanta funder API
  version: '2026-09-23'
  summary: Funding requests, decisions, programme terms, recourse, limits, bank statements and bank data, signed webhooks, client links and your full data export for funders.
  description: |
    The programmatic twin of the Advanta funder portal. A funder (bank, fund or embedded
    lender) reads the funding requests Advanta operations routed to it, sends its decision
    (offer, decline, fund, settle), manages credit limits per debtor and per seller, reads a
    buyer's payer record, sends its own bank statement for matching, sets what its debtors must
    sign, sets its programme terms (announced or confidential notice, with or without recourse,
    bank data) and announces a confidential request, follows its recourse claims, reads the cash
    flow a seller shares with it from its bank, receives signed webhooks when something happens,
    creates onboarding links for its own suppliers, and manages its own clients: its open link, its prescribers with a link each,
    its invitations with each company's origin, and a report per prescriber. Every morning it can
    read the opportunities of the day: the invoices of its own clients that became eligible under its
    rules overnight, and what changed in those it was shown. It can also take
    everything it can see, at any time, as a ZIP of CSV and JSON Lines files with a schema and
    SHA-256 digests: its exit right. Every write has the same effect as the same action in the
    portal.

    **Authentication.** Every call carries `Authorization: Bearer adv_fk_<64 hex>`. Keys are
    issued by Advanta operations and shown once; only their SHA-256 is stored. A key belongs
    to one funder and may expire.

    **Environments.** One base URL. The key decides the environment, and `GET /v1/me` says
    which: `live` (a funder classified real or pilot: live customers only), `sandbox` (a
    demonstration funder: fictitious companies on the demonstration plane only, shared with
    other demonstrations and rebuilt when the scenario is reset), `unclassified` (a funder
    Advanta operations has not classified yet: it sees no request). A request on the other
    plane is never visible, whatever the key.

    **Errors.** Every error is JSON: `{"error": {"code": "…", "message": "…"}}`, sometimes
    with more fields (see `debtor_not_eligible_for_funder`). Codes are stable; messages are
    for people.

    **Versioning.** The path carries the major version (`/v1`). Within v1, fields and event
    types can be added: ignore what you do not know. `api_version` in `GET /v1/me` and in every
    webhook event names the revision you are reading.

    **Rate limits.** Each key may make 120 calls a minute and 3,000 an hour, counted across
    every Advanta server (Advanta operations can set a different limit for a key). A call beyond
    the limit is answered `429 rate_limited` with a `Retry-After` header (seconds) and
    `retry_after_seconds`, `limit` and `window_seconds` in the error; nothing it asked for was
    done, so send it again after that time. Repeated calls with an unknown or malformed key from
    one address are also answered `429`. `GET /v1/health` is not limited. Exports keep their own
    limit (`export_rate_limited`).
  contact:
    name: Advanta
    email: diogo@advanta.pt
    url: https://www.advanta.capital/developers
servers:
  - url: https://bzsengbmlzzhztjfvcag.supabase.co/functions/v1/funder-api
    description: Production (live and sandbox keys alike)
security:
  - funderKey: []
tags:
  - name: Account
  - name: Requests
  - name: Settings
  - name: Programme
    description: Programme terms (announced or confidential notice, with or without recourse, bank data), announcing a confidential request, recourse claims and bank data.
  - name: Limits
  - name: Payer record
  - name: Statements
  - name: Webhooks
  - name: Onboarding
  - name: Clients
  - name: Exports
  - name: Opportunities
    description: The opportunities of the day (ADR 0045) from your own clients' books, and the webhook that says they are ready.
  - name: Assignment registry
    description: |
      Is this invoice already assigned or pledged? (E7, ADR 0051). Advanta keeps each assignment and pledge as two keyed
      hashes of the seller's and the debtor's tax ids, the invoice number, the amount and the issue date, and keeps
      nothing else of the invoice. You learn yes or no, never to whom, for how much or on what terms. Every lookup and
      its answer is on Advanta's evidence chain. Open on the sandbox; on the live plane once Advanta switches it on
      (403 `registry_not_open` until then). The assignment itself stays the notice to the debtor: the register says
      what others have declared, it does not decide who has priority.
  - name: Buyer programme early payments
    description: |
      A buyer programme's early payments you make (ADR 0064): when a buyer accepts an invoice of its supplier and the
      supplier accepts the early payment offer, you pay the supplier early, on the buyer's behalf, and the buyer pays
      you the invoice amount on its due date. Each offer records its funder when it is released, so you see and record
      only your own. You record the early payment you made and, later, the buyer's repayment; each record is on
      Advanta's evidence chain and on the buyer's own audit chain.
paths:
  /v1/health:
    get:
      tags: [Account]
      operationId: getHealth
      summary: Is the API up (no key)
      description: |
        Public and unauthenticated. Answers 200 when the API is deployed and serving; it reads no
        data and makes no database call. Advanta's own uptime checks read it every 5 minutes, and
        the results are published at https://www.advanta.capital/status.
      security: []
      responses:
        '200':
          description: The API is serving.
          content:
            application/json:
              schema:
                type: object
                required: [status, api_version, time]
                properties:
                  status: { type: string, enum: [ok] }
                  api_version: { type: string }
                  time: { type: string, format: date-time }
              example:
                status: ok
                api_version: '2026-09-23'
                time: '2026-09-27T12:00:00.000Z'

  /v1/me:
    get:
      tags: [Account]
      operationId: getMe
      summary: The key, its funder and its environment
      responses:
        '200':
          description: Who is calling.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Me' }
              example:
                api_version: '2026-09-23'
                environment: sandbox
                funder: { bank_id: 6d164c92-02cc-4f9a-ae8d-3f7f5ef043d3, name: Compartment Demo (LU) }
                key:
                  id: 0b3c6a52-5d0e-4b53-9d0e-1c2b3a4d5e6f
                  name: sandbox · Example prospect
                  prefix: adv_fk_1a2b3
                  scopes: [requests:read, limits:read, webhooks:write, onboarding:write]
                  created_at: '2026-09-23T18:00:00Z'
                  expires_at: '2026-10-07T18:00:00Z'
                  prospect: Example prospect
        '401': { $ref: '#/components/responses/Unauthorized' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }

  /v1/requests:
    get:
      tags: [Requests]
      operationId: listRequests
      summary: Funding requests visible to this funder
      description: |
        Requests routed to you (you can act on them) and requests you already acted on (read
        only, even after a re-routing), newest first, each with your own offer if you made one.
        Scope `requests:read`.
      parameters:
        - name: status
          in: query
          description: "`open` (default: pending, submitted, under_review, terms_sent, accepted, approved), `all`, or one status."
          schema: { type: string, default: open }
        - name: limit
          in: query
          schema: { type: integer, default: 50, minimum: 1, maximum: 200 }
      responses:
        '200':
          description: The requests.
          content:
            application/json:
              schema:
                type: object
                required: [funder, count, requests]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  count: { type: integer }
                  requests:
                    type: array
                    items:
                      allOf:
                        - $ref: '#/components/schemas/Request'
                        - type: object
                          properties:
                            my_offer:
                              oneOf:
                                - $ref: '#/components/schemas/OfferSummary'
                                - type: 'null'
                            debtor_consent:
                              type: array
                              items: { $ref: '#/components/schemas/DebtorConsent' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/requests/{id}:
    get:
      tags: [Requests]
      operationId: getRequest
      summary: The underwriting packet of one request
      description: |
        The request, its receivables, the seller's latest Advanta Score (computed on the spot
        when the seller has none yet; null if that fails), your own offer, and `risk`: the fraud
        signals still open or confirmed on the request and every dispute recorded against it, as
        your portal shows them. Scope `requests:read`.
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: The packet.
          content:
            application/json:
              schema:
                type: object
                required: [request, receivables, score, my_offer, debtor_consent, risk]
                properties:
                  request: { $ref: '#/components/schemas/Request' }
                  debtor_consent:
                    type: array
                    items: { $ref: '#/components/schemas/DebtorConsent' }
                  receivables:
                    type: array
                    items: { $ref: '#/components/schemas/Receivable' }
                  score:
                    oneOf:
                      - $ref: '#/components/schemas/Score'
                      - type: 'null'
                  my_offer:
                    oneOf:
                      - $ref: '#/components/schemas/Offer'
                      - type: 'null'
                  risk: { $ref: '#/components/schemas/RequestRisk' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/requests/{id}/decision:
    post:
      tags: [Requests]
      operationId: decideRequest
      summary: Offer terms, decline, fund, or record a settlement
      description: |
        Scope `decisions:write`. The request must be routed to you (else 409 `not_routed_to_you`).

        * `offer`: send terms, on a pending, under-review or `terms_sent` request only (409
          `invalid_state` on any other status: once the seller accepted your terms, status
          `approved`, they do not change). Moves a pending, submitted or under-review request to
          `terms_sent`. The offer expires after `valid_days` (1 to 90), else after your
          configured validity (7 days by default). Refused with 409 `credit_limit` when one of
          your limits cannot hold it, and with 409 `debtor_not_eligible_for_funder` when you
          take listed buyers only and a debtor is not on your list, and with 409
          `documents_missing_for_funder` when a document you require from the seller is missing,
          unverified or expired (the error lists them).
        * `decline`: close the request with a reason. `reason` is one of payer_credit,
          invoice_ineligible, documentation, concentration, amount_out_of_range, sector_excluded,
          no_funder_capacity, withdrawn_by_client, other; free text in `reason` or `notes` is
          kept as a note with reason `other`. That note is the message the seller reads;
          `internal_note` is kept for your team and never shown to the seller. On a request the
          seller already accepted (status `approved`) this steps back from the deal before funding
          (`step_back: true` in the answer): the message the seller reads is then required, at least
          10 characters (422 `step_back_message_required`), your accepted offer stays on record as
          the seller accepted it, and the debtors' notices are withdrawn. A funded or settled request
          is not declined (409 `invalid_state`).
        * `fund`: only once the seller accepted your terms (status `approved`), with the
          `value_date` and the `reference` of your transfer to the seller (422
          `invalid_funding_details` without them; an `amount` other than the accepted advance is
          409 `funding_amount_mismatch`). For factoring,
          the database also requires every debtor's notice to be acknowledged (409 `funding_gate_failed`),
          and every request needs the documents you require from the seller to be valid on the
          funding date (409 `documents_missing_for_funder`).
        * `settle`: record money received on a funded request. Partial payments add up; the
          request becomes `settled` when the total reaches the request amount or `final` is true.
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/OfferDecision'
                - $ref: '#/components/schemas/DeclineDecision'
                - $ref: '#/components/schemas/FundDecision'
                - $ref: '#/components/schemas/SettleDecision'
              discriminator: { propertyName: decision }
            examples:
              offer: { value: { decision: offer, rate: 2.4, advance_pct: 90, days: 60, valid_days: 7, notes: Subject to the notice being acknowledged } }
              decline: { value: { decision: decline, reason: concentration, notes: We cannot fund this buyer this quarter, internal_note: Group exposure above our internal limit } }
              fund: { value: { decision: fund, value_date: '2026-09-30', reference: 'TRF-2026-0930-01' } }
              settle: { value: { decision: settle, amount: 12500.00, received_at: '2026-10-30T10:00:00Z', reference: ADV-A1F51301-1000 } }
      responses:
        '200':
          description: Declined, funded or settlement recorded.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/DeclineResult'
                  - $ref: '#/components/schemas/FundResult'
                  - $ref: '#/components/schemas/SettleResult'
        '201':
          description: Offer sent.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OfferResult' }
        '400':
          description: "`reason_required`: a decline without `reason` or `notes`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403':
          description: "`forbidden` (scope) or `not_your_request` (settle: not the funder of record)."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '404': { $ref: '#/components/responses/NotFound' }
        '409':
          description: |
            `not_routed_to_you`, `invalid_state` (wrong status for this decision),
            `credit_limit`, `funding_gate_failed`, `funding_amount_mismatch`, or
            `debtor_not_eligible_for_funder` (with `debtors`).
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/DebtorNotEligibleError'
        '422':
          description: "`invalid_terms`, `invalid_amount`, `invalid_received_at`, `invalid_funding_details`, `step_back_message_required` or `invalid_decision`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/requests/{id}/consent-level:
    post:
      tags: [Requests]
      operationId: raiseConsentLevel
      summary: Raise what the debtors of one request must sign
      description: |
        Only upwards, only on a factoring request routed to you and in flight, and only before
        any of its debtors has answered. Scope `decisions:write`.
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [level, reason]
              properties:
                level: { $ref: '#/components/schemas/ConsentLevel' }
                reason: { type: string, minLength: 8 }
      responses:
        '200':
          description: The level now required.
          content:
            application/json:
              schema:
                type: object
                properties:
                  request_id: { type: string, format: uuid }
                  consent_level_required: { $ref: '#/components/schemas/ConsentLevel' }
                  changed: { type: boolean }
                  from: { oneOf: [{ $ref: '#/components/schemas/ConsentLevel' }, { type: 'null' }] }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '409':
          description: "`not_routed_to_you`, `level_lower`, `notice_already_decided`, `not_factoring` or `request_not_in_flight`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '422':
          description: "`level_invalid` or `reason_required`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/requests/{id}/documents:
    get:
      tags: [Requests]
      operationId: getRequestDocuments
      summary: The seller's supporting documents on a request
      description: |
        The deal file: when the request was routed to you, and again when it was funded, Advanta
        recorded which version of each document you require (see `/v1/required-documents`)
        satisfied you: its file name, SHA-256, issue and validity dates, and when and how Advanta
        verified it. The record never changes, even when the seller uploads newer versions; each
        entry also says where the document stands today. `current` lists the seller's current
        documents. Every entry with a file carries a download URL valid for two minutes; each URL
        issued is logged. Compare the SHA-256 of what you download with the one recorded.
        Scope `requests:read`.
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: The deal file and the current documents.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/DealDocuments' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/required-documents:
    get:
      tags: [Settings]
      operationId: getRequiredDocuments
      summary: The documents you require from sellers
      description: |
        Your list per seller country, and the catalogue it is chosen from: each document's code,
        name in seven languages, issuer, usual validity (a pre-fill: the date printed on the
        document is what the seller records and Advanta checks) and sensitivity. A request is
        routed to you, your offer is recorded and the request is funded only while every document
        on your list for the seller's country is verified by Advanta and valid on that date;
        otherwise 409 `documents_missing_for_funder`. Scope `requests:read`.
      responses:
        '200':
          description: Your list and the catalogue.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/RequiredDocuments' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '500': { $ref: '#/components/responses/ServerError' }
    put:
      tags: [Settings]
      operationId: putRequiredDocuments
      summary: Set the documents you require from sellers in one country
      description: |
        Replaces the list for one seller country (an empty list clears it); codes come from the
        catalogue. Kept on Advanta's evidence chain with `note`. Requests already with you stay
        with you; your next offer or funding on one waits until the seller meets the new list
        (`open_requests_not_meeting` counts them). Scope `settings:write` or `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [country, codes]
              properties:
                country: { type: string, pattern: '^[A-Za-z]{2}$' }
                codes: { type: array, items: { type: string } }
                note: { type: string, maxLength: 500 }
            example: { country: PT, codes: [cert_hacienda, cert_seguridad_social, cirbe], note: Credit committee of 23 September }
      responses:
        '200':
          description: Your list after the change.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/RequiredDocuments'
                  - type: object
                    properties:
                      changed: { type: boolean }
                      country: { type: string }
                      codes: { type: array, items: { type: string } }
                      open_requests_not_meeting: { type: integer }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422':
          description: "`body_required`, `country_invalid`, `codes_invalid`, `note_invalid`, `country_without_catalogue` or `document_code_unknown`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/settings:
    get:
      tags: [Settings]
      operationId: getSettings
      summary: What your debtors must sign before you fund
      description: |
        Your debtor declaration policy: the level every debtor must sign before a factoring
        request routed to you can be funded (receipt < acknowledgment < acceptance), whether only
        counsel-approved declaration texts count, the open requests per level, and which levels
        each governing law has texts for (and in which languages). Scope `requests:read`.
      responses:
        '200':
          description: The policy.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Settings' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '500': { $ref: '#/components/responses/ServerError' }
    put:
      tags: [Settings]
      operationId: putSettings
      summary: Change what your debtors must sign
      description: |
        Applies to requests routed to you from then on; a request already routed keeps the level
        it was routed with. `reason` (at least 8 characters) is kept on Advanta's evidence chain.
        Scope `settings:write` or `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reason]
              properties:
                debtor_consent_level: { $ref: '#/components/schemas/ConsentLevel' }
                require_counsel_approved_texts: { type: boolean }
                reason: { type: string, minLength: 8 }
            example: { debtor_consent_level: acknowledgment, reason: Credit committee decision of 22 September }
      responses:
        '200':
          description: The policy after the change.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Settings'
                  - type: object
                    properties:
                      changed: { type: boolean }
                      open_requests_keep_their_level: { type: integer }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422':
          description: "`level_invalid`, `invalid_flag` or `reason_required`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/programme:
    get:
      tags: [Programme]
      operationId: getProgramme
      summary: Your programme terms
      description: |
        Your terms for the factoring requests routed to you: your default, the terms you set for
        particular companies (a programme is you and one seller), the companies you can set terms
        for (those with a request routed to you, and your own clients), and your requests counted by
        the terms they carry. Each term is explained in the `ProgrammeTerms` schema. A request takes
        the terms in force when it is routed to you and keeps them: a later change applies to
        requests routed from then on. Scope `requests:read`.
      responses:
        '200':
          description: Your terms.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Programme' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '500': { $ref: '#/components/responses/ServerError' }
    put:
      tags: [Programme]
      operationId: putProgramme
      summary: Change your default terms, or one company's
      description: |
        Without `seller_id` (or with `seller_id: null`), changes your default; with a company's id
        (from `sellers` in `GET /v1/programme`), changes that company's own terms, which then take
        precedence over your default. Only the keys you send change. `{"reset": true}`, alone and
        with a `seller_id`, removes that company's own terms, so your default applies to it again.
        The change applies to requests routed to you from then on; requests already routed keep
        their terms (`open_requests_keep_their_terms` counts those still open). Each change is kept
        on Advanta's evidence chain with `reason`. Scope `settings:write` or `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [terms, reason]
              properties:
                seller_id: { type: [string, 'null'], format: uuid }
                terms: { $ref: '#/components/schemas/ProgrammeTermsChange' }
                reason: { type: string, minLength: 8 }
            example: { terms: { disclosure: confidential, announce_overdue_days: 15, announce_on_dispute: true, announce_on_kyc_lapse: true }, reason: Credit committee of 28 September }
      responses:
        '200':
          description: The terms after the change.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ProgrammeChange' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422':
          description: "`body_invalid`, `seller_id_invalid`, `terms_invalid` (not an object, empty, a value out of range, or a reset without a company), `terms_key_unknown`, `reason_required` or `seller_not_in_programme` (the company has no request routed to you and is not one of your clients)."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/requests/{id}/announce:
    post:
      tags: [Programme]
      operationId: announceRequest
      summary: Announce a confidential request
      description: |
        For a request routed to you under confidential terms: it becomes announced (`disclosure`
        announced, `announced_at`, `announced_trigger` manual) and the notices of assignment that
        were prepared for it are sent to its debtors (`sending_queued`), who then acknowledge them
        as in an announced programme. You may announce at any time while the request is pending,
        under review, with terms sent, approved or funded. The announcement is kept on Advanta's
        evidence chain with `reason`, and a `request.announced` event follows. Once a notice has
        been sent the request stays announced. Scope `decisions:write`.
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reason]
              properties:
                reason: { type: string, minLength: 8 }
            example: { reason: Invoice 2026-118 is 20 days overdue }
      responses:
        '200':
          description: Announced.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AnnounceResult' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403':
          description: "`forbidden` (the key lacks the scope) or `not_routed_to_you` (the request is not routed to you)."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '404': { $ref: '#/components/responses/NotFound' }
        '422':
          description: "`body_invalid`, `reason_required`, `already_announced` (the request is in an announced programme) or `request_closed` (rejected, settled or otherwise closed)."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/requests/{id}/notices:
    get:
      tags: [Programme]
      operationId: getRequestNotices
      summary: The notices of assignment of a request
      description: |
        One entry per debtor: the notice's status, the invoices it covers and, when there is one,
        the prepared document: the exact subject and HTML the debtor receives, its language and
        governing law, and its SHA-256 (computed by the database over the subject, a newline and
        the HTML, when it was prepared). In a confidential programme the document is prepared when
        the request is routed to you and kept ready to send; it is the text sent when the request
        is announced. The HTML carries the literal `{{ACK_LINK}}` where the debtor's personal
        acknowledgment link goes (the link holds a secret and is never shown). `names_this_funder`
        says the document names the funder the request is routed to; `current` says it still
        matches the notice's invoices and amount. For a request routed to you, or one you acted on.
        Scope `requests:read`.
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: The notices.
          content:
            application/json:
              schema:
                type: object
                properties:
                  request_id: { type: string, format: uuid }
                  count: { type: integer }
                  notices: { type: array, items: { $ref: '#/components/schemas/RequestNotice' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/requests/{id}/debtors:
    get:
      tags: [Limits]
      operationId: getRequestDebtors
      summary: What Advanta knows about each debtor on a request
      description: |
        One entry per debtor on a factoring request routed to you, or one you acted on. `level` says how
        far the debtor has come on Advanta: `notice` (it knows us from the notice only), `account` (it
        claimed its free payer account), `books` (it connected its accounting system), `buyer` (it runs a
        buyer programme; `buyer_programme` is then true), with `level_since`. `score` is the debtor's own
        score (grade, 0-100, when and by which model version) and is given only when the debtor shares its
        data with the funders that finance invoices owed by it, is at level `books` or `buyer`, and this
        request is routed to you (not one you only acted on); otherwise null. `pair_history` is the
        seller's own history with this debtor over 36
        months, with the payer record's rules (real invoices only; lateness only against due dates stated
        on the document or in the ERP). `public_payment_period` is the latest official average payment
        period when the debtor is a public body (DGAL for Portuguese municipalities, Hacienda for Spanish
        local entities). `credit_limit` is your own limit on the debtor, where it came from and what is
        used (outstanding, committed and offered). Scope `requests:read`.
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: The debtors.
          content:
            application/json:
              schema:
                type: object
                required: [funder, request_id, count, debtors]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  request_id: { type: string, format: uuid }
                  count: { type: integer }
                  debtors:
                    type: array
                    items:
                      type: object
                      properties:
                        debtor_key: { type: string }
                        debtor_country: { type: string }
                        debtor_name: { type: [string, 'null'] }
                        level: { type: string, enum: [notice, account, books, buyer] }
                        level_since: { type: [string, 'null'], format: date-time }
                        score:
                          type: [object, 'null']
                          properties:
                            grade: { type: string, enum: [A, B, C, D, E] }
                            score_100: { type: integer, minimum: 0, maximum: 100 }
                            computed_at: { type: string, format: date-time }
                            model_version: { type: string }
                        buyer_programme: { type: boolean }
                        pair_history:
                          type: object
                          properties:
                            invoices: { type: integer }
                            settled: { type: integer }
                            open: { type: integer }
                            overdue: { type: integer }
                            first_invoice: { type: [string, 'null'], format: date }
                            last_invoice: { type: [string, 'null'], format: date }
                            avg_days_to_pay: { type: [number, 'null'] }
                            median_days_to_pay: { type: [number, 'null'] }
                            on_time_pct: { type: [number, 'null'] }
                            with_due_date: { type: integer }
                            share_of_sales_pct: { type: [number, 'null'] }
                        public_payment_period:
                          type: [object, 'null']
                          properties:
                            days: { type: number }
                            period_end: { type: string, format: date }
                            source: { type: string, enum: [dgal_pmp, hacienda_pmp] }
                            entity_name: { type: string }
                        credit_limit:
                          type: [object, 'null']
                          properties:
                            amount: { type: [number, 'null'] }
                            status: { type: string, enum: [active, refused, suspended] }
                            source: { type: string, enum: [manual, api, import, insurer] }
                            source_ref: { type: [string, 'null'] }
                            exposure: { type: number, description: Outstanding plus committed plus offered, in euros. }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/requests/{id}/cash-flow:
    get:
      tags: [Programme]
      operationId: getRequestCashFlow
      summary: The seller's cash flow, shared with you from its bank
      description: |
        When your terms ask for bank data (`bank_data` requested or required), the seller can
        connect its business bank account for you: read-only, with its consent, through a licensed
        account-information provider. This returns what it shares with you: the connection, its
        accounts (the last four characters of each IBAN) and their balances, twelve months of
        movements by month, and the check of its payout account (the account you pay into must be
        among the accounts its own bank returned, held in the company's name). `cash_flow` is null
        while the seller has not connected an account for you. `bank_data_problems` says what
        funding still waits for when your terms require bank data. `payment_alerts` are the
        payments the seller received from a debtor of this request after you funded it under
        confidential terms (see `payment.reached_seller`). A seller's consent is given to one
        funder: you see only what it shares with you. For a request routed to you, or one you
        acted on. Scope `requests:read`.
      parameters:
        - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: The cash flow and the alerts.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/RequestCashFlow' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/recourse:
    get:
      tags: [Programme]
      operationId: getRecourse
      summary: Your exposure by recourse type, and the recourse claims
      description: |
        Your funded factoring requests counted by recourse type (`with`, `without`, and
        `not_recorded` for requests routed before 28 September 2026), with the face value still
        outstanding, the amount advanced, how many have an automatic claim rule
        (`recourse_days`) and how many are confidential; the claims counted by kind and status; and
        the claims themselves, open ones first. A claim opens once per request, when a funded
        request is not settled `recourse_days` after an invoice's due date: with recourse, a claim
        against the seller (`kind` recourse) for the amount you advanced plus your fees as recorded
        on the request, less what you already collected on it; without recourse, a debtor
        default flagged to you (`kind` debtor_default) for your own collections and credit
        insurance, for what the debtor still owes. The seller repays a recourse claim into
        `pay_to_iban` quoting `pay_reference`; once the payments you record from then on (a
        statement line you confirm, or the `settle` decision) cover `claim_amount`, the claim is
        settled and the request closes as settled by recourse: the invoices go back to the seller,
        still unpaid by the debtor. A claim of either kind is also settled when the request settles
        the ordinary way. Scope `requests:read`.
      parameters:
        - name: status
          in: query
          description: Only the claims with this status. Absent, every claim.
          schema: { type: string, enum: [open, settled, withdrawn, written_off] }
      responses:
        '200':
          description: Exposure and claims.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Recourse' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422':
          description: "`status_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/recourse/{id}/close:
    post:
      tags: [Programme]
      operationId: closeRecourseClaim
      summary: Withdraw a recourse claim, or write off a debtor default
      description: |
        Closes an open claim of yours: a recourse claim is `withdrawn` (you waived it or agreed
        otherwise with the seller), a debtor default is `written_off` (passed to your collections or
        your insurer). Kept on Advanta's evidence chain with `reason`. Scope `decisions:write`.
      parameters:
        - $ref: '#/components/parameters/ClaimId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [status, reason]
              properties:
                status: { type: string, enum: [withdrawn, written_off] }
                reason: { type: string, minLength: 8 }
            example: { status: withdrawn, reason: Payment plan agreed with the seller on 2 October }
      responses:
        '200':
          description: Closed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  claim_id: { type: string, format: uuid }
                  status: { type: string, enum: [withdrawn, written_off] }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403':
          description: "`forbidden` (the key lacks the scope) or `not_your_claim` (the claim is not on a request of yours)."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '404': { $ref: '#/components/responses/NotFound' }
        '422':
          description: "`body_invalid`, `status_invalid`, `reason_required`, `close_invalid` (withdrawn is for a recourse claim, written_off for a debtor default) or `claim_closed` (the claim is no longer open)."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/bank-data:
    get:
      tags: [Programme]
      operationId: getBankData
      summary: Your bank data
      description: |
        Your own collection account read the same way (connected by your administrator in the
        portal): each connection, its accounts, when it was last read and the last error; its
        movements go through the same matching as `POST /v1/statements`, so collections match your
        funded requests without uploading files, and you confirm each match in the portal. Also:
        how many sellers share their account with you now, the payment alerts on your requests
        (the last 180 days) and the account-information provider's charges recorded against you
        (by month; `unit_price_eur` and `amount_eur` are null until the provider's price is fixed).
        Scope `requests:read`.
      responses:
        '200':
          description: Your bank data.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BankData' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/credit-limits:
    get:
      tags: [Limits]
      operationId: listCreditLimits
      summary: Your book per debtor
      description: |
        Per debtor, your limit and what is outstanding, committed, offered and left. Scope `limits:read` or `requests:read`.
        `outstanding` is your money still out: the financed invoices' amount less the payments you recorded (payments
        recorded in Receipts or with `settle`, statement lines you confirmed, a seller's repayment under recourse). The
        seller's own "paid" flag never lowers it: an invoice the seller's invoicing software marks paid that you have
        not received is listed in `seller_marked_paid` (the debtor may have paid the wrong party), and while it is past
        due the debtor stays `frozen` until you record the payment.
      responses:
        '200':
          description: The book.
          content:
            application/json:
              schema:
                type: object
                required: [funder, currency, count, debtors]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  currency: { type: string, const: EUR }
                  count: { type: integer }
                  debtors:
                    type: array
                    items: { $ref: '#/components/schemas/DebtorExposure' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '500': { $ref: '#/components/responses/ServerError' }
    put:
      tags: [Limits]
      operationId: putCreditLimit
      summary: Set or revise a limit on a debtor, or refuse it
      description: Scope `limits:write` or `decisions:write`. The database refuses any later offer this limit cannot hold.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [debtor_tax_id]
              properties:
                debtor_tax_id: { type: string, description: "The debtor's VAT or tax number." }
                debtor_country: { type: string, description: ISO 3166 alpha-2. }
                debtor_name: { type: string }
                amount: { type: [number, 'null'], minimum: 0, description: Euros. Required for an active limit. }
                status: { type: string, enum: [active, refused, suspended], default: active }
                note: { type: string }
            example: { debtor_tax_id: '506921000', debtor_country: PT, debtor_name: Município de Lisboa, amount: 250000, status: active }
      responses:
        '200':
          description: The limit as stored.
          content:
            application/json:
              schema:
                type: object
                required: [credit_limit]
                properties:
                  credit_limit: { $ref: '#/components/schemas/DebtorLimit' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422':
          description: "`debtor_tax_id_required`, `invalid_amount` or `invalid_limit`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/credit-limits/import:
    post:
      tags: [Limits]
      operationId: importCreditLimits
      summary: Load up to 2,000 limits on debtors at once
      description: |
        Your own book, or your credit insurer's limits (`source` import or insurer), with `source_ref`
        naming the file or batch. Each row is checked exactly as PUT /v1/credit-limits checks one and is
        answered on its own; a row that fails does not stop the others, and a debtor twice in one call is
        refused the second time. Every limit written records its source and reference, on the limit and
        on its history. A list of rows alone is also accepted (source import). Scope `limits:write` or
        `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [rows]
              properties:
                rows:
                  type: array
                  minItems: 1
                  maxItems: 2000
                  items:
                    type: object
                    required: [debtor_tax_id]
                    properties:
                      debtor_tax_id: { type: string }
                      debtor_country: { type: string, description: ISO 3166 alpha-2. }
                      debtor_name: { type: string }
                      amount: { type: [number, string, 'null'], description: Euros; a number or digits with a decimal point. Required for an active limit. }
                      status: { type: string, enum: [active, refused, suspended], default: active }
                      note: { type: string }
                source: { type: string, enum: [import, insurer], default: import }
                source_ref: { type: string, maxLength: 200 }
            example: { source: insurer, source_ref: CESCE 2026-09, rows: [{ debtor_tax_id: '506921000', debtor_country: PT, amount: 250000 }, { debtor_tax_id: 'B12345678', debtor_country: ES, status: refused }] }
      responses:
        '200':
          description: One answer per row.
          content:
            application/json:
              schema:
                type: object
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  source: { type: string }
                  source_ref: { type: [string, 'null'] }
                  received: { type: integer }
                  written: { type: integer }
                  refused: { type: integer }
                  rows:
                    type: array
                    items:
                      type: object
                      required: [row, ok]
                      properties:
                        row: { type: integer }
                        debtor_tax_id: { type: [string, 'null'] }
                        ok: { type: boolean }
                        debtor_key: { type: string }
                        status: { type: string }
                        amount: { type: [number, 'null'] }
                        error: { type: string, description: "`invalid_amount`, `debtor_tax_id_required`, `duplicate_debtor`, `invalid_status`, `amount_required`, `invalid_country`, `row_invalid` or `invalid_limit`." }
                        detail: { type: string }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '413':
          description: "`too_many_rows`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '422':
          description: "`rows_required`, `invalid_source`, `source_ref_invalid` or `source_ref_too_long`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/seller-limits:
    get:
      tags: [Limits]
      operationId: listSellerLimits
      summary: Your book per seller
      description: Scope `limits:read` or `requests:read`.
      responses:
        '200':
          description: The book.
          content:
            application/json:
              schema:
                type: object
                required: [funder, currency, count, sellers]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  currency: { type: string, const: EUR }
                  count: { type: integer }
                  sellers:
                    type: array
                    items: { $ref: '#/components/schemas/SellerExposure' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '500': { $ref: '#/components/responses/ServerError' }
    put:
      tags: [Limits]
      operationId: putSellerLimit
      summary: Set or revise a limit on a seller, or refuse it
      description: Scope `limits:write` or `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [seller_id]
              properties:
                seller_id: { type: string, format: uuid, description: As returned by GET /v1/seller-limits. }
                amount: { type: [number, 'null'], minimum: 0 }
                status: { type: string, enum: [active, refused, suspended], default: active }
                note: { type: string }
      responses:
        '200':
          description: The limit as stored.
          content:
            application/json:
              schema:
                type: object
                required: [seller_limit]
                properties:
                  seller_limit: { $ref: '#/components/schemas/SellerLimit' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '422':
          description: "`seller_id_required`, `invalid_amount` or `invalid_limit`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/payer-record:
    get:
      tags: [Payer record]
      operationId: getPayerRecord
      summary: How a buyer pays its suppliers
      description: |
        Aggregates only, from the ledgers of the suppliers connected to Advanta: published when
        at least three suppliers observe the buyer, otherwise `status` says why and every figure
        is null. Only for a buyer on a request in your scope or on your debtor list. A sandbox
        key reads the demonstration plane's record. Scope `limits:read` or `requests:read`.
      parameters:
        - { name: tax_id, in: query, required: true, schema: { type: string }, description: "The buyer's VAT or tax number." }
        - { name: country, in: query, schema: { type: string }, description: ISO 3166 alpha-2. }
      responses:
        '200':
          description: The record, or null.
          content:
            application/json:
              schema:
                type: object
                required: [funder, payer_record]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  payer_record:
                    oneOf:
                      - $ref: '#/components/schemas/PayerRecord'
                      - type: 'null'
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '422':
          description: "`tax_id_required`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/statements:
    post:
      tags: [Statements]
      operationId: postStatement
      summary: Send your bank statement for matching
      description: |
        A CAMT.053 (XML) or CSV statement of your collection account, at most 4 MiB and 5,000
        transactions. Each credit is matched against your own funded requests (the reference the
        debtor quoted first); nothing is settled until you confirm a match in the portal. The
        same file twice is refused (its SHA-256). Scope `statements:write` or `decisions:write`.
      parameters:
        - { name: file_name, in: query, schema: { type: string } }
        - { name: kind, in: query, schema: { type: string, enum: [camt053, csv] }, description: Detected when omitted. }
      requestBody:
        required: true
        content:
          application/xml: { schema: { type: string } }
          text/csv: { schema: { type: string } }
          application/json:
            schema:
              type: object
              required: [content_base64]
              properties:
                file_name: { type: string }
                kind: { type: string, enum: [camt053, csv] }
                content_base64: { type: string }
      responses:
        '201':
          description: Imported.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StatementResult' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '409':
          description: "`statement_already_imported`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '413':
          description: "`file_too_large` or `too_many_lines`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '422':
          description: "`file_required`, `file_unreadable`, `file_empty`, `statement_unreadable`, `statement_has_no_transactions` or `line_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/webhooks:
    get:
      tags: [Webhooks]
      operationId: listWebhooks
      summary: Your webhook endpoints
      description: |
        The active endpoints this key manages, without secrets. A key in the sandbox manages only
        the endpoints it created. Scope `webhooks:write`, `decisions:write` or `requests:read`.
      responses:
        '200':
          description: The endpoints, and the event types you can subscribe to.
          content:
            application/json:
              schema:
                type: object
                required: [count, webhooks, event_types]
                properties:
                  count: { type: integer }
                  webhooks:
                    type: array
                    items: { $ref: '#/components/schemas/WebhookEndpoint' }
                  event_types:
                    type: array
                    items: { $ref: '#/components/schemas/EventType' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    post:
      tags: [Webhooks]
      operationId: createWebhook
      summary: Register an endpoint (the signing secret is shown once)
      description: |
        `url` is https on a public host name, port 443, without credentials; private, loopback
        and link-local addresses are refused, and redirects are never followed. At most 10
        active endpoints. Creation is recorded on Advanta's evidence chain. Scope
        `webhooks:write` or `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url: { type: string, format: uri, maxLength: 2048 }
                events:
                  description: Event types, or ["*"] for all (the default).
                  type: array
                  minItems: 1
                  items:
                    oneOf:
                      - $ref: '#/components/schemas/EventType'
                      - { type: string, const: '*' }
                description: { type: string, maxLength: 200 }
            example: { url: 'https://hooks.example.com/advanta', events: [request.routed, notice.acknowledged, notice.disputed, request.funded, settlement.recorded] }
      responses:
        '201':
          description: Created. Store `secret` now; it is not shown again.
          content:
            application/json:
              schema:
                type: object
                required: [webhook, secret, signature]
                properties:
                  webhook: { $ref: '#/components/schemas/WebhookEndpoint' }
                  secret: { type: string, pattern: '^whsec_[0-9a-f]{64}$' }
                  signature:
                    type: object
                    properties:
                      header: { type: string, const: Advanta-Signature }
                      scheme: { type: string }
                      tolerance_seconds: { type: integer, const: 300 }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '409':
          description: "`too_many_endpoints`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '422':
          description: |
            `body_required`, `url_required`, `url_invalid`, `url_too_long`, `url_must_be_https`,
            `url_has_credentials`, `url_port_not_allowed`, `url_host_not_allowed`, `url_not_allowed`,
            `events_invalid`, `unknown_event_type` or `invalid_description`.
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/webhooks/{id}:
    delete:
      tags: [Webhooks]
      operationId: deleteWebhook
      summary: Stop an endpoint
      description: Deliveries still pending are cancelled and its secrets are deleted. Scope `webhooks:write` or `decisions:write`.
      parameters:
        - $ref: '#/components/parameters/WebhookId'
      responses:
        '200':
          description: Stopped.
          content:
            application/json:
              schema:
                type: object
                required: [id, active, deleted, cancelled_deliveries]
                properties:
                  id: { type: string, format: uuid }
                  active: { type: boolean, const: false }
                  deleted: { type: boolean, const: true }
                  cancelled_deliveries: { type: integer }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/webhooks/{id}/rotate-secret:
    post:
      tags: [Webhooks]
      operationId: rotateWebhookSecret
      summary: A new signing secret (shown once)
      description: |
        The previous secret keeps signing, as a second `v1` in the header, for
        `keep_previous_hours` (0 to 72, default 24), so you can switch without losing events.
        Scope `webhooks:write` or `decisions:write`.
      parameters:
        - $ref: '#/components/parameters/WebhookId'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                keep_previous_hours: { type: integer, minimum: 0, maximum: 72, default: 24 }
      responses:
        '200':
          description: Rotated.
          content:
            application/json:
              schema:
                type: object
                required: [webhook, secret, previous_secret_valid_until]
                properties:
                  webhook: { $ref: '#/components/schemas/WebhookEndpoint' }
                  secret: { type: string, pattern: '^whsec_[0-9a-f]{64}$' }
                  previous_secret_valid_until: { type: [string, 'null'], format: date-time }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '422':
          description: "`invalid_keep_previous_hours`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/webhooks/{id}/test:
    post:
      tags: [Webhooks]
      operationId: testWebhook
      summary: Queue a webhook.test event to this endpoint
      description: Delivered by the next dispatcher run (within about a minute). Scope `webhooks:write` or `decisions:write`.
      parameters:
        - $ref: '#/components/parameters/WebhookId'
      responses:
        '202':
          description: Queued.
          content:
            application/json:
              schema:
                type: object
                required: [endpoint_id, event_id, delivery_id, status]
                properties:
                  endpoint_id: { type: string, format: uuid }
                  event_id: { type: string, format: uuid }
                  delivery_id: { type: string, format: uuid }
                  status: { type: string, const: pending }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/webhooks/{id}/deliveries:
    get:
      tags: [Webhooks]
      operationId: listWebhookDeliveries
      summary: The delivery log of an endpoint
      description: Newest first. Scope `webhooks:write`, `decisions:write` or `requests:read`.
      parameters:
        - $ref: '#/components/parameters/WebhookId'
        - { name: limit, in: query, schema: { type: integer, default: 50, minimum: 1, maximum: 200 } }
      responses:
        '200':
          description: The deliveries.
          content:
            application/json:
              schema:
                type: object
                required: [count, deliveries]
                properties:
                  count: { type: integer }
                  deliveries:
                    type: array
                    items: { $ref: '#/components/schemas/Delivery' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/onboarding-links:
    post:
      tags: [Onboarding]
      operationId: createOnboardingLink
      summary: A single-use onboarding link for one of your suppliers
      description: |
        Creates an invitation for a named company, attributed to you (inviter type funder),
        single use, valid for `valid_days` (1 to 30, default 14); only the SHA-256 of its token
        is stored. Advanta sends no e-mail: give `url` to your supplier. `return_url` must be
        https and its origin on your list of return origins (kept in the portal settings or by
        Advanta, never through this API). When the supplier has submitted its company
        verification you receive `onboarding.completed`, and the supplier is sent back to
        `return_url` with `advanta_onboarding`, `advanta_status`, `advanta_ts` and
        `advanta_sig` = hex HMAC-SHA256(`return_secret`, "<advanta_onboarding>.<advanta_status>.<advanta_ts>").
        `return_secret` is shown once, here. `company_name` may be left out for an EU VAT
        number VIES can name. A link made with a sandbox key registers the supplier as a test
        company on the demonstration plane. `prescriber_id` (optional) names one of your own
        active prescribers (GET /v1/prescribers) as the one who brought this company: it then
        counts for that prescriber in your report, and `client.joined` says so. Another funder's
        prescriber, or one you switched off, is refused (`prescriber_not_found`) and nothing is
        created. A company that reached you before keeps its first origin
        (`prescriber_attribution`: `already_known`). The supplier opens `url` on the app's
        invitation page (live since 23 September 2026). Scope `onboarding:write` or `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [company_vat, country, contact_email, return_url]
              properties:
                company_vat: { type: string, description: "The supplier's VAT or tax number (with or without the country prefix)." }
                country: { type: string, description: ISO 3166 alpha-2. }
                contact_email: { type: string, format: email }
                contact_name: { type: string, maxLength: 120 }
                company_name: { type: string, minLength: 2, maxLength: 200 }
                return_url: { type: string, format: uri, maxLength: 2048 }
                metadata:
                  type: object
                  description: At most 20 keys (letters, digits, _ . -), values string, number, boolean or null, 2 KB of JSON. Returned on the link and in onboarding.completed.
                  additionalProperties: { type: [string, number, boolean, 'null'] }
                locale: { type: string, enum: [pt, es, en, fr, de, it, nl] }
                valid_days: { type: integer, minimum: 1, maximum: 30, default: 14 }
                prescriber_id: { type: [string, 'null'], format: uuid, description: One of your active prescribers who brought this company. }
            example: { company_vat: PT512640017, country: PT, contact_email: ana@fornecedor.example, contact_name: Ana Sousa, company_name: Fornecedor Exemplo Lda, return_url: 'https://pronto.example.com/onboarding/done', metadata: { supplier_ref: S-42 } }
      responses:
        '201':
          description: Created. Store `return_secret` now; it is not shown again.
          content:
            application/json:
              schema:
                type: object
                required: [onboarding_link, url, expires_at, environment, return_secret]
                properties:
                  onboarding_link: { $ref: '#/components/schemas/OnboardingLink' }
                  url: { type: string, format: uri, description: 'https://app.advanta.capital/accept-invite?invitation=<token>&lang=<xx>' }
                  expires_at: { type: string, format: date-time }
                  environment: { type: string, enum: [live, sandbox, unclassified] }
                  return_secret: { type: string, pattern: '^ors_[0-9a-f]{64}$' }
                  prescriber_attribution:
                    type: string
                    enum: [recorded, already_known]
                    description: Only when `prescriber_id` was sent. `already_known`, the company reached you before and keeps that first origin.
                  return:
                    type: object
                    properties:
                      parameters: { type: array, items: { type: string } }
                      signature: { type: string }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '409':
          description: "`company_already_registered`, `email_has_account`, `invitation_pending_exists` or `country_not_served`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '422':
          description: |
            `body_required`, `country_invalid`, `company_vat_invalid`, `contact_email_invalid`,
            `contact_name_invalid`, `company_name_invalid`, `company_name_required`,
            `return_url_invalid`, `return_url_not_allowed`, `metadata_invalid`, `locale_invalid`,
            `valid_days_invalid`, `prescriber_id_invalid`, `prescriber_not_found` or `country_not_served`.
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }
    get:
      tags: [Onboarding]
      operationId: listOnboardingLinks
      summary: Your onboarding links
      description: Newest first. A sandbox key sees the links it created. Scope `onboarding:write`, `decisions:write` or `requests:read`.
      parameters:
        - { name: limit, in: query, schema: { type: integer, default: 50, minimum: 1, maximum: 200 } }
      responses:
        '200':
          description: The links.
          content:
            application/json:
              schema:
                type: object
                required: [count, onboarding_links]
                properties:
                  count: { type: integer }
                  onboarding_links: { type: array, items: { $ref: '#/components/schemas/OnboardingLink' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/onboarding-links/{id}:
    get:
      tags: [Onboarding]
      operationId: getOnboardingLink
      summary: One onboarding link and where the supplier is
      parameters:
        - { name: id, in: path, required: true, schema: { type: string, format: uuid } }
      responses:
        '200':
          description: The link.
          content:
            application/json:
              schema:
                type: object
                required: [onboarding_link]
                properties:
                  onboarding_link: { $ref: '#/components/schemas/OnboardingLink' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/prescribers:
    get:
      tags: [Clients]
      operationId: listPrescribers
      summary: Your prescribers, each with its open link
      description: |
        Your own introducers ("prescriptores"), active first, each with its current link: `state`
        (`active`, `disabled` or `expired`), `url` while it works (null otherwise), and how many
        companies arrived through it. They are yours, not Advanta's partners. The same list as the
        Clients page of your portal. A sandbox key reads the demonstration funder, whose prescribers
        are shared by every demonstration. Scope `requests:read`, `clients:write` or `decisions:write`.
      parameters:
        - $ref: '#/components/parameters/LinkLang'
      responses:
        '200':
          description: The prescribers.
          content:
            application/json:
              schema:
                type: object
                required: [funder, count, prescribers]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  count: { type: integer }
                  prescribers: { type: array, items: { $ref: '#/components/schemas/Prescriber' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422':
          description: "`lang_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }
    post:
      tags: [Clients]
      operationId: createPrescriber
      summary: Add a prescriber (its open link is issued with it)
      description: |
        `name` is 2 to 120 characters and unique among your active prescribers. `email` and `notes`
        (at most 1000 characters) are optional; a sandbox funder records only reserved addresses
        (ending in .example, .invalid, .test or .demo). The prescriber gets its own open link at once,
        in `prescriber.link.url`. Its name and e-mail are kept off Advanta's evidence chain (only
        their hashes are on it). Scope `clients:write` or `decisions:write`; in the sandbox this changes
        shared demonstration state, so a sandbox key needs `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name: { type: string, minLength: 2, maxLength: 120 }
                email: { type: [string, 'null'], format: email, maxLength: 254 }
                notes: { type: [string, 'null'], maxLength: 1000 }
                lang: { $ref: '#/components/schemas/LinkLang' }
            example: { name: Gestoría Norte, email: ana@gestoria-norte.example, notes: Accountant in Porto }
      responses:
        '201':
          description: Created, with its link.
          content:
            application/json:
              schema:
                type: object
                required: [prescriber]
                properties:
                  prescriber: { $ref: '#/components/schemas/Prescriber' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '409':
          description: "`prescriber_exists`: an active prescriber of yours already has this name."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '422':
          description: "`body_required`, `name_required`, `name_invalid`, `email_invalid`, `email_not_reserved`, `notes_too_long` or `lang_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/prescribers/report:
    get:
      tags: [Clients]
      operationId: getPrescriberReport
      summary: What each prescriber brought you
      description: |
        One group per prescriber, then your own link (`own_link`), your invitations by name
        (`named`) and the API's onboarding links (`api`). A company you invited by name or through
        the API naming one of your prescribers (`prescriber_id`) counts for that prescriber, not in
        `named` or `api`. Per group and per company: when it
        arrived, when its account was opened (`joined`), when its company verification was approved
        (`onboarded`), the requests routed to you, the amount requested and the amount funded
        (advance, else total, of funded or settled requests). A company counts once, for whoever
        brought it first to you. Only your data, only companies on your own data plane (a company
        Advanta classifies as a test leaves a live funder's report). The same numbers as your
        portal. A sandbox key does not see what other sandbox keys made through the API. Scope
        `requests:read`, `clients:write` or `decisions:write`.
      responses:
        '200':
          description: The report.
          content:
            application/json:
              schema:
                type: object
                required: [funder, plane, generated_at, currency, totals, groups]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  plane: { type: string, enum: [live, sandbox] }
                  generated_at: { type: string, format: date-time }
                  currency: { type: string, const: EUR }
                  totals:
                    type: object
                    description: The sum over every group.
                    properties:
                      arrived: { type: integer }
                      joined: { type: integer }
                      onboarded: { type: integer }
                      requests: { type: integer }
                      amount_requested: { type: number }
                      amount_funded: { type: number }
                  groups: { type: array, items: { $ref: '#/components/schemas/ReportGroup' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/prescribers/{id}/disable:
    post:
      tags: [Clients]
      operationId: disablePrescriber
      summary: Switch a prescriber off
      description: |
        Its link stops working at once; the companies it brought stay attributed to it. Disabling a
        prescriber already off changes nothing (`changed` false). On Advanta's evidence chain. Scope
        `clients:write` or `decisions:write`.
      parameters:
        - { name: id, in: path, required: true, schema: { type: string, format: uuid } }
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason: { type: string, maxLength: 200 }
      responses:
        '200':
          description: Switched off.
          content:
            application/json:
              schema:
                type: object
                required: [prescriber, changed]
                properties:
                  prescriber: { $ref: '#/components/schemas/Prescriber' }
                  changed: { type: boolean }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '422':
          description: "`body_invalid` or `reason_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/client-links:
    get:
      tags: [Clients]
      operationId: listClientLinks
      summary: Your open link and each prescriber's
      description: |
        The link of your own (`prescriber_id` null) and the current link of each prescriber, with
        its `url` while it works. A company that opens a link gives its name, tax number, country
        and e-mail and receives an invitation of yours by e-mail; when it accepts, you become its
        exclusive home funder, and its origin (the link, the prescriber, the date) is recorded.
        Opening a link never creates an account by itself. Like your portal, the API shows a working
        link's url again to its owner. Scope `requests:read`, `clients:write` or `decisions:write`.
      parameters:
        - $ref: '#/components/parameters/LinkLang'
      responses:
        '200':
          description: The links.
          content:
            application/json:
              schema:
                type: object
                required: [funder, count, client_links]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  count: { type: integer }
                  client_links: { type: array, items: { $ref: '#/components/schemas/ClientLink' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422':
          description: "`lang_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }
    post:
      tags: [Clients]
      operationId: issueClientLink
      summary: Issue your open link, or a prescriber's
      description: |
        Without `prescriber_id`, your own link; with it, that prescriber's. There is one working
        link per owner: when one still works, send `replace: true` to replace it (the old one stops
        working at once and points at the new one), otherwise `link_exists`. `expires_at` is
        optional, between one hour and three years from now. Only the SHA-256 of the token is
        stored. A sandbox funder's link makes test invitations only. On Advanta's evidence chain.
        Scope `clients:write` or `decisions:write`; a sandbox key needs `decisions:write`.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                prescriber_id: { type: [string, 'null'], format: uuid }
                expires_at: { type: [string, 'null'], format: date-time }
                reason: { type: string, maxLength: 200, description: Why (kept on the replaced link and on the evidence chain). }
                replace: { type: boolean, default: false }
                lang: { $ref: '#/components/schemas/LinkLang' }
            example: { prescriber_id: 5f1c2a8e-3b7d-4e0a-9c61-2d4b8e7f9a10, expires_at: '2026-12-31T23:59:59Z' }
      responses:
        '201':
          description: Issued.
          content:
            application/json:
              schema:
                type: object
                required: [client_link]
                properties:
                  client_link: { $ref: '#/components/schemas/ClientLink' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404':
          description: "`not_found`: no such active prescriber of yours."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '409':
          description: "`link_exists`: a link that still works; send `replace: true`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '422':
          description: "`body_invalid`, `prescriber_id_invalid`, `expires_at_invalid`, `reason_invalid`, `replace_invalid` or `lang_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/client-links/{id}/disable:
    post:
      tags: [Clients]
      operationId: disableClientLink
      summary: Switch a link off
      description: |
        It stops working at once; companies that already arrived through it keep their origin.
        Switching off a link already off changes nothing (`changed` false). Issue a new one with
        POST /v1/client-links. On Advanta's evidence chain. Scope `clients:write` or `decisions:write`.
      parameters:
        - { name: id, in: path, required: true, schema: { type: string, format: uuid } }
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason: { type: string, maxLength: 200 }
      responses:
        '200':
          description: Switched off.
          content:
            application/json:
              schema:
                type: object
                required: [link_id, changed, state]
                properties:
                  link_id: { type: string, format: uuid }
                  changed: { type: boolean }
                  state: { type: string, const: disabled }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '422':
          description: "`body_invalid` or `reason_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/client-invitations:
    get:
      tags: [Clients]
      operationId: listClientInvitations
      summary: Your invitations, each with the company's origin
      description: |
        Every invitation of yours (through a link, by name in the portal, or an API onboarding link),
        newest first, on your own data plane, with `via` (`link`, `named` or `api`) and the
        prescriber that brought the company, if any. A sandbox key does not see the invitations other
        sandbox keys made. Scope `requests:read`, `clients:write` or `decisions:write`.
      parameters:
        - { name: limit, in: query, schema: { type: integer, default: 200, minimum: 1, maximum: 500 } }
      responses:
        '200':
          description: The invitations.
          content:
            application/json:
              schema:
                type: object
                required: [funder, count, invitations]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  count: { type: integer }
                  invitations: { type: array, items: { $ref: '#/components/schemas/ClientInvitation' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/exports:
    post:
      tags: [Exports]
      operationId: startExport
      summary: Export everything you can see (your exit right)
      description: |
        Starts an export of everything this funder can see on Advanta, as the portal's Export page
        does: requests and their history, offers, invoices with their verification, sellers (company
        data, the KYC summary you may see, the seller's representative verification), debtors,
        cession and confirming notices with the debtors' answers and the certificates' data, the
        evidence chain entries about your operations with the hashes and day roots to verify them,
        settlements and statements, gate refusals, your rules and limits, your team, your webhook
        endpoints (never a signing secret), your API keys (never a key), your audit trail and your
        documents. DORA Art. 28(8) and Art. 30(3)(f): you can take your data and leave, at any time,
        without asking.

        The export is built in the background (usually within a minute) into a ZIP: one CSV (UTF-8,
        header row, RFC 4180, ISO 8601 dates and UTC times, decimal point) and one JSON Lines file per
        entity, `schema.json` (every column), `manifest.json` (every file's SHA-256 and size, the rows
        of every entity, and `manifest_sha256`, the SHA-256 of the manifest's canonical form),
        `README.txt` in `lang`, and `verify.py`, which checks all of it with Python 3.8 alone. A large
        export comes in several volumes. Documents are inside when they total at most 64 MiB and 400
        files; otherwise `documents/index.csv` has links and `GET /v1/exports/{id}/documents` gives
        fresh ones. The manifest digest is recorded on the export and on the evidence chain.
        Subscribe to `export.ready` to be told when it is ready, or poll `GET /v1/exports/{id}`.

        A live key only, with scope `exports:write` or `decisions:write`. One export at a time;
        at most 10 in 24 hours.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                lang: { type: string, enum: [pt, es, en, fr, de, it, nl], description: The language of README.txt (default en). }
      responses:
        '202':
          description: The export, queued.
          content:
            application/json:
              schema:
                type: object
                required: [funder, export]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  export: { $ref: '#/components/schemas/Export' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403':
          description: "`forbidden` (the key lacks `exports:write`), or `export_live_key_required`: a sandbox key cannot export (the demonstration funder is shared)."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '409':
          description: "`export_in_progress`: an export of yours is still being built."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '422':
          description: "`body_invalid` or `lang_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '429':
          description: "`export_rate_limited`: at most 10 exports in 24 hours."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/ServerError' }
    get:
      tags: [Exports]
      operationId: listExports
      summary: Your exports, from the portal and the API
      description: Newest first, every status. Scope `exports:write` or `decisions:write`; a live key only.
      parameters:
        - { name: limit, in: query, schema: { type: integer, default: 50, minimum: 1, maximum: 200 } }
      responses:
        '200':
          description: The exports.
          content:
            application/json:
              schema:
                type: object
                required: [funder, count, exports]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  count: { type: integer }
                  exports: { type: array, items: { $ref: '#/components/schemas/Export' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403':
          description: "`forbidden` or `export_live_key_required`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/ServerError' }
  /v1/exports/{id}:
    get:
      tags: [Exports]
      operationId: getExport
      summary: One export, and its files while they can be downloaded
      description: |
        The export's status (`queued`, `running`, `ready` or `failed`), its progress while it is
        built, and once it is ready its `manifest_sha256`, size, row counts and volumes. For 24
        hours after it is ready, `files` lists each volume with a signed link valid for one hour at
        most (never past those 24 hours); ask again for fresh links. Every call that returns links
        is recorded. After 24 hours the files are deleted; the record stays. Scope `exports:write`
        or `decisions:write`; a live key only.
      parameters: [{ $ref: '#/components/parameters/ExportId' }]
      responses:
        '200':
          description: The export.
          content:
            application/json:
              schema:
                type: object
                required: [funder, export, files]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  export: { $ref: '#/components/schemas/Export' }
                  files: { type: array, items: { $ref: '#/components/schemas/ExportFile' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403':
          description: "`forbidden` or `export_live_key_required`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/ServerError' }
  /v1/exports/{id}/documents:
    get:
      tags: [Exports]
      operationId: listExportDocuments
      summary: The export's documents, with fresh links, a page at a time
      description: |
        Every document of the export (invoice PDFs and e-invoices, offline notice documents, KYC
        documents, the seller documents you may read) with a signed link valid for 15 minutes.
        Page with `after` = the previous answer's `next_after` until it is null. The list is computed
        when you ask, so a document you may no longer read is not in it. Available while the
        export's files can be downloaded (24 hours after it is ready). Every page is recorded, and
        every document is logged as the portal logs its downloads. Scope `exports:write` or
        `decisions:write`; a live key only.
      parameters:
        - { $ref: '#/components/parameters/ExportId' }
        - { name: after, in: query, schema: { type: string }, description: The previous page's next_after. }
        - { name: limit, in: query, schema: { type: integer, default: 100, minimum: 1, maximum: 200 } }
      responses:
        '200':
          description: A page of documents.
          content:
            application/json:
              schema:
                type: object
                required: [funder, export_id, documents, next_after]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  export_id: { type: string, format: uuid }
                  documents: { type: array, items: { $ref: '#/components/schemas/ExportDocument' } }
                  next_after: { type: [string, 'null'], description: Pass it as after for the next page; null on the last one. }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403':
          description: "`forbidden` or `export_live_key_required`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '409':
          description: "`export_not_ready` (still being built) or `export_failed`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '410':
          description: "`export_expired`: its files could be downloaded for 24 hours; start a new export."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/opportunities:
    get:
      tags: [Opportunities]
      operationId: getOpportunities
      summary: The opportunities of the day from your own clients
      description: |
        Every morning at about 06:30 Madrid time, after the nightly prequalification, Advanta builds
        your digest: for each of your own clients (companies whose home funder you are) that allows you
        to see it, the invoices that became eligible under your rules since the previous digest
        (`kind` new), with the debtor and its tax id, the amount, the due date, and the client with its
        sector (NACE section), grade and size band; and what changed in the invoices you were shown
        before: `paid`, `disputed` (the client recorded that its debtor contests it), or `no_longer_eligible` with a
        `reason` (`requested`: the client asked to finance it; `cancelled`; `removed`: gone from the
        client's books; `left_programme`; `not_shared`: the client stopped sharing; `rules`: it no longer
        meets your rules). The totals say how many clients share and how many do not yet, what is
        eligible today, what is new and what changed. `stale` is true when the night's run did not
        complete: nothing was compared that morning. A digest is a list the database computed, not an
        offer: a request is checked again when it is made, and you decide and price it as always.
        The webhook event `opportunities.daily` says when a digest with something in it is ready.
        Scope `requests:read`.
      parameters:
        - name: date
          in: query
          description: The day of the digest (YYYY-MM-DD, Madrid). Absent, the latest.
          schema: { type: string, format: date }
      responses:
        '200':
          description: The digest of that day; `date` null and no lines when there is none.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Opportunities' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '422':
          description: "`invalid_date`: not a calendar day."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/graph/debtors/{vat}:
    get:
      tags: [Payer record]
      operationId: getGraphDebtor
      summary: The payment graph's record of one debtor
      description: |
        How a debtor pays its suppliers across the ledgers Advanta reads, recomputed every morning:
        a `score` from 0 to 100, a `band` A to E, `good_payer`, the `confidence`, every reason with
        its points and source (the median delay against real due dates, the late tail, the on-time
        share, what is open and overdue, the trend, the debtor watch), the figures, and the previous
        day's score. Published only when three or more suppliers observe the debtor; otherwise
        `status` is `not_published` with a `reason` (`below_threshold`, `held` while a correction the
        debtor asked for stands, `funder_unclassified`) and no figure. Only for a debtor on a request
        in your scope or on your debtor list. A sandbox key reads the demonstration plane. Every call
        is recorded as your read. The score describes payment behaviour; it is not a credit opinion
        or a price: you decide and price. Scope `limits:read` or `requests:read`.
      parameters:
        - { name: vat, in: path, required: true, schema: { type: string }, description: "The debtor's VAT or tax number." }
        - { name: country, in: query, schema: { type: string }, description: ISO 3166 alpha-2. }
      responses:
        '200':
          description: The debtor's record, or why it is not published.
          content:
            application/json:
              schema:
                type: object
                required: [funder, debtor]
                properties:
                  funder: { $ref: '#/components/schemas/FunderRef' }
                  debtor:
                    type: object
                    required: [status]
                    properties:
                      status: { type: string, enum: [published, not_published] }
                      reason: { type: string, enum: [below_threshold, held, funder_unclassified] }
                      debtor_key: { type: string }
                      country: { type: string }
                      score: { type: integer, minimum: 0, maximum: 100 }
                      band: { type: string, enum: [A, B, C, D, E] }
                      good_payer: { type: boolean }
                      confidence: { type: string, enum: [low, medium, high] }
                      reasons:
                        type: array
                        items:
                          type: object
                          required: [code, points, source]
                          properties:
                            code: { type: string }
                            points: { type: integer }
                            value: {}
                            unit: { type: string }
                            source: { type: string, enum: [graph, debtor_watch] }
                      figures: { type: object, additionalProperties: true }
                      previous: { type: object, additionalProperties: true }
                      min_suppliers: { type: integer }
                      plane: { type: string, enum: [live, sandbox] }
                      model_version: { type: string }
                      computed_on: { type: string, format: date }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '422':
          description: "`tax_id_invalid` or `country_invalid`."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '429':
          description: "`rate_limited`: too many graph reads this hour; `retry_after` in seconds."
          content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
        '500': { $ref: '#/components/responses/ServerError' }

  /v1/registry/lookups:
    post:
      tags: [Assignment registry]
      operationId: registryLookup
      summary: Is each invoice already assigned or pledged?
      description: |
        Up to 100 invoices a call (`invoices`, or one invoice as the body). For each: `assigned` true or false; when
        true, `kind` (`assignment` or `pledge`), `match` (`exact`: the same seller, debtor, number, amount and issue
        date; `partial`: the same seller, debtor and number, another amount or date) and `yours` (you hold it
        yourself). When another funder holds it, a conflict is raised (`conflict_id`): both of you get the webhook
        `registry.conflict`, neither named to the other. An invoice that cannot be read is answered with `errors`
        (`seller_tax_id_required`, `seller_country_invalid`, `seller_tax_id_invalid`, the same for the debtor,
        `number_required`, `amount_invalid`, `currency_invalid`, `issue_date_invalid`, `reference_too_long`).
        Counted per funder: 2,000 invoices an hour, 20,000 a day. Scope `requests:read` or `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [invoices]
              properties: { invoices: { type: array, minItems: 1, maxItems: 100, items: { $ref: '#/components/schemas/RegistryInvoice' } } }
      responses:
        '200':
          description: One answer per invoice, in the order sent (`index`).
          content:
            application/json:
              schema:
                type: object
                properties:
                  results: { type: array, items: { $ref: '#/components/schemas/RegistryAnswer' } }
                  checked_at: { type: string, format: date-time }
        '400': { description: "`invalid_json`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { description: "`forbidden` (the key's scope) or `registry_not_open`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '413': { description: "`too_many_invoices`: at most 100 a call", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '422': { description: "`invoices_required`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '429': { description: "`rate_limited`, with `retry_after` and the Retry-After header", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '500': { $ref: '#/components/responses/ServerError' }
        '503': { description: "`registry_unavailable`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
  /v1/registry/assignments:
    get:
      tags: [Assignment registry]
      operationId: registryEntries
      summary: What you hold in the register
      description: |
        Your entries, newest first: from your requests on Advanta (`source` platform: reserved while the request is in
        progress, assigned once funded, discharged once paid, released when it ends otherwise) and from your own book
        (`source` api or portal). With the counts. Scope `requests:read`.
      parameters:
        - { name: state, in: query, schema: { type: string, enum: [reserved, assigned, discharged, released] } }
        - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 200, default: 50 } }
        - { name: before, in: query, description: Entries registered before this time, for the next page., schema: { type: string, format: date-time } }
      responses:
        '200':
          description: The counts and the entries.
          content:
            application/json:
              schema:
                type: object
                properties:
                  summary: { type: object }
                  entries: { type: array, items: { $ref: '#/components/schemas/RegistryEntry' } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { description: "`forbidden` or `registry_not_open`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '422': { description: "`invalid_state` or `invalid_paging`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '500': { $ref: '#/components/responses/ServerError' }
    post:
      tags: [Assignment registry]
      operationId: registryRegister
      summary: Register your own assignments and pledges made outside Advanta
      description: |
        Up to 100 invoices a call, each with `kind` (`assignment`, the default, or `pledge`). Each is looked up first:
        when another holds it, it is not registered (`assigned_elsewhere`, with the conflict raised and both of you
        told); when you already hold it, `already_yours` with its `entry_id`; otherwise it is registered
        (`registered` true, `entry_id`). Counted per funder: 5,000 a day. Scope `decisions:write`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [invoices]
              properties: { invoices: { type: array, minItems: 1, maxItems: 100, items: { $ref: '#/components/schemas/RegistryInvoice' } } }
      responses:
        '200':
          description: One answer per invoice (`index`, `registered`, and `entry_id`, `assigned_elsewhere`, `already_yours` or `errors`).
          content: { application/json: { schema: { type: object, properties: { results: { type: array, items: { type: object } }, checked_at: { type: string, format: date-time } } } } }
        '400': { description: "`invalid_json`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { description: "`forbidden` or `registry_not_open`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '413': { description: "`too_many_invoices`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '422': { description: "`invoices_required`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '429': { description: "`rate_limited`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '500': { $ref: '#/components/responses/ServerError' }
  /v1/registry/assignments/{id}/release:
    post:
      tags: [Assignment registry]
      operationId: registryRelease
      summary: An entry you registered is paid or ends
      description: |
        `reason`: `paid` (discharged: it still answers an exact match, so a paid invoice cannot be financed again),
        `repurchased`, `cancelled`, `expired` or `error` (released: it answers nothing). Entries of your requests on
        Advanta follow the request and are not released here (409 `entry_follows_its_request`). Scope `decisions:write`.
      parameters: [{ name: id, in: path, required: true, schema: { type: string, format: uuid } }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { type: object, required: [reason], properties: { reason: { type: string, enum: [paid, repurchased, cancelled, expired, error] } } }
      responses:
        '200':
          description: The entry's new state.
          content: { application/json: { schema: { type: object, properties: { entry_id: { type: string, format: uuid }, state: { type: string }, release_reason: { type: string }, changed_at: { type: string, format: date-time } } } } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { description: "`forbidden` or `registry_not_open`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '404': { $ref: '#/components/responses/NotFound' }
        '409': { description: "`entry_follows_its_request` or `entry_closed`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '422': { description: "`invalid_reason`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '500': { $ref: '#/components/responses/ServerError' }
  /v1/registry/conflicts:
    get:
      tags: [Assignment registry]
      operationId: registryConflicts
      summary: The conflicts you are part of
      description: |
        Newest first: your `role` (`holder`: an invoice you hold was presented elsewhere; `asker`: an invoice you asked
        about or tried to register is held elsewhere), `kind`, `match`, your own reference, `status` (`open` until
        Advanta operations review it). Never the other funder. Scope `requests:read`.
      parameters:
        - { name: status, in: query, schema: { type: string, enum: [open, resolved, dismissed] } }
        - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 200, default: 50 } }
      responses:
        '200':
          description: The conflicts.
          content: { application/json: { schema: { type: object, properties: { conflicts: { type: array, items: { $ref: '#/components/schemas/RegistryConflict' } } } } } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { description: "`forbidden` or `registry_not_open`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '422': { description: "`invalid_status` or `invalid_paging`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '500': { $ref: '#/components/responses/ServerError' }
  /v1/early-payments:
    get:
      tags: [Buyer programme early payments]
      operationId: earlyPaymentsList
      summary: The buyer programmes' early payments you make
      description: |
        The offers of buyer programmes you pay early, on the buyer's behalf: those the supplier accepted that you have
        still to pay (`to_pay`), and each early payment you recorded with the buyer's repayment to you (`due`, `overdue`
        after the invoice's due date, `repaid`), to pay first, then overdue, then due by date. With the totals: what is
        to pay, what the buyers owe you (`owed`), overdue, repaid, the next due date. Scope `requests:read` or
        `decisions:write`.
      parameters:
        - { name: state, in: query, schema: { type: string, enum: [to_pay, due, overdue, repaid] } }
        - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 500, default: 100 } }
      responses:
        '200':
          description: The totals and the early payments.
          content:
            application/json:
              schema:
                type: object
                properties:
                  today: { type: string, format: date, description: The day the states are computed on (Europe/Lisbon). }
                  totals: { $ref: '#/components/schemas/EarlyPaymentTotals' }
                  early_payments: { type: array, items: { $ref: '#/components/schemas/EarlyPayment' } }
                  limit: { type: integer }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '422': { description: "`invalid_query`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '500': { $ref: '#/components/responses/ServerError' }
  /v1/early-payments/{id}/confirm:
    post:
      tags: [Buyer programme early payments]
      operationId: earlyPaymentConfirm
      summary: You paid the supplier early
      description: |
        `id` is the offer's. Record the early payment you made to the supplier, on the buyer's behalf: the date the money
        left your account (today or before, not before the supplier accepted) and the amount, which is the accepted
        offer's net amount unless you give a `reason` of 8 to 500 characters; your bank reference if you wish (3 to 140
        characters). The payment instruction and the invoice are settled, and the buyer owes you the invoice amount on
        its due date (`repayment`). Recorded once. Another funder's offer answers 404, as an unknown one does. Scope
        `decisions:write`.
      parameters: [{ name: id, in: path, required: true, schema: { type: string, format: uuid } }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/MoneyRecord' }
      responses:
        '200':
          description: The early payment and the repayment it created.
          content:
            application/json:
              schema:
                type: object
                properties:
                  early_payment_id: { type: string, format: uuid }
                  offer_id: { type: string, format: uuid }
                  amount: { type: number }
                  value_date: { type: string, format: date }
                  bank_reference: { type: [string, 'null'] }
                  payment_instruction_status: { type: string, const: settled }
                  repayment: { type: object, properties: { amount: { type: number }, due_date: { type: string, format: date }, state: { type: string, enum: [due, overdue] } } }
                  evidence_seq: { type: integer }
        '400': { description: "`invalid_json`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '409': { description: "`offer_not_accepted`, `no_payment_instruction` or `already_confirmed`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '422': { description: "`body_invalid`, `value_date_required`, `value_date_in_the_future`, `value_date_before_acceptance`, `amount_invalid`, `reason_required` or `reference_invalid`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '500': { $ref: '#/components/responses/ServerError' }
  /v1/early-payments/{id}/repayment:
    post:
      tags: [Buyer programme early payments]
      operationId: earlyPaymentRepayment
      summary: The buyer repaid you
      description: |
        `id` is the offer's. Record the buyer's repayment of an early payment you made: the date the money reached your
        account (today or before, not before your early payment) and the amount, which is what is owed (the invoice
        amount) unless you give a `reason` of 8 to 500 characters; your bank reference if you wish. Recorded once; until
        then the repayment is `due`, or `overdue` after the invoice's due date. Before the early payment is recorded,
        409 `not_paid_early`. Scope `decisions:write`.
      parameters: [{ name: id, in: path, required: true, schema: { type: string, format: uuid } }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/MoneyRecord' }
      responses:
        '200':
          description: The repayment, recorded.
          content:
            application/json:
              schema:
                type: object
                properties:
                  repayment_id: { type: string, format: uuid }
                  offer_id: { type: string, format: uuid }
                  owed: { type: number }
                  due_date: { type: string, format: date }
                  amount: { type: number }
                  value_date: { type: string, format: date }
                  bank_reference: { type: [string, 'null'] }
                  state: { type: string, const: paid }
                  days_after_due: { type: integer }
                  evidence_seq: { type: integer }
        '400': { description: "`invalid_json`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '409': { description: "`not_paid_early` or `already_repaid`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '422': { description: "`body_invalid`, `value_date_required`, `value_date_in_the_future`, `value_date_before_early_payment`, `amount_invalid`, `reason_required` or `reference_invalid`", content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
        '500': { $ref: '#/components/responses/ServerError' }

webhooks:
  request.routed:
    post:
      summary: Advanta operations routed a request to you
      description: "You can now read it and decide. data: request_id, request_ref, type, status, total_amount, currency, routed_at."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/RequestEventData' } }
      responses: { '2XX': { description: Received. Anything else is retried. } }
  request.unrouted:
    post:
      summary: A request routed to you was routed elsewhere or unrouted
      description: "You can no longer act on it. data: request_id, request_ref, unrouted_at."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody: { content: { application/json: { schema: { $ref: '#/components/schemas/Event' } } } }
      responses: { '2XX': { description: Received. } }
  offer.accepted:
    post:
      summary: Your offer was accepted
      description: "data: offer_id, request_id, request_ref, request_status (approved once the seller accepted), rate, advance_pct, days, accepted_at. You can fund it."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody: { content: { application/json: { schema: { $ref: '#/components/schemas/Event' } } } }
      responses: { '2XX': { description: Received. } }
  notice.acknowledged:
    post:
      summary: A debtor acknowledged the assignment notice
      description: "One event per debtor. data: notice_id, request_id, request_ref, debtor_name, debtor_tax_id, invoice_count, total_amount, channel (online | offline), decided_at."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/NoticeEventData' } }
      responses: { '2XX': { description: Received. } }
  notice.disputed:
    post:
      summary: A debtor rejected the assignment notice
      description: "One event per debtor, with the same data as notice.acknowledged plus reason (the debtor's words, at most 500 characters)."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/NoticeEventData' } }
      responses: { '2XX': { description: Received. } }
  request.funded:
    post:
      summary: A request routed to you was funded
      description: "data: the request fields of request.routed plus funded_at and advance_amount."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody: { content: { application/json: { schema: { $ref: '#/components/schemas/Event' } } } }
      responses: { '2XX': { description: Received. } }
  settlement.recorded:
    post:
      summary: Money received on a funded request was recorded
      description: Partial or final (the payment that settles the request has final true).
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/SettlementEventData' } }
      responses: { '2XX': { description: Received. } }
  seller.documents_expiring:
    post:
      summary: A dated document of a seller routed to you is about to expire
      description: |
        Checked daily. For a seller with an open or funded request routed to you, each dated
        document (for example a tax or social-security certificate) is announced at 30 days, at
        7 days and on the day it expires. data: seller_id, company_name, company_tax_id,
        document_id, document_type, valid_until, days_left, threshold_days (30 | 7 | 0), request_ids.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody: { content: { application/json: { schema: { $ref: '#/components/schemas/Event' } } } }
      responses: { '2XX': { description: Received. } }
  dispute.opened:
    post:
      summary: A debtor disputed invoices on a request routed to you, after approval or funding
      description: "data: dispute_id, request_id, request_ref, notice_id, debtor_name, debtor_tax_id, invoice_numbers, reason (goods_not_received | defective | amount_incorrect | already_paid | not_our_invoice | other), description (at most 500 characters), amount_disputed, channel (cession_page | letter | email), reported_by, received_on, request_status, status."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody: { content: { application/json: { schema: { $ref: '#/components/schemas/Event' } } } }
      responses: { '2XX': { description: Received. } }
  dispute.resolved:
    post:
      summary: Advanta operations closed a dispute
      description: "The data of dispute.opened with status (resolved_for_debtor | resolved_for_seller | withdrawn), resolved_at and resolution_note."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody: { content: { application/json: { schema: { $ref: '#/components/schemas/Event' } } } }
      responses: { '2XX': { description: Received. } }
  onboarding.completed:
    post:
      summary: A supplier you invited with an onboarding link submitted its company verification
      description: "data: onboarding_link_id, status (completed), company_name, company_tax_id, country, seller_id, account_created_at, completed_at, verification_status, metadata (yours, as sent). For a link made with a sandbox key, only that key's endpoints receive it."
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody: { content: { application/json: { schema: { $ref: '#/components/schemas/Event' } } } }
      responses: { '2XX': { description: Received. } }
  client.joined:
    post:
      summary: A company you invited accepted and is now your client
      description: |
        A company accepted one of your invitations (by name, through your open link or a
        prescriber's, or an API onboarding link) and opened its account: you are now its exclusive
        home funder, so its requests come to you. Sent once per invitation, to you only. data: the
        company as you invited it and where it came from (`origin`: `named`, `open_link`,
        `prescriber` or `api`; a company counts for whoever brought it to you first). For an API
        onboarding link made with a sandbox key, only that key's endpoints receive it. No
        verification yet: `onboarding.completed` (API links) and your portal tell you when its
        company verification is in.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/ClientJoinedEventData' } }
      responses: { '2XX': { description: Received. } }
  export.ready:
    post:
      summary: An export of yours is ready to download
      description: |
        An export you asked for (portal or API) is ready: its files can be downloaded for 24 hours
        with GET /v1/exports/{id}. data: export_id, status, requested_via, manifest_sha256 (the digest
        of its manifest, also on the evidence chain), size_bytes, file_count, documents_mode (files,
        links or none), volumes (name, bytes and SHA-256 of each ZIP), completed_at, expires_at. No
        link: the event never carries one.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/ExportReadyEventData' } }
      responses: { '2XX': { description: Received. } }
  request.announced:
    post:
      summary: A confidential request routed to you was announced
      description: |
        You (portal or API) or Advanta operations announced it, or a trigger you turned on did
        (`trigger`: manual, overdue, dispute or kyc_lapsed, with `reason`). The request is now
        announced and its prepared notices are being sent to the debtors, each listed with the
        prepared document's id and SHA-256. data: request_id, request_ref, trigger, reason, status,
        notices, announced_at.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/RequestAnnouncedEventData' } }
      responses: { '2XX': { description: Received. } }
  recourse.opened:
    post:
      summary: A funded request of yours opened a recourse claim or a debtor default
      description: |
        The request is not settled `recourse_days` after an invoice's due date. `kind` recourse: a
        claim against the seller, who repays `claim_amount` into your collection account quoting
        `pay_reference`; `kind` debtor_default (without recourse): flagged for your own collections
        and insurance. data: claim_id, request_id, request_ref, kind, claim_amount, funded_amount,
        fee_amount, collected_before, first_due_date, days_after_due, invoice_ids, pay_reference.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/RecourseOpenedEventData' } }
      responses: { '2XX': { description: Received. } }
  recourse.settled:
    post:
      summary: A recourse claim or debtor default was settled
      description: |
        `via` statement or manual: the payments you recorded since the claim opened cover it, and
        the request closed as settled by recourse (the invoices go back to the seller, still unpaid
        by the debtor). `via` request_settled: the request settled the ordinary way. data: claim_id,
        request_id, request_ref, kind, claim_amount, paid (not for request_settled), via,
        request_closed.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/RecourseSettledEventData' } }
      responses: { '2XX': { description: Received. } }
  payment.reached_seller:
    post:
      summary: A debtor's payment on a confidential request reached the seller
      description: |
        On an account the seller shares with you (read-only, with its consent), a payment came in
        from a debtor of a request you funded under confidential terms, booked from the day before
        funding onwards: its reference carries a financed invoice's number (`match_rule`
        invoice_reference), or the payer is the debtor and the amount is an invoice's or the
        debtor's total on the request (payer_and_amount). It is flagged so you can follow it up with
        the seller. data: alert_id, request_id, invoice_ids, payer_name, payer_iban, amount,
        currency, booking_date, match_rule, confidence.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/PaymentReachedSellerEventData' } }
      responses: { '2XX': { description: Received. } }
  opportunities.daily:
    post:
      summary: Your opportunities of the day are ready
      description: |
        The morning's digest has something in it: invoices of your own clients that became eligible
        since the previous digest, or a change in those you were shown. A summary only (counts and
        totals, never an invoice, a debtor or a client): read the lines with
        `GET /v1/opportunities?date=` (`data.lines`). At most one per day; none on a day with nothing
        new and nothing changed. data: digest_id, date, stale, snapshot_at, clients, eligible, new,
        changes, currency, lines.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/OpportunitiesSummary' } }
      responses: { '2XX': { description: Received. } }
  debtor.watch_blocked:
    post:
      summary: A debtor of a request you funded is blocked by an official source
      description: |
        The debtor watch read, in an official bulletin (the BORME for Spanish companies, Citius for
        Portuguese ones), an act that blocks a debtor of a request you funded for new financing:
        insolvency declared or in progress, liquidation, insolvency concluded for lack of assets,
        dissolution, extinction, or the register sheet closed by the tax agency or after an
        insolvency. While it stands, no new offer and no new funding go to this debtor's invoices.
        One event per request and per change into blocked (a debtor that ops set aside and that
        becomes blocked again is told again); the request's page shows the acts with their links.
        It is what a public bulletin published, for you to review, not a legal conclusion. Only
        companies in Spain and Portugal are watched. data: request_id, request_ref, debtor (country,
        tax_id, name), status, note, events (kind, published_on, source, url), detected_at.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/DebtorWatchBlockedEventData' } }
      responses: { '2XX': { description: Received. } }
  pre_offer.accepted:
    post:
      summary: A client requested the invoices of your pre-offer
      description: |
        You sent one of your own clients a pre-offer from your morning opportunities (indicative
        terms from your own credit box grid), and the client requested financing for invoices of it:
        its usual request, with every check, now carries the pre-offer. The request is routed to you
        as always (request.routed), and your credit box prepares your offer from your grid; you send
        it as any offer. The terms here are the ones your grid gave when you sent the pre-offer: the
        price is yours, Advanta states none. One event per pre-offer, once. data: pre_offer_id,
        request_id, request_ref, seller_id, company_name, company_tax_id, invoice_ids, invoice_count,
        total_amount, currency, terms (advance_pct, rate, term_days, grade, grid_version), sent_at,
        valid_until, accepted_at.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/PreOfferAcceptedEventData' } }
      responses: { '2XX': { description: Received. } }
  registry.conflict:
    post:
      summary: An invoice is claimed twice in the assignment registry
      description: |
        Sent to both funders, neither named to the other. `role` holder: an invoice you hold (from a request on Advanta,
        `request_id` and `request_ref`, or your own book, your `reference`) was presented elsewhere: asked about by
        another funder, registered by one, or submitted again by the seller. `role` asker: an invoice you asked about
        or tried to register is already assigned or pledged elsewhere (your `reference`, `lookup_id`). `match` exact
        or partial. No amount, no terms. data: conflict_id, role, kind, match, reference, detected_at, and entry_id,
        request_id, request_ref (holder) or lookup_id (asker).
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/RegistryConflict' } }
      responses: { '2XX': { description: Received. } }
  payout.instruction:
    post:
      summary: An accepted request is ready to pay (the ten-minute path)
      description: |
        Sent only for requests on the ten-minute path (ADR 0052): a company with your programme switched on
        automatic financing, your rule's offer was accepted within the company's own bounds, and every funding
        gate passes now (the notice your programme needs, the checks, screening, limits, documents). It carries
        what your system needs to pay the company and then to record it: the accepted advance (the amount
        POST /v1/requests/{id}/decision with decision fund checks to the cent), the company's account, the
        remittance text and a unique end-to-end id. SEPA Instant is requested; your bank executes, Advanta never
        moves the money. When your bank has paid, send the `confirm` object as the decision (decision fund,
        value_date, reference, amount). A pain.001.001.03 file of the same transfer is in the funder portal when
        your account is registered on the platform. Not sent while the path is switched off. data:
        instruction_id, request_id, request_ref, amount, currency, creditor (name, iban, confirmed_by_bank),
        remittance, end_to_end_id, execution_date, instant, pain001_sha256, issued_at, confirm.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/PayoutInstructionEventData' } }
      responses: { '2XX': { description: Received. } }
  programme.early_payment_confirmed:
    post:
      summary: Your early payment to a buyer's supplier is recorded
      description: |
        Buyer programmes (ADR 0064, tag Buyer programme early payments): an early payment you made to a supplier, on the
        buyer's behalf, is recorded: by you (the portal, POST /v1/early-payments/{id}/confirm or a line of your own bank
        statement you confirmed) or by a privileged settlement of its payment instruction. The buyer now owes you the
        invoice amount on its due date (`repayment`). One event per early payment, once. data: ProgrammeMoneyEventData.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/ProgrammeMoneyEventData' } }
      responses: { '2XX': { description: Received. } }
  programme.repayment_due_soon:
    post:
      summary: A buyer's repayment to you falls due soon
      description: |
        A repayment a buyer owes you for one of your early payments falls due in 7 days or fewer (`threshold_days` 7),
        then tomorrow or today (`threshold_days` 1), with `days_to_due`. Written by the morning run (Europe/Lisbon
        day); the buyer's team is reminded in its app at the same milestones. Once per repayment and threshold; not
        sent once you recorded the repayment. data: ProgrammeMoneyEventData with days_to_due and threshold_days.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/ProgrammeMoneyEventData' } }
      responses: { '2XX': { description: Received. } }
  programme.repayment_overdue:
    post:
      summary: A buyer's repayment to you is overdue
      description: |
        The repayment is unpaid after its due date (no repayment recorded by you), with `days_overdue`: the first
        morning after the due date. Once per repayment; the buyer's team is told in its app the same morning. data:
        ProgrammeMoneyEventData with days_overdue.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/ProgrammeMoneyEventData' } }
      responses: { '2XX': { description: Received. } }
  programme.repayment_recorded:
    post:
      summary: You recorded a buyer's repayment
      description: |
        You recorded the buyer's repayment of an early payment (the portal, POST /v1/early-payments/{id}/repayment or a
        line of your own bank statement you confirmed): `repayment.paid` says how much, the value date, your reference,
        the channel and the days after the due date. One event per repayment, once. data: ProgrammeMoneyEventData.
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/Event'
                - properties: { data: { $ref: '#/components/schemas/ProgrammeMoneyEventData' } }
      responses: { '2XX': { description: Received. } }
  webhook.test:
    post:
      summary: A test event you asked for (POST /v1/webhooks/{id}/test)
      parameters: [{ $ref: '#/components/parameters/SignatureHeader' }, { $ref: '#/components/parameters/EventIdHeader' }, { $ref: '#/components/parameters/EventTypeHeader' }]
      requestBody: { content: { application/json: { schema: { $ref: '#/components/schemas/Event' } } } }
      responses: { '2XX': { description: Received. } }

components:
  securitySchemes:
    funderKey:
      type: http
      scheme: bearer
      bearerFormat: adv_fk_<64 hex>
      description: A funder API key, issued by Advanta operations and shown once.

  parameters:
    RequestId:
      name: id
      in: path
      required: true
      schema: { type: string, format: uuid }
    WebhookId:
      name: id
      in: path
      required: true
      schema: { type: string, format: uuid }
    ExportId:
      name: id
      in: path
      required: true
      schema: { type: string, format: uuid }
    ClaimId:
      name: id
      in: path
      required: true
      description: The claim's id (claim_id in GET /v1/recourse).
      schema: { type: string, format: uuid }
    LinkLang:
      name: lang
      in: query
      description: The language of the page each link opens (pt, es, en, fr, de, it or nl), added to its url.
      schema: { type: string, enum: [pt, es, en, fr, de, it, nl] }
    SignatureHeader:
      name: Advanta-Signature
      in: header
      required: true
      description: |
        `t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC key is your endpoint secret
        (the whole `whsec_…` string, UTF-8); the message is `<t>.<raw request body>`. Accept the
        delivery if any `v1` matches (after a rotation there are two) and `t` is within 300
        seconds of your clock. Compare in constant time.
      schema: { type: string, example: 't=1790179835,v1=5f2b…' }
    EventIdHeader:
      name: Advanta-Event-Id
      in: header
      required: true
      description: The event id (also `id` in the body). Delivery is at least once; ignore an id you already processed.
      schema: { type: string, format: uuid }
    EventTypeHeader:
      name: Advanta-Event-Type
      in: header
      required: true
      schema: { $ref: '#/components/schemas/EventType' }

  responses:
    Unauthorized:
      description: "`unauthorized` (missing, malformed, unknown, revoked or inactive key) or `key_expired`."
      content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
    Forbidden:
      description: "`forbidden`: the key lacks the scope, or the funder is not active."
      content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
    NotFound:
      description: "`not_found`: no such resource visible to this key (or an unknown route)."
      content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
    MethodNotAllowed:
      description: "`method_not_allowed`."
      content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
    ServerError:
      description: "`internal`, `query_failed`, `write_failed`, `ingest_failed`: retry later."
      content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
    TooManyRequests:
      description: "`rate_limited`: more calls than the key's limit (120 a minute and 3,000 an hour unless Advanta set another), or repeated calls with an unknown key from one address. Send it again after `Retry-After` seconds."
      headers:
        Retry-After: { description: Seconds to wait before the next call., schema: { type: integer, minimum: 1 } }
      content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }

  schemas:
    Error:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code: { type: string }
            message: { type: string }
          additionalProperties: true
    DebtorNotEligibleError:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message, debtors]
          properties:
            code: { type: string, const: debtor_not_eligible_for_funder }
            message: { type: string }
            debtors:
              type: array
              items:
                type: object
                properties:
                  debtor_key: { type: string }
                  name: { type: [string, 'null'] }
                  country: { type: [string, 'null'] }
                  reason: { type: string, enum: [not_listed, refused, suspended, no_tax_id, invoice_missing, no_invoices] }
                  invoices: { type: integer }
    DocumentsMissingError:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message, documents]
          properties:
            code: { type: string, const: documents_missing_for_funder }
            message: { type: string }
            documents:
              type: array
              items:
                type: object
                properties:
                  code: { type: string }
                  name: { type: string }
                  reason: { type: string, enum: [missing, unverified, expired, rejected, no_validity_date, not_in_catalogue] }
                  valid_until: { type: [string, 'null'], format: date }
                  document_id: { type: [string, 'null'], format: uuid }
    DealDocumentItem:
      type: object
      properties:
        code: { type: string }
        names: { type: object, additionalProperties: { type: string } }
        sensitivity: { type: string, enum: [public_record, confidential, personal_data] }
        document_id: { type: [string, 'null'], format: uuid }
        file_name: { type: string }
        file_size: { type: [integer, 'null'] }
        sha256: { type: [string, 'null'], description: 'SHA-256 of the stored file, computed by Advanta' }
        issued_on: { type: [string, 'null'], format: date }
        valid_until: { type: [string, 'null'], format: date }
        status: { type: string }
        verified_at: { type: [string, 'null'], format: date-time }
        verification_note: { type: [string, 'null'] }
        valid_today: { type: boolean }
        current_document_id: { type: [string, 'null'], format: uuid }
        current_state: { type: string, enum: [valid, unverified, expired, rejected, no_validity_date, missing] }
        current_valid_until: { type: [string, 'null'], format: date }
        download_url: { type: [string, 'null'], format: uri }
        url_expires_in: { type: [integer, 'null'] }
    DealDocuments:
      type: object
      properties:
        request_id: { type: string, format: uuid }
        seller_country: { type: string }
        today: { type: string, format: date }
        required_now: { type: array, items: { type: string } }
        snapshots:
          type: array
          items:
            type: object
            properties:
              id: { type: string, format: uuid }
              event: { type: string, enum: [routed, funded] }
              taken_at: { type: string, format: date-time }
              on_date: { type: string, format: date }
              seller_country: { type: string }
              required_codes: { type: array, items: { type: string } }
              evidence_seq: { type: [integer, 'null'] }
              items: { type: array, items: { $ref: '#/components/schemas/DealDocumentItem' } }
        current:
          type: array
          items:
            type: object
            properties:
              code: { type: string }
              names: { type: object, additionalProperties: { type: string } }
              required_now: { type: boolean }
              document_id: { type: [string, 'null'], format: uuid }
              state: { type: string, enum: [valid, unverified, expired, rejected, no_validity_date, missing] }
              issued_on: { type: [string, 'null'], format: date }
              valid_until: { type: [string, 'null'], format: date }
              sha256: { type: [string, 'null'] }
              file_name: { type: [string, 'null'] }
              download_url: { type: [string, 'null'], format: uri }
              url_expires_in: { type: [integer, 'null'] }
    RequiredDocuments:
      type: object
      properties:
        funder: { $ref: '#/components/schemas/FunderRef' }
        required:
          type: object
          description: 'Seller country to the codes you require, for example {"PT": ["cert_hacienda", "cirbe"]}.'
          additionalProperties: { type: array, items: { type: string } }
        catalogue:
          type: array
          items:
            type: object
            properties:
              country: { type: string }
              code: { type: string }
              names: { type: object, additionalProperties: { type: string } }
              issuer: { type: string }
              validity_rule: { type: string, enum: [months_from_issue, annual_deadline] }
              validity_months: { type: [integer, 'null'] }
              validity_deadline: { type: [string, 'null'], description: 'MM-DD of the yearly filing' }
              validity_printed: { type: boolean }
              validity_basis: { type: string }
              sensitivity: { type: string, enum: [public_record, confidential, personal_data] }
    ConsentLevel:
      type: string
      enum: [receipt, acknowledgment, acceptance]
      description: What a debtor signs. receipt < acknowledgment < acceptance.
    DebtorConsent:
      type: object
      description: One debtor of the request, the level required and the level it signed.
      properties:
        debtor_name: { type: [string, 'null'] }
        debtor_tax_id: { type: [string, 'null'] }
        status: { type: string, description: 'The notice status (pending, sent, acknowledged, rejected, bounced, resent).' }
        acknowledged_at: { type: [string, 'null'], format: date-time }
        level_required: { oneOf: [{ $ref: '#/components/schemas/ConsentLevel' }, { type: 'null' }] }
        level_achieved: { oneOf: [{ $ref: '#/components/schemas/ConsentLevel' }, { type: 'null' }] }
        meets_requirement: { type: boolean }
        channel: { type: [string, 'null'], description: online or offline. }
        text_version: { type: [string, 'null'] }
        text_review_status: { type: [string, 'null'], description: Whether counsel approved the declaration text signed. }
        signer_name: { type: [string, 'null'] }
        signer_role: { type: [string, 'null'] }
    Settings:
      type: object
      properties:
        funder: { $ref: '#/components/schemas/FunderRef' }
        debtor_consent_level: { $ref: '#/components/schemas/ConsentLevel' }
        require_counsel_approved_texts: { type: boolean }
        open_requests_by_level: { type: object, additionalProperties: { type: integer } }
        levels: { type: array, items: { $ref: '#/components/schemas/ConsentLevel' } }
        levels_by_law:
          type: object
          description: Per governing law, the levels with a declaration text and the languages of each.
          additionalProperties: { type: object, additionalProperties: { type: array, items: { type: string } } }
        texts_counsel_approved: { type: array, items: { type: string } }
    FunderRef:
      type: object
      required: [bank_id, name]
      properties:
        bank_id: { type: string, format: uuid }
        name: { type: string }
    Me:
      type: object
      required: [api_version, environment, funder, key]
      properties:
        api_version: { type: string }
        environment: { type: string, enum: [live, sandbox, unclassified] }
        funder: { $ref: '#/components/schemas/FunderRef' }
        key:
          type: object
          required: [id, name, prefix, scopes, created_at, expires_at, prospect]
          properties:
            id: { type: string, format: uuid }
            name: { type: string }
            prefix: { type: string, description: The first 12 characters of the key. }
            scopes: { type: array, items: { type: string } }
            created_at: { type: string, format: date-time }
            expires_at: { type: [string, 'null'], format: date-time }
            prospect: { type: [string, 'null'], description: Who a sandbox key was issued to. }
    Request:
      type: object
      properties:
        id: { type: string, format: uuid }
        request_ref: { type: string }
        type: { type: string, description: factoring or confirming. }
        status: { type: string, enum: [pending, under_review, terms_sent, approved, funded, rejected, settled] }
        total_amount: { type: number }
        advance_amount: { type: [number, 'null'] }
        fee_percentage: { type: [number, 'null'] }
        company_name: { type: [string, 'null'], description: The seller. }
        company_nif: { type: [string, 'null'], description: "The seller's tax number." }
        health_score: { type: [integer, 'null'] }
        invoice_count: { type: [integer, 'null'] }
        notes: { type: [string, 'null'] }
        proposed_rate: { type: [number, 'null'] }
        proposed_advance_pct: { type: [number, 'null'] }
        proposed_days: { type: [integer, 'null'] }
        proposed_at: { type: [string, 'null'], format: date-time }
        assigned_bank_id: { type: [string, 'null'], format: uuid }
        bank_partner: { type: [string, 'null'] }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        funded_at: { type: [string, 'null'], format: date-time }
        consent_level_required:
          description: What every debtor must sign before this request can be funded, set when it was routed.
          oneOf: [{ $ref: '#/components/schemas/ConsentLevel' }, { type: 'null' }]
        disclosure:
          type: [string, 'null']
          enum: [announced, confidential, null]
          description: The notice terms the request was routed with (see ProgrammeTerms); null for a confirming request or one not routed.
        recourse:
          type: [string, 'null']
          enum: [with, without, null]
          description: The recourse terms the request was routed with; null for a factoring request routed before 28 September 2026 (not recorded) or a confirming one.
        recourse_days: { type: [integer, 'null'], description: 'Days after an invoice''s due date before a recourse claim or a debtor default opens; null: none.' }
        announced_at: { type: [string, 'null'], format: date-time, description: When a confidential request was announced. }
        announced_trigger: { type: [string, 'null'], enum: [manual, overdue, dispute, kyc_lapsed, null] }
    OfferSummary:
      type: object
      properties:
        funding_request_id: { type: string, format: uuid }
        rate: { type: number }
        advance_pct: { type: number }
        days: { type: [integer, 'null'] }
        status: { type: string, enum: [pending, accepted, rejected, expired] }
        submitted_at: { type: [string, 'null'], format: date-time }
        accepted_at: { type: [string, 'null'], format: date-time }
    Offer:
      type: object
      properties:
        id: { type: string, format: uuid }
        rate: { type: number }
        advance_pct: { type: number }
        days: { type: [integer, 'null'] }
        notes: { type: [string, 'null'] }
        status: { type: string, enum: [pending, accepted, rejected, expired] }
        submitted_at: { type: [string, 'null'], format: date-time }
        expires_at: { type: [string, 'null'], format: date-time }
        accepted_at: { type: [string, 'null'], format: date-time }
    Receivable:
      type: object
      properties:
        invoice_no: { type: string }
        invoice_amount: { type: number }
        invoice_date: { type: [string, 'null'], format: date }
        invoice_due_date: { type: [string, 'null'], format: date }
        customer_name: { type: [string, 'null'], description: The debtor. }
        supplier_name: { type: [string, 'null'] }
        supplier_nif: { type: [string, 'null'] }
    Score:
      type: object
      properties:
        score: { type: number, description: 300 to 850. }
        grade: { type: string, description: A to E. }
        dimensions: { type: object, additionalProperties: { type: number } }
        computed_at: { type: string, format: date-time }
    RequestRisk:
      type: object
      description: |
        Fraud signals and disputes on one request. A `hard` signal (for example the same invoice
        financed elsewhere, an amount changed while in a request, a credit note against it, an
        open dispute) stops routing and funding until Advanta's operations team reviews it; the
        others only flag. `shared` carries the figures that explain the signal (for example the
        ratio to the seller's usual amount); the internal detail stays with Advanta.
      required: [signals, disputes]
      properties:
        signals:
          type: array
          items:
            type: object
            required: [id, code, severity, status]
            properties:
              id: { type: string, format: uuid }
              code: { type: string, description: 'Stable signal code, for example double_financing_detected, amount_above_history, round_amount_cluster.' }
              severity: { type: string, enum: [hard, high, medium, low] }
              status: { type: string, enum: [open, confirmed] }
              invoice_id: { type: string, format: uuid }
              invoice_number: { type: string }
              shared: { type: object, additionalProperties: true }
              first_seen_at: { type: string, format: date-time }
              last_seen_at: { type: string, format: date-time }
              reviewed_at: { type: string, format: date-time }
        disputes:
          type: array
          items:
            type: object
            required: [id, status]
            properties:
              id: { type: string, format: uuid }
              status: { type: string }
              reason: { type: string }
              description: { type: string }
              amount_disputed: { type: number }
              invoices: { type: array, items: { type: string } }
              debtor_nif: { type: string }
              debtor_name: { type: string }
              channel: { type: string, description: 'How the dispute arrived, for example the notice page, a letter or an e-mail.' }
              reported_by: { type: string }
              received_on: { type: string, format: date }
              recorded_at: { type: string, format: date-time }
              request_status: { type: string, description: 'Status of the request when the dispute was recorded.' }
              resolution_note: { type: string }
              resolved_at: { type: string, format: date-time }
              evidence_seq: { type: integer, description: 'Position of the dispute on the hash-chained evidence log.' }
              funder_notified_at: { type: string, format: date-time }
              document_sha256: { type: string, description: 'SHA-256 of the letter or e-mail the dispute was recorded from, when there is one.' }
    OfferDecision:
      type: object
      required: [decision, rate, advance_pct]
      properties:
        decision: { type: string, const: offer }
        rate: { type: number, exclusiveMinimum: 0, maximum: 100, description: Percent. }
        advance_pct: { type: number, exclusiveMinimum: 0, maximum: 100 }
        days: { type: integer }
        notes: { type: string }
        valid_days: { type: integer, minimum: 1, maximum: 90 }
    DeclineDecision:
      type: object
      required: [decision]
      properties:
        decision: { type: string, const: decline }
        reason: { type: string, description: 'payer_credit, invoice_ineligible, documentation, concentration, amount_out_of_range, sector_excluded, no_funder_capacity, withdrawn_by_client, other, or free text. `reason` or `notes` is required.' }
        notes: { type: string, description: 'The message the seller reads with the decline, shown as written. At least 10 characters when you step back from a request the seller accepted (status approved).' }
        internal_note: { type: string, maxLength: 4000, description: 'Your own note on the decline. Kept for your team (and Advanta operations); the seller never sees it.' }
    FundDecision:
      type: object
      required: [decision, value_date, reference]
      properties:
        decision: { type: string, const: fund }
        value_date: { type: string, format: date, description: 'The value date of your transfer to the seller, at most 7 days from today and not before the request.' }
        reference: { type: string, minLength: 3, maxLength: 140, description: 'The reference of your transfer to the seller.' }
        amount: { type: number, exclusiveMinimum: 0, description: 'Optional: the amount you transferred. Refused with 409 funding_amount_mismatch unless it is the accepted advance, to the cent.' }
    SettleDecision:
      type: object
      required: [decision, amount]
      properties:
        decision: { type: string, const: settle }
        amount: { type: number, exclusiveMinimum: 0 }
        received_at: { type: string, format: date-time, description: Defaults to now; at most one day ahead. }
        reference: { type: string, maxLength: 140 }
        note: { type: string, maxLength: 1000 }
        final: { type: boolean, description: True closes the request whatever the total. }
    OfferResult:
      type: object
      properties:
        decision: { type: string, const: offer }
        request_id: { type: string, format: uuid }
        offer_id: { type: string, format: uuid }
        expires_at: { type: [string, 'null'], format: date-time }
        status: { type: string }
    DeclineResult:
      type: object
      properties:
        decision: { type: string, const: decline }
        request_id: { type: string, format: uuid }
        status: { type: string }
        step_back: { type: boolean, description: 'True when the seller had accepted your offer: you stepped back from the deal before funding.' }
    FundResult:
      type: object
      properties:
        decision: { type: string, const: fund }
        request_id: { type: string, format: uuid }
        status: { type: string, const: funded }
        funded_at: { type: string, format: date-time }
        value_date: { type: string, format: date }
        reference: { type: string }
    SettleResult:
      type: object
      properties:
        decision: { type: string, const: settle }
        request_id: { type: string, format: uuid }
        settlement_id: { type: string, format: uuid }
        status: { type: string }
        received_total: { type: number }
        request_total: { type: number }
        outstanding: { type: number }
    DebtorExposure:
      type: object
      properties:
        debtor_key: { type: string }
        debtor_name: { type: [string, 'null'] }
        debtor_country: { type: [string, 'null'] }
        limit_status: { type: [string, 'null'] }
        limit_amount: { type: [number, 'null'] }
        outstanding: { type: number }
        committed: { type: number }
        offered: { type: number }
        available: { type: [number, 'null'] }
        overdue_count: { type: integer }
        oldest_overdue: { type: [string, 'null'], format: date }
        frozen: { type: boolean }
        decided_at: { type: [string, 'null'], format: date-time }
        note: { type: [string, 'null'] }
        seller_marked_paid:
          type: array
          items: { $ref: '#/components/schemas/SellerMarkedPaid' }
    SellerMarkedPaid:
      type: object
      description: A financed invoice the seller's invoicing software marks paid while you have not received all of it.
      properties:
        request_id: { type: string, format: uuid }
        request_ref: { type: string }
        invoice_id: { type: [string, 'null'], format: uuid }
        invoice_number: { type: [string, 'null'] }
        seller_name: { type: [string, 'null'] }
        debtor_name: { type: [string, 'null'] }
        due_date: { type: [string, 'null'], format: date }
        seller_paid_on: { type: [string, 'null'], format: date, description: The payment date the seller's software recorded. }
        amount: { type: number }
        received: { type: number, description: Your recorded payments on the operation, in proportion to its invoices. }
        outstanding: { type: number }
    SellerExposure:
      type: object
      properties:
        seller_id: { type: string, format: uuid }
        seller_name: { type: [string, 'null'] }
        seller_nif: { type: [string, 'null'] }
        seller_country: { type: [string, 'null'] }
        limit_status: { type: [string, 'null'] }
        limit_amount: { type: [number, 'null'] }
        outstanding: { type: number }
        committed: { type: number }
        offered: { type: number }
        available: { type: [number, 'null'] }
        overdue_count: { type: integer }
        oldest_overdue: { type: [string, 'null'], format: date }
        frozen: { type: boolean }
        decided_at: { type: [string, 'null'], format: date-time }
        note: { type: [string, 'null'] }
        seller_marked_paid:
          type: array
          items: { $ref: '#/components/schemas/SellerMarkedPaid' }
    DebtorLimit:
      type: object
      properties:
        id: { type: string, format: uuid }
        bank_id: { type: string, format: uuid }
        debtor_key: { type: string }
        debtor_country: { type: [string, 'null'] }
        debtor_name: { type: [string, 'null'] }
        amount: { type: [number, 'null'] }
        status: { type: string, enum: [active, refused, suspended] }
        note: { type: [string, 'null'] }
        decided_by: { type: [string, 'null'], format: uuid }
        decided_at: { type: string, format: date-time }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    SellerLimit:
      type: object
      properties:
        id: { type: string, format: uuid }
        bank_id: { type: string, format: uuid }
        seller_id: { type: string, format: uuid }
        amount: { type: [number, 'null'] }
        status: { type: string, enum: [active, refused, suspended] }
        note: { type: [string, 'null'] }
        decided_by: { type: [string, 'null'], format: uuid }
        decided_at: { type: string, format: date-time }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    PayerRecord:
      type: object
      properties:
        debtor_key: { type: string }
        debtor_country: { type: [string, 'null'] }
        status: { type: string }
        reason: { type: [string, 'null'] }
        min_observers: { type: integer }
        observers: { type: [integer, 'null'] }
        settled_observers: { type: [integer, 'null'] }
        invoice_count: { type: [integer, 'null'] }
        due_date_known_count: { type: [integer, 'null'] }
        settled_sample: { type: [integer, 'null'] }
        delay_sample: { type: [integer, 'null'] }
        avg_settle_delay_days: { type: [number, 'null'] }
        median_settle_delay_days: { type: [number, 'null'] }
        p75_settle_delay_days: { type: [number, 'null'] }
        worst_settle_delay_days: { type: [integer, 'null'] }
        on_time_pct: { type: [number, 'null'] }
        avg_days_to_pay: { type: [number, 'null'] }
        median_days_to_pay: { type: [number, 'null'] }
        open_count: { type: [integer, 'null'] }
        open_overdue_count: { type: [integer, 'null'] }
        avg_overdue_days: { type: [number, 'null'] }
        worst_overdue_days: { type: [integer, 'null'] }
        oldest_open_days: { type: [integer, 'null'] }
        window_from: { type: [string, 'null'], format: date }
        refreshed_at: { type: [string, 'null'], format: date-time }
        plane: { type: string, enum: [live, sandbox] }
    StatementResult:
      type: object
      properties:
        funder: { $ref: '#/components/schemas/FunderRef' }
        file_sha256: { type: string }
        source: { type: string }
        statement_id: { type: [string, 'null'] }
        account_iban_last4: { type: [string, 'null'] }
        parse_errors: { type: array, items: { type: string } }
        import_id: { type: string, format: uuid }
        bank_id: { type: string, format: uuid }
        lines: { type: integer }
        credits: { type: integer }
        duplicates: { type: integer }
        account_matches: { type: [boolean, 'null'] }
        proposed: { type: integer }
        suggested: { type: integer }
        unmatched: { type: integer }
        ignored: { type: integer }
    OnboardingLink:
      type: object
      properties:
        id: { type: string, format: uuid }
        status: { type: string, enum: [pending, account_created, completed, expired, revoked] }
        company_name: { type: string }
        company_tax_id: { type: string }
        country: { type: string }
        contact_name: { type: [string, 'null'] }
        locale: { type: string }
        return_url: { type: string }
        metadata: { type: object }
        created_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
        account_created_at: { type: [string, 'null'], format: date-time }
        completed_at: { type: [string, 'null'], format: date-time }
        seller_id: { type: [string, 'null'], format: uuid, description: Once completed; the id GET /v1/seller-limits uses. }
        prescriber_id: { type: [string, 'null'], format: uuid, description: The prescriber of yours the company is attributed to (its first origin with you), if any. }
    LinkLang:
      type: [string, 'null']
      enum: [pt, es, en, fr, de, it, nl, null]
      description: The language of the page the link opens (added to its url as `&lang=`). Without it, the page picks one.
    ClientLink:
      type: object
      properties:
        id: { type: string, format: uuid }
        prescriber_id: { type: [string, 'null'], format: uuid, description: Null for your own link. }
        prescriber_name: { type: [string, 'null'], description: In GET /v1/client-links. }
        state: { type: string, enum: [active, disabled, expired], description: A link of an inactive funder or of a disabled prescriber is disabled. }
        url: { type: [string, 'null'], format: uri, description: "https://app.advanta.capital/join?link=<token>[&lang=xx], while the link works." }
        created_at: { type: string, format: date-time }
        expires_at: { type: [string, 'null'], format: date-time }
        disabled_at: { type: [string, 'null'], format: date-time }
        disabled_reason: { type: [string, 'null'] }
        replaced_by: { type: [string, 'null'], format: uuid }
        arrivals: { type: integer, description: Companies whose first arrival to you was through this link. }
        claims_last_day: { type: integer, description: Sign-ups through this link in the last 24 hours (20 an hour and 100 a day at most). }
    Prescriber:
      type: object
      properties:
        id: { type: string, format: uuid }
        name: { type: string }
        email: { type: [string, 'null'] }
        notes: { type: [string, 'null'] }
        active: { type: boolean }
        created_at: { type: string, format: date-time }
        disabled_at: { type: [string, 'null'], format: date-time }
        link:
          oneOf:
            - $ref: '#/components/schemas/ClientLink'
            - type: 'null'
    ClientInvitation:
      type: object
      properties:
        id: { type: string, format: uuid }
        state: { type: string, description: 'pending, accepted, revoked or expired.' }
        company_name: { type: string }
        company_tax_id: { type: string }
        country: { type: string }
        contact_email: { type: string }
        contact_name: { type: [string, 'null'] }
        locale: { type: [string, 'null'] }
        created_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
        accepted_at: { type: [string, 'null'], format: date-time }
        revoked_at: { type: [string, 'null'], format: date-time }
        email_sent_at: { type: [string, 'null'], format: date-time }
        send_count: { type: [integer, 'null'] }
        via: { type: string, enum: [link, named, api] }
        prescriber_id: { type: [string, 'null'], format: uuid, description: The prescriber who brought the company, through its link or named on an invitation by name or through the API. }
        prescriber_name: { type: [string, 'null'] }
    ReportCompany:
      type: object
      properties:
        company_name: { type: string }
        company_tax_id: { type: string }
        country: { type: string }
        arrived_at: { type: string, format: date-time }
        joined_at: { type: [string, 'null'], format: date-time, description: When its account was opened (the invitation accepted). }
        onboarded_at: { type: [string, 'null'], format: date-time, description: When its company verification was approved. }
        requests: { type: integer }
        amount_requested: { type: number }
        amount_funded: { type: number }
    ReportGroup:
      type: object
      properties:
        kind: { type: string, enum: [own_link, prescriber, named, api] }
        prescriber_id: { type: [string, 'null'], format: uuid }
        name: { type: [string, 'null'] }
        active: { type: [boolean, 'null'] }
        since: { type: [string, 'null'], format: date-time }
        arrived: { type: integer }
        joined: { type: integer }
        onboarded: { type: integer }
        requests: { type: integer }
        amount_requested: { type: number }
        amount_funded: { type: number }
        companies: { type: array, items: { $ref: '#/components/schemas/ReportCompany' } }
    EventType:
      type: string
      enum: [request.routed, request.unrouted, offer.accepted, notice.acknowledged, notice.disputed, request.funded, settlement.recorded, seller.documents_expiring, dispute.opened, dispute.resolved, onboarding.completed, client.joined, export.ready, request.announced, recourse.opened, recourse.settled, payment.reached_seller, opportunities.daily, debtor.watch_blocked, payout.instruction, registry.conflict, pre_offer.accepted, programme.early_payment_confirmed, programme.repayment_due_soon, programme.repayment_overdue, programme.repayment_recorded, webhook.test]
    WebhookEndpoint:
      type: object
      properties:
        id: { type: string, format: uuid }
        url: { type: string }
        description: { type: [string, 'null'] }
        events: { type: array, items: { type: string } }
        active: { type: boolean }
        secret_prefix: { type: string, description: The first 12 characters of the secret. }
        created_at: { type: string, format: date-time }
        created_via: { type: string, enum: [api, portal, ops] }
        rotated_at: { type: [string, 'null'], format: date-time }
        previous_secret_expires_at: { type: [string, 'null'], format: date-time }
        disabled_at: { type: [string, 'null'], format: date-time }
        last_attempt_at: { type: [string, 'null'], format: date-time }
        last_success_at: { type: [string, 'null'], format: date-time }
        last_failure_at: { type: [string, 'null'], format: date-time }
        last_status: { type: [integer, 'null'] }
        pending_deliveries: { type: integer }
        failed_deliveries_7d: { type: integer }
    Delivery:
      type: object
      properties:
        id: { type: string, format: uuid }
        event_id: { type: string, format: uuid }
        event_type: { $ref: '#/components/schemas/EventType' }
        payload_sha256: { type: string, description: SHA-256 of the exact body sent. }
        status: { type: string, enum: [pending, delivered, failed, cancelled] }
        attempts: { type: integer }
        next_attempt_at: { type: [string, 'null'], format: date-time }
        last_attempt_at: { type: [string, 'null'], format: date-time }
        delivered_at: { type: [string, 'null'], format: date-time }
        response_code: { type: [integer, 'null'] }
        last_error: { type: [string, 'null'], description: 'http_<code>, timeout, network_error, redirect_not_followed, …' }
        created_at: { type: string, format: date-time }
    Event:
      type: object
      description: |
        The body of every delivery, sent byte for byte as stored (its SHA-256 is in the
        delivery log). A delivery that fails (any answer but 2xx, no answer within 10 seconds, a
        redirect) is tried again after 1, 2, 4, 8 … minutes, doubling, at most 6 hours apart,
        with a last try 24 hours after the event; then it is marked failed.
      required: [id, object, type, api_version, created, environment, data]
      properties:
        id: { type: string, format: uuid }
        object: { type: string, const: event }
        type: { $ref: '#/components/schemas/EventType' }
        api_version: { type: string }
        created: { type: integer, description: Unix seconds. }
        environment: { type: string, enum: [live, sandbox, unclassified] }
        data: { type: object }
      example:
        id: 9b2f7f64-5a1c-4a57-9d8a-0f2e3c4b5a69
        object: event
        type: request.funded
        api_version: '2026-09-23'
        created: 1790179835
        environment: sandbox
        data: { request_id: 4c1e0d2a-8f3b-4f6e-9a55-3c2b1d0e9f87, request_ref: FR-2026-0042, type: factoring, status: funded, total_amount: 18450.00, currency: EUR, funded_at: '2026-09-23T18:10:35Z', advance_amount: 16605.00 }
    RequestEventData:
      type: object
      properties:
        request_id: { type: string, format: uuid }
        request_ref: { type: string }
        type: { type: string }
        status: { type: string }
        total_amount: { type: number }
        currency: { type: string, const: EUR }
        routed_at: { type: string, format: date-time }
    NoticeEventData:
      type: object
      properties:
        notice_id: { type: string, format: uuid }
        request_id: { type: string, format: uuid }
        request_ref: { type: string }
        debtor_name: { type: [string, 'null'] }
        debtor_tax_id: { type: [string, 'null'] }
        invoice_count: { type: integer }
        total_amount: { type: [number, 'null'] }
        channel: { type: string, enum: [online, offline] }
        decided_at: { type: string, format: date-time }
        reason: { type: [string, 'null'], description: notice.disputed only. }
    ClientJoinedEventData:
      type: object
      required: [seller_id, invitation_id, company_name, company_tax_id, country, origin, channel, joined_at]
      properties:
        seller_id: { type: string, format: uuid, description: The seller's tenant id at Advanta (the id GET /v1/seller-limits uses). }
        invitation_id: { type: string, format: uuid, description: The invitation it accepted (for an API onboarding link, the link id). }
        company_name: { type: string, description: As you invited it. }
        company_tax_id: { type: string, description: As you invited it, normalised. }
        country: { type: string }
        origin: { type: string, enum: [named, open_link, prescriber, api], description: How the company first reached you. }
        channel: { type: string, enum: [named, link, api], description: 'The way in: an invitation by name, an open link (yours or a prescriber''s), the API.' }
        link_id: { type: [string, 'null'], format: uuid, description: The open link, when it came through one. }
        prescriber_id: { type: [string, 'null'], format: uuid }
        prescriber_name: { type: [string, 'null'] }
        arrived_at: { type: string, format: date-time, description: When it first reached you. }
        joined_at: { type: string, format: date-time, description: When it accepted the invitation. }
        mode: { type: string, enum: [exclusive], description: 'Your place as its home funder: exclusive, its requests go only to you.' }
      example:
        seller_id: 7d0c6c52-3f7b-4a55-9c1e-2b8f7a61d0e4
        invitation_id: 0b4f7c1e-9a2d-4e8b-8f3a-5c6d7e8f9a0b
        company_name: Fornecedor Exemplo Lda
        company_tax_id: '512640017'
        country: PT
        origin: prescriber
        channel: link
        link_id: 5e1d2c3b-4a59-4687-9a8b-7c6d5e4f3a2b
        prescriber_id: 1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d
        prescriber_name: Gestoría Norte
        arrived_at: '2026-09-26T09:12:00Z'
        joined_at: '2026-09-26T10:40:00Z'
        mode: exclusive
    Export:
      type: object
      properties:
        id: { type: string, format: uuid }
        subject: { type: string, enum: [funder] }
        status: { type: string, enum: [queued, running, ready, failed] }
        plane: { type: string, enum: [live, sandbox] }
        requested_via: { type: string, enum: [portal, api] }
        actor_role: { type: string, description: 'admin (the portal) or api:<key name>.' }
        requested_by: { type: [string, 'null'], format: uuid, description: The login that asked, for a portal export. }
        requested_by_email: { type: [string, 'null'] }
        lang: { type: string, enum: [pt, es, en, fr, de, it, nl] }
        created_at: { type: string, format: date-time }
        started_at: { type: [string, 'null'], format: date-time }
        completed_at: { type: [string, 'null'], format: date-time }
        expires_at: { type: [string, 'null'], format: date-time, description: Until when its files can be downloaded (24 hours after it was ready). }
        download_available: { type: boolean }
        manifest_sha256: { type: [string, 'null'], description: SHA-256 of the manifest's canonical form (keys sorted, no spaces, without this field); also on the evidence chain (export.ready). }
        size_bytes: { type: [integer, 'null'] }
        file_count: { type: [integer, 'null'] }
        row_counts: { type: [object, 'null'], additionalProperties: { type: integer }, description: Rows per entity. }
        documents_mode: { type: [string, 'null'], enum: [files, links, none, null] }
        volumes: { type: array, items: { type: object, properties: { name: { type: string }, bytes: { type: integer }, sha256: { type: string } } } }
        error: { type: [string, 'null'] }
        purged_at: { type: [string, 'null'], format: date-time, description: When its files were deleted. }
        progress:
          type: [object, 'null']
          description: While it is queued or running.
          properties:
            entities_done: { type: integer }
            entities_total: { type: integer }
            rows: { type: integer }
            volumes_written: { type: integer }
            phase: { type: string, enum: [data, documents, final] }
      example:
        id: 5e1f0a2b-3c4d-4e5f-8a9b-0c1d2e3f4a5b
        subject: funder
        status: ready
        plane: live
        requested_via: api
        actor_role: 'api:treasury'
        lang: es
        created_at: '2026-09-27T09:00:02.114000Z'
        completed_at: '2026-09-27T09:00:41.502000Z'
        expires_at: '2026-09-28T09:00:41.502000Z'
        download_available: true
        manifest_sha256: 1c822b8797ba58903eca0689cc0c93138e7d396e01a038d133b5c1f3aeec7497
        size_bytes: 482113
        file_count: 101
        documents_mode: files
        volumes: [{ name: advanta-export-2026-09-27-5e1f0a2b-v001.zip, bytes: 482113, sha256: 9b0e5c1d2a7f4e6b8c3d1a0f9e8d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a291807 }]
    ExportFile:
      type: object
      properties:
        name: { type: string, description: The volume's file name. }
        bytes: { type: integer }
        sha256: { type: string }
        url: { type: [string, 'null'], description: A signed link to the volume. }
        url_expires_at: { type: string, format: date-time }
    ExportDocument:
      type: object
      properties:
        document_key: { type: string, description: The document's key at Advanta (bucket and path); the cursor. }
        kind: { type: string, enum: [invoice, kyc, notice, seller_document] }
        request_id: { type: [string, 'null'], format: uuid }
        notice_id: { type: [string, 'null'], format: uuid }
        invoice_id: { type: [string, 'null'], format: uuid }
        seller_id: { type: [string, 'null'], format: uuid }
        document_id: { type: [string, 'null'], format: uuid }
        file_name: { type: string }
        bytes: { type: [integer, 'null'] }
        mime_type: { type: [string, 'null'] }
        sha256: { type: [string, 'null'], description: As Advanta recorded it, when it did. }
        uploaded_at: { type: [string, 'null'], format: date-time }
        download_url: { type: [string, 'null'], description: Valid for 15 minutes. }
        download_expires_at: { type: [string, 'null'], format: date-time }
    ExportReadyEventData:
      type: object
      properties:
        export_id: { type: string, format: uuid }
        status: { type: string, enum: [ready] }
        requested_via: { type: string, enum: [portal, api] }
        manifest_sha256: { type: string }
        size_bytes: { type: integer }
        file_count: { type: integer }
        documents_mode: { type: string, enum: [files, links, none] }
        volumes: { type: array, items: { type: object, properties: { name: { type: string }, bytes: { type: integer }, sha256: { type: string } } } }
        completed_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
    SettlementEventData:
      type: object
      properties:
        settlement_id: { type: string, format: uuid }
        request_id: { type: string, format: uuid }
        request_ref: { type: string }
        amount: { type: number }
        received_at: { type: string, format: date-time }
        reference: { type: [string, 'null'] }
        received_total: { type: number }
        request_total: { type: number }
        outstanding: { type: number }
        final: { type: boolean }
        request_status: { type: string }
    ProgrammeTerms:
      type: object
      description: |
        The terms of a programme (you and one seller), for factoring requests.

        `disclosure`: `announced` (the default): each debtor is notified of the assignment and
        acknowledges it before the request can be funded. `confidential`: when the request is
        routed to you, the notice of assignment to each debtor is prepared, fingerprinted (SHA-256)
        and stored ready to send, and funding does not wait for the debtor's acknowledgment.
        Instead, before funding, every blocking invoice check must pass, the invoices must have been
        read from the seller's own books (ERP, e-invoice or SAF-T, not typed in or uploaded as a
        file), every debtor must have a current prepared notice naming you and an address to send
        it to, and the seller's verification must be approved. The prepared notices are sent when
        you announce the request (`POST /v1/requests/{id}/announce`, or the portal), and
        automatically, on a funded request, when a trigger you turned on is met. Once a notice has
        been sent the request stays announced.

        `recourse`: `with` (the default) or `without`. `recourse_days`: days after an invoice's due
        date before a funded request not yet settled opens a recourse claim against the seller
        (with recourse) or flags a debtor default to you (without recourse); null: nothing
        automatic.
        See `GET /v1/recourse`.

        The automatic announcement of a confidential request, once funded:
        `announce_overdue_days` (the request is not settled this many days after a financed
        invoice's due date; null: off), `announce_on_dispute` (a dispute reported on the request),
        `announce_on_kyc_lapse`
        (the seller's verification lapsed, or a screening alert is open).

        `bank_data`: `off` (the default); `requested`: the seller is asked to connect its business
        bank account for you, read-only and with its consent, so you see its cash flow on the
        request; `required`: in addition, funding waits until the account you pay into is confirmed
        as the seller's own through that connection. The account-information provider's charges
        for the accounts connected for you are recorded against you (`GET /v1/bank-data`).
      properties:
        disclosure: { type: string, enum: [announced, confidential] }
        recourse: { type: string, enum: [with, without] }
        recourse_days: { type: [integer, 'null'], minimum: 1, maximum: 365 }
        announce_overdue_days: { type: [integer, 'null'], minimum: 1, maximum: 365 }
        announce_on_dispute: { type: boolean }
        announce_on_kyc_lapse: { type: boolean }
        bank_data: { type: string, enum: ['off', requested, required] }
        source: { type: string, enum: [builtin, funder_default, seller], description: "Where the terms come from: Advanta's defaults (you set none), your default, or the company's own terms." }
        updated_at: { type: [string, 'null'], format: date-time }
    ProgrammeTermsChange:
      type: object
      description: 'The terms to change; the keys you leave out keep their value. `{"reset": true}` alone, with a `seller_id`, removes that company''s own terms.'
      minProperties: 1
      additionalProperties: false
      properties:
        disclosure: { type: string, enum: [announced, confidential] }
        recourse: { type: string, enum: [with, without] }
        recourse_days: { type: [integer, 'null'], minimum: 1, maximum: 365 }
        announce_overdue_days: { type: [integer, 'null'], minimum: 1, maximum: 365 }
        announce_on_dispute: { type: boolean }
        announce_on_kyc_lapse: { type: boolean }
        bank_data: { type: string, enum: ['off', requested, required] }
        reset: { type: boolean, const: true }
    ProgrammeCompany:
      type: object
      properties:
        seller_id: { type: string, format: uuid }
        company_name: { type: [string, 'null'] }
        tax_id: { type: [string, 'null'] }
    Programme:
      type: object
      properties:
        funder: { $ref: '#/components/schemas/FunderRef' }
        bank_id: { type: string, format: uuid }
        default: { $ref: '#/components/schemas/ProgrammeTerms' }
        companies:
          type: array
          description: The companies with terms of their own.
          items:
            allOf:
              - $ref: '#/components/schemas/ProgrammeCompany'
              - type: object
                properties:
                  terms: { $ref: '#/components/schemas/ProgrammeTerms' }
                  reason: { type: [string, 'null'] }
                  updated_at: { type: string, format: date-time }
        sellers:
          type: array
          description: The companies you can set terms for.
          items: { $ref: '#/components/schemas/ProgrammeCompany' }
        requests:
          type: object
          description: 'Your factoring requests counted by the terms they carry, keyed `<disclosure>:<recourse>:<open | funded | settled>` (for example `confidential:with:open`); `not_set` for a term not recorded (routed before 28 September 2026).'
          additionalProperties: { type: integer }
    ProgrammeChange:
      type: object
      properties:
        funder: { $ref: '#/components/schemas/FunderRef' }
        bank_id: { type: string, format: uuid }
        seller_id: { type: [string, 'null'], format: uuid }
        terms: { $ref: '#/components/schemas/ProgrammeTerms' }
        changed: { type: boolean }
        open_requests_keep_their_terms: { type: integer, description: Your open factoring requests (for this company, or all) that keep the terms they were routed with. }
    AnnounceResult:
      type: object
      properties:
        request_id: { type: string, format: uuid }
        disclosure: { type: string, const: announced }
        trigger: { type: string, const: manual }
        notices: { type: integer, description: The request's notices of assignment. }
        sending_queued: { type: boolean, description: The prepared notices were queued for sending. }
    NoticeDocument:
      type: object
      properties:
        document_id: { type: string, format: uuid }
        sha256: { type: string, description: 'SHA-256 of the subject, a newline and the HTML, computed by the database.' }
        subject: { type: string }
        body_html: { type: string, description: 'The e-mail HTML, with the literal {{ACK_LINK}} where the acknowledgment link goes.' }
        lang: { type: string }
        law: { type: string, description: The governing law of the notice (a country code). }
        template_version: { type: string }
        prepared_at: { type: string, format: date-time }
        sent_at: { type: [string, 'null'], format: date-time }
        names_this_funder: { type: boolean }
        current: { type: boolean }
    RequestNotice:
      type: object
      properties:
        notice_id: { type: string, format: uuid }
        debtor_nif: { type: [string, 'null'], description: "The debtor's tax number." }
        debtor_name: { type: [string, 'null'] }
        has_address: { type: boolean, description: The notice has an e-mail address to go to. }
        status: { type: string, description: 'pending, sent, resent, bounced, acknowledged or rejected.' }
        invoice_ids: { type: array, items: { type: string, format: uuid } }
        total_amount: { type: [number, 'null'] }
        email_sent_at: { type: [string, 'null'], format: date-time }
        document:
          oneOf:
            - $ref: '#/components/schemas/NoticeDocument'
            - type: 'null'
    PayoutCheckResult:
      type: string
      description: "`confirmed`: the payout IBAN is among the accounts the seller's bank returned, held in the company's name. Otherwise why not."
      enum: [confirmed, name_partial, name_mismatch, not_in_linked_accounts, no_bank_link, no_payout_iban]
    PaymentAlert:
      type: object
      properties:
        alert_id: { type: string, format: uuid }
        payer_name: { type: [string, 'null'] }
        payer_iban: { type: [string, 'null'] }
        amount: { type: number }
        currency: { type: string }
        booking_date: { type: string, format: date }
        reference: { type: [string, 'null'] }
        match_rule: { type: string, enum: [invoice_reference, payer_and_amount] }
        confidence: { type: number }
        status: { type: string, enum: [open, acknowledged, dismissed] }
        invoice_ids: { type: array, items: { type: string, format: uuid } }
        created_at: { type: string, format: date-time }
    RequestCashFlow:
      type: object
      properties:
        request_id: { type: string, format: uuid }
        bank_data: { type: string, enum: ['off', requested, required], description: What your terms ask of this seller. }
        cash_flow:
          description: What the seller shares with you; null while it has not connected an account for you.
          oneOf:
            - type: 'null'
            - type: object
              properties:
                consent:
                  type: object
                  properties:
                    consent_id: { type: string, format: uuid }
                    status: { type: string, enum: [active, expired, revoked] }
                    bank: { type: string }
                    country: { type: string }
                    authorised_at: { type: [string, 'null'], format: date-time }
                    valid_until: { type: [string, 'null'], format: date-time }
                    last_sync_at: { type: [string, 'null'], format: date-time }
                accounts:
                  type: array
                  items:
                    type: object
                    properties:
                      iban_last4: { type: string }
                      currency: { type: [string, 'null'] }
                      holder_name: { type: [string, 'null'] }
                      balance:
                        type: [object, 'null']
                        properties:
                          type: { type: string, description: 'The bank''s balance type (CLBD, ITBD, CLAV, …).' }
                          amount: { type: number }
                          currency: { type: string }
                          date: { type: [string, 'null'], format: date }
                balance_total: { type: [number, 'null'], description: The balances of the accounts in euros, added. }
                months:
                  type: array
                  description: The last twelve months with movements, oldest first (booked movements only).
                  items:
                    type: object
                    properties:
                      month: { type: string, description: YYYY-MM }
                      inflow: { type: [number, 'null'] }
                      outflow: { type: [number, 'null'] }
                      net: { type: number }
                      movements: { type: integer }
                first_movement: { type: [string, 'null'], format: date }
                last_movement: { type: [string, 'null'], format: date }
                avg_monthly_inflow: { type: [number, 'null'] }
                avg_monthly_outflow: { type: [number, 'null'] }
                payout_check:
                  type: [object, 'null']
                  properties:
                    result: { $ref: '#/components/schemas/PayoutCheckResult' }
                    iban_last4: { type: [string, 'null'] }
                    holder_name: { type: [string, 'null'] }
                    company_name: { type: [string, 'null'] }
                    checked_at: { type: string, format: date-time }
        bank_data_problems: { type: array, items: { type: string }, description: What funding still waits for when your terms require bank data; empty otherwise. }
        payment_alerts: { type: array, items: { $ref: '#/components/schemas/PaymentAlert' } }
    RecourseClaim:
      type: object
      properties:
        claim_id: { type: string, format: uuid }
        request_id: { type: string, format: uuid }
        request_ref: { type: string }
        seller_id: { type: string, format: uuid }
        company_name: { type: [string, 'null'] }
        kind: { type: string, enum: [recourse, debtor_default] }
        status: { type: string, enum: [open, settled, withdrawn, written_off] }
        invoice_ids: { type: array, items: { type: string, format: uuid }, description: The invoices overdue when the claim opened. }
        first_due_date: { type: string, format: date }
        days_after_due: { type: integer, description: The request's recourse_days. }
        face_amount: { type: number }
        funded_amount: { type: number }
        fee_amount: { type: number }
        collected_before: { type: number, description: What you had collected on the request when the claim opened. }
        claim_amount: { type: number, description: 'recourse: funded_amount + fee_amount - collected_before; debtor_default: face_amount - collected_before (never below 0).' }
        paid_since: { type: number, description: What you recorded on the request since the claim opened. }
        pay_to_iban: { type: [string, 'null'], description: 'Your verified collection account, for a recourse claim.' }
        pay_reference: { type: string, description: 'ADV- and the first 8 characters of the request id, upper case: the reference the statement matching reads.' }
        opened_at: { type: string, format: date-time }
        settled_at: { type: [string, 'null'], format: date-time }
        settled_amount: { type: [number, 'null'] }
        settled_via: { type: [string, 'null'], enum: [statement, manual, request_settled, null] }
        closed_at: { type: [string, 'null'], format: date-time }
        closed_reason: { type: [string, 'null'] }
    Recourse:
      type: object
      properties:
        funder: { $ref: '#/components/schemas/FunderRef' }
        bank_id: { type: string, format: uuid }
        currency: { type: string, const: EUR }
        as_of: { type: string, format: date-time }
        by_type:
          type: array
          description: Your funded factoring requests, by recourse type.
          items:
            type: object
            properties:
              recourse: { type: string, enum: [with, without, not_recorded] }
              requests: { type: integer }
              outstanding_face: { type: number, description: Face value less what you collected. }
              advanced: { type: number }
              with_claim_rule: { type: integer, description: Requests with recourse_days set. }
              confidential: { type: integer }
        claims:
          type: array
          items:
            type: object
            properties:
              kind: { type: string, enum: [recourse, debtor_default] }
              status: { type: string, enum: [open, settled, withdrawn, written_off] }
              n: { type: integer }
              amount: { type: number, description: The claims' claim_amount, added. }
        list: { type: array, items: { $ref: '#/components/schemas/RecourseClaim' } }
    BankData:
      type: object
      properties:
        funder: { $ref: '#/components/schemas/FunderRef' }
        bank_id: { type: string, format: uuid }
        own_accounts:
          type: array
          items:
            type: object
            properties:
              consent_id: { type: string, format: uuid }
              status: { type: string, enum: [pending, active, expired, revoked] }
              bank: { type: string }
              country: { type: string }
              valid_until: { type: [string, 'null'], format: date-time }
              authorised_at: { type: [string, 'null'], format: date-time }
              last_sync_at: { type: [string, 'null'], format: date-time }
              last_sync_error: { type: [string, 'null'] }
              accounts:
                type: array
                items:
                  type: object
                  properties:
                    iban: { type: string }
                    holder_name: { type: [string, 'null'] }
                    currency: { type: [string, 'null'] }
        sellers_sharing: { type: integer, description: Sellers with an active connection shared with you. }
        payment_alerts:
          type: array
          description: The last 180 days.
          items:
            type: object
            properties:
              alert_id: { type: string, format: uuid }
              request_id: { type: string, format: uuid }
              request_ref: { type: string }
              company_name: { type: [string, 'null'] }
              payer_name: { type: [string, 'null'] }
              amount: { type: number }
              currency: { type: string }
              booking_date: { type: string, format: date }
              match_rule: { type: string, enum: [invoice_reference, payer_and_amount] }
              status: { type: string, enum: [open, acknowledged, dismissed] }
              created_at: { type: string, format: date-time }
        charges:
          type: array
          description: 'The account-information provider''s charges recorded against you, per month (the last twelve).'
          items:
            type: object
            properties:
              period: { type: string, format: date, description: The first day of the month. }
              provider: { type: string }
              item: { type: string, description: 'account_month: one account connected for a month.' }
              units: { type: number }
              unit_price_eur: { type: [number, 'null'] }
              amount_eur: { type: [number, 'null'] }
    RequestAnnouncedEventData:
      type: object
      properties:
        request_id: { type: string, format: uuid }
        request_ref: { type: string }
        trigger: { type: string, enum: [manual, overdue, dispute, kyc_lapsed] }
        reason: { type: string }
        status: { type: string, description: The request's status when it was announced. }
        notices:
          type: array
          description: The notices being sent, each with the prepared document's id and SHA-256.
          items:
            type: object
            properties:
              notice_id: { type: string, format: uuid }
              debtor_nif: { type: [string, 'null'] }
              document_id: { type: [string, 'null'], format: uuid }
              document_sha256: { type: [string, 'null'] }
        announced_at: { type: string, format: date-time }
    RecourseOpenedEventData:
      type: object
      properties:
        claim_id: { type: string, format: uuid }
        request_id: { type: string, format: uuid }
        request_ref: { type: string }
        kind: { type: string, enum: [recourse, debtor_default] }
        claim_amount: { type: number }
        funded_amount: { type: number }
        fee_amount: { type: number }
        collected_before: { type: number }
        first_due_date: { type: string, format: date }
        days_after_due: { type: integer }
        invoice_ids: { type: array, items: { type: string, format: uuid } }
        pay_reference: { type: string }
    RecourseSettledEventData:
      type: object
      properties:
        claim_id: { type: string, format: uuid }
        request_id: { type: string, format: uuid }
        request_ref: { type: string }
        kind: { type: string, enum: [recourse, debtor_default] }
        claim_amount: { type: number }
        paid: { type: number, description: What you recorded since the claim opened; absent when the request settled the ordinary way. }
        via: { type: string, enum: [statement, manual, request_settled] }
        request_closed: { type: boolean, const: true }
    PaymentReachedSellerEventData:
      type: object
      properties:
        alert_id: { type: string, format: uuid }
        request_id: { type: string, format: uuid }
        invoice_ids: { type: array, items: { type: string, format: uuid } }
        payer_name: { type: [string, 'null'] }
        payer_iban: { type: [string, 'null'] }
        amount: { type: number }
        currency: { type: string }
        booking_date: { type: string, format: date }
        match_rule: { type: string, enum: [invoice_reference, payer_and_amount] }
        confidence: { type: number, description: '0.98 (reference and amount), 0.90 (reference), 0.80 (payer and amount).' }
    DebtorWatchBlockedEventData:
      type: object
      required: [request_id, request_ref, debtor, status, note, events, detected_at]
      properties:
        request_id: { type: string, format: uuid }
        request_ref: { type: [string, 'null'] }
        debtor:
          type: object
          properties:
            country: { type: string, enum: [ES, PT], description: ISO 3166 alpha-2. }
            tax_id: { type: string, description: The company's tax id (a Spanish CIF or a Portuguese NIPC). }
            name: { type: [string, 'null'], description: The debtor's name on the request's invoices. }
        status: { type: string, const: blocked }
        note:
          type: string
          enum: [insolvency, liquidation, insolvency_no_assets, dissolved, extinct, tax_closed]
          description: The most serious of the acts, as the funder portal labels it.
        events:
          type: array
          description: The acts that block the debtor now (within one insolvency procedure only its latest act counts).
          items:
            type: object
            properties:
              kind:
                type: string
                enum: [insolvency_declared, insolvency_in_progress, insolvency_liquidation, insolvency_concluded_no_assets, dissolution, extinction, register_closed_tax, register_closed_insolvency]
              published_on: { type: string, format: date, description: The day the bulletin published it. }
              source: { type: string, enum: [borme, citius] }
              url: { type: string, format: uri, description: The publication on the BOE (BORME) or on Citius. }
        detected_at: { type: string, format: date-time, description: When the debtor watch read it and the debtor became blocked. }
      example:
        request_id: 7f1c2a9e-5b8d-4c3e-9a1f-0e2d4b6c8a10
        request_ref: ADV-2026-004471
        debtor: { country: ES, tax_id: A28015865, name: 'Grupo Industrial del Cantábrico, S.A.' }
        status: blocked
        note: liquidation
        events: [{ kind: insolvency_liquidation, published_on: '2026-10-02', source: borme, url: 'https://www.boe.es/diario_borme/txt.php?id=BORME-A-2026-189-28' }]
        detected_at: '2026-10-02T07:41:09Z'
    PreOfferAcceptedEventData:
      type: object
      required: [pre_offer_id, request_id, request_ref, seller_id, company_name, company_tax_id, invoice_ids, invoice_count, total_amount, currency, terms, sent_at, valid_until, accepted_at]
      properties:
        pre_offer_id: { type: string, format: uuid }
        request_id: { type: string, format: uuid, description: The request the client made; it is routed to you as always. }
        request_ref: { type: [string, 'null'] }
        seller_id: { type: string, format: uuid, description: Your client. }
        company_name: { type: [string, 'null'] }
        company_tax_id: { type: [string, 'null'] }
        invoice_ids: { type: array, items: { type: string, format: uuid }, description: The invoices of the pre-offer that the request holds. }
        invoice_count: { type: integer }
        total_amount: { type: number, description: The request's total. }
        currency: { type: string, const: EUR }
        terms:
          type: object
          description: What your credit box grid gave when you sent the pre-offer (indicative; your offer on the request is prepared from your grid as it is now).
          properties:
            advance_pct: { type: number }
            rate: { type: number, description: Your discount for the whole term, a flat percentage of the invoices' amount. }
            term_days: { type: integer, description: Days to the due dates, weighted by amount. }
            grade: { type: string, description: Your client's grade when you sent it. }
            grid_version: { type: integer, description: Your credit box policy version. }
        sent_at: { type: string, format: date-time }
        valid_until: { type: string, format: date-time }
        accepted_at: { type: string, format: date-time }
      example:
        pre_offer_id: 3b8f0d2e-61c4-4a7e-9d15-2c0a8e4f7b91
        request_id: 7f1c2a9e-5b8d-4c3e-9a1f-0e2d4b6c8a10
        request_ref: FR-261014-5A72
        seller_id: 0c7d3e51-9a2b-4f6e-8d10-5b3a9c2e7f44
        company_name: 'Distribuciones Ejemplo, S.L.'
        company_tax_id: B00000000
        invoice_ids: [9d2e4f61-0a3b-4c5d-8e7f-1a2b3c4d5e6f]
        invoice_count: 1
        total_amount: 6000
        currency: EUR
        terms: { advance_pct: 85, rate: 1.9, term_days: 54, grade: B, grid_version: 3 }
        sent_at: '2026-10-14T08:12:40Z'
        valid_until: '2026-10-19T08:12:40Z'
        accepted_at: '2026-10-14T10:03:11Z'
    PayoutInstructionEventData:
      type: object
      required: [instruction_id, request_id, request_ref, amount, currency, creditor, remittance, end_to_end_id, execution_date, instant, issued_at, confirm]
      properties:
        instruction_id: { type: string, format: uuid }
        request_id: { type: string, format: uuid }
        request_ref: { type: [string, 'null'] }
        amount: { type: number, description: The accepted advance in euros, the amount the funding confirmation checks to the cent. }
        currency: { type: string, const: EUR }
        creditor:
          type: object
          properties:
            name: { type: string, description: The company's legal name. }
            iban: { type: string, description: The company's payout account. }
            confirmed_by_bank: { type: boolean, description: The company's own bank listed this account in its name (open banking, ADR 0029). }
        remittance: { type: string, description: The request's reference and the end-to-end id, to quote on the transfer. }
        end_to_end_id: { type: string, maxLength: 35 }
        execution_date: { type: string, format: date }
        instant: { type: boolean, description: SEPA Instant is requested. }
        pain001_sha256: { type: [string, 'null'], description: The SHA-256 of the pain.001 file in the funder portal, when your account is registered. }
        issued_at: { type: string, format: date-time }
        confirm:
          type: object
          description: The body of POST /v1/requests/{id}/decision once your bank has paid.
          properties:
            decision: { type: string, const: fund }
            value_date: { type: string, format: date }
            reference: { type: string }
            amount: { type: number }
      example:
        instruction_id: 4b0f9d2a-6c1e-4f7a-9b3d-2e8c5a1f0d47
        request_id: 7f1c2a9e-5b8d-4c3e-9a1f-0e2d4b6c8a10
        request_ref: FR-261012-A41C
        amount: 10200.00
        currency: EUR
        creditor: { name: 'Exemplo Distribuição, Lda', iban: PT50000201231234567890154, confirmed_by_bank: true }
        remittance: FR-261012-A41C TM9C2D41E07B5A3F261012091502
        end_to_end_id: TM9C2D41E07B5A3F261012091502
        execution_date: '2026-10-12'
        instant: true
        pain001_sha256: null
        issued_at: '2026-10-12T09:15:02Z'
        confirm: { decision: fund, value_date: '2026-10-12', reference: TM9C2D41E07B5A3F261012091502, amount: 10200.00 }
    OpportunitiesSummary:
      type: object
      description: A digest in figures (the webhook's data, and `digest` in GET /v1/opportunities).
      properties:
        digest_id: { type: string, format: uuid }
        date: { type: string, format: date }
        stale: { type: boolean, description: The night's run did not complete; nothing was compared. }
        snapshot_at: { type: [string, 'null'], format: date-time, description: When the night's run read your clients' invoices. }
        clients:
          type: object
          properties:
            sharing: { type: integer, description: Your clients that allow you to see their invoices and are verified. }
            not_sharing: { type: integer, description: Your clients that have not allowed it (yet) or are not verified. }
        eligible:
          type: object
          description: Everything eligible that morning (new or shown before).
          properties: { count: { type: integer }, total: { type: number } }
        new:
          type: object
          properties: { count: { type: integer }, total: { type: number } }
        changes:
          type: object
          properties: { paid: { type: integer }, disputed: { type: integer }, no_longer_eligible: { type: integer } }
        currency: { type: string, const: EUR }
        lines: { type: string, description: 'Where the lines are: /v1/opportunities?date=YYYY-MM-DD.' }
    OpportunityLine:
      type: object
      properties:
        kind: { type: string, enum: [new, paid, disputed, no_longer_eligible] }
        reason: { type: [string, 'null'], enum: [requested, cancelled, removed, left_programme, not_shared, rules, null] }
        invoice_id: { type: string, format: uuid }
        number: { type: [string, 'null'] }
        debtor:
          type: object
          properties:
            name: { type: [string, 'null'] }
            tax_id: { type: [string, 'null'] }
            country: { type: [string, 'null'] }
        amount: { type: number, description: What is still owed on the invoice, as the night read it. }
        currency: { type: string, const: EUR }
        due_date: { type: [string, 'null'], format: date }
        client:
          type: object
          properties:
            seller_id: { type: string, format: uuid }
            name: { type: [string, 'null'] }
            tax_id: { type: [string, 'null'] }
            sector: { type: [string, 'null'], description: NACE section (A to U) of the client's activity. }
            grade: { type: [string, 'null'], description: The client's grade that morning. }
            size_band: { type: string, enum: [micro, small, medium, large, unknown], description: 'EU Recommendation 2003/361 turnover bands; unknown when not known.' }
    Opportunities:
      type: object
      properties:
        funder:
          type: object
          properties: { bank_id: { type: string, format: uuid }, name: { type: string } }
        date: { type: [string, 'null'], format: date }
        digest: { oneOf: [{ $ref: '#/components/schemas/OpportunitiesSummary' }, { type: 'null' }] }
        lines: { type: array, items: { $ref: '#/components/schemas/OpportunityLine' }, description: New lines first, then the changes. }
      example:
        funder: { bank_id: 3f1c2a9e-6b1d-4a77-9a51-2f6c0f1d8e10, name: Factor Ejemplo }
        date: '2026-10-07'
        digest:
          digest_id: 9b2d4c1e-0f3a-4e5b-8c6d-7a8b9c0d1e2f
          date: '2026-10-07'
          stale: false
          snapshot_at: '2026-10-07T03:30:12Z'
          clients: { sharing: 9, not_sharing: 1 }
          eligible: { count: 42, total: 318450.00 }
          new: { count: 6, total: 41200.00 }
          changes: { paid: 2, disputed: 0, no_longer_eligible: 1 }
          currency: EUR
          lines: /v1/opportunities?date=2026-10-07
        lines:
          - kind: new
            reason: null
            invoice_id: 0c5e7f3a-2b4d-4c6e-9f81-3a5b7c9d1e2f
            number: FV 2026/1184
            debtor: { name: Distribuciones Ejemplo, S.A., tax_id: A00000000, country: ES }
            amount: 12400.00
            currency: EUR
            due_date: '2026-12-15'
            client: { seller_id: 7d9f1b3c-5e7a-4c9e-8b1d-2f4a6c8e0a1b, name: Talleres Ejemplo, S.L., tax_id: B00000000, sector: C, grade: B, size_band: small }
    RegistryInvoice:
      type: object
      required: [seller, debtor, number, amount, issue_date]
      description: An invoice as you state it. Advanta matches it under a keyed hash and keeps nothing else of it.
      properties:
        seller: { type: object, required: [tax_id, country], properties: { tax_id: { type: string }, country: { type: string, example: ES } } }
        debtor: { type: object, required: [tax_id, country], properties: { tax_id: { type: string }, country: { type: string, example: PT } } }
        number: { type: string, description: As printed on the invoice; spaces, dashes and leading zeros are normalised. }
        amount: { type: number, description: The face amount, taxes included, at most two decimals. }
        currency: { type: string, default: EUR }
        issue_date: { type: string, format: date }
        reference: { type: string, maxLength: 80, description: "Your own reference, returned with the answer and in the webhook, shown to nobody else. Do not put the invoice's tax ids, number or amount in it." }
        kind: { type: string, enum: [assignment, pledge], default: assignment, description: Only when registering. }
      example:
        seller: { tax_id: B00000000, country: ES }
        debtor: { tax_id: '500000000', country: PT }
        number: FV 2026/1184
        amount: 12400.00
        issue_date: '2026-09-30'
        reference: LOT-2026-10-07-118
    RegistryAnswer:
      type: object
      properties:
        index: { type: integer }
        reference: { type: [string, 'null'] }
        assigned: { type: boolean }
        kind: { type: [string, 'null'], enum: [assignment, pledge, null] }
        match: { type: [string, 'null'], enum: [exact, partial, null] }
        yours: { type: boolean }
        lookup_id: { type: string, format: uuid }
        conflict_id: { type: [string, 'null'], format: uuid }
        checked_at: { type: string, format: date-time }
        errors: { type: array, items: { type: string } }
    RegistryEntry:
      type: object
      properties:
        id: { type: string, format: uuid }
        kind: { type: string, enum: [assignment, pledge] }
        state: { type: string, enum: [reserved, assigned, discharged, released] }
        source: { type: string, enum: [platform, api, portal] }
        reference: { type: [string, 'null'] }
        request_id: { type: [string, 'null'], format: uuid }
        request_ref: { type: [string, 'null'] }
        registered_at: { type: string, format: date-time }
        assigned_at: { type: [string, 'null'], format: date-time }
        discharged_at: { type: [string, 'null'], format: date-time }
        released_at: { type: [string, 'null'], format: date-time }
        release_reason: { type: [string, 'null'] }
    RegistryConflict:
      type: object
      properties:
        id: { type: string, format: uuid }
        conflict_id: { type: string, format: uuid, description: In the webhook. }
        role: { type: string, enum: [holder, asker] }
        kind: { type: string, enum: [assignment, pledge] }
        match: { type: string, enum: [exact, partial] }
        status: { type: string, enum: [open, resolved, dismissed] }
        reference: { type: [string, 'null'] }
        entry_id: { type: [string, 'null'], format: uuid }
        lookup_id: { type: [string, 'null'], format: uuid }
        request_id: { type: [string, 'null'], format: uuid }
        request_ref: { type: [string, 'null'] }
        detected_at: { type: string, format: date-time }
    MoneyRecord:
      type: object
      required: [value_date, amount]
      properties:
        value_date: { type: string, format: date, description: The date the money moved (today or before). }
        amount: { type: number, exclusiveMinimum: 0, description: Euros, at most two decimals. }
        bank_reference: { type: [string, 'null'], minLength: 3, maxLength: 140 }
        reason: { type: [string, 'null'], minLength: 8, maxLength: 500, description: Needed when the amount differs from what is due. }
    ProgrammeMoneyEventData:
      type: object
      description: The data of the four programme.* events (one shape). Amounts in euros; dates as dates.
      required: [early_payment_id, repayment_id, offer_id, invoice_id, invoice_ref, currency, buyer, early_payment, repayment]
      properties:
        early_payment_id: { type: string, format: uuid }
        repayment_id: { type: string, format: uuid }
        offer_id: { type: string, format: uuid, description: "The offer's id, the one POST /v1/early-payments/{id}/confirm and /repayment take." }
        invoice_id: { type: string, format: uuid }
        invoice_ref: { type: [string, 'null'], description: "The supplier's invoice number." }
        currency: { type: string, const: EUR }
        buyer: { type: object, description: "Who owes you the repayment.", properties: { id: { type: string, format: uuid }, legal_name: { type: string }, tax_id: { type: string }, tax_country: { type: string } } }
        supplier: { type: [object, 'null'], description: "Whom you paid early.", properties: { legal_name: { type: string }, tax_id: { type: [string, 'null'] }, tax_country: { type: [string, 'null'] } } }
        early_payment: { type: object, properties: { amount: { type: number }, value_date: { type: string, format: date }, bank_reference: { type: [string, 'null'] }, channel: { type: string, enum: [portal, api, service, db] }, recorded_at: { type: string, format: date-time } } }
        repayment:
          type: object
          properties:
            amount: { type: number, description: "What the buyer owes you, the invoice amount." }
            due_date: { type: string, format: date }
            paid: { type: object, description: "programme.repayment_recorded only.", properties: { amount: { type: number }, value_date: { type: string, format: date }, bank_reference: { type: [string, 'null'] }, channel: { type: string, enum: [portal, api] }, recorded_at: { type: string, format: date-time }, days_after_due: { type: integer } } }
        days_to_due: { type: integer, description: "programme.repayment_due_soon only." }
        threshold_days: { type: integer, enum: [7, 1], description: "programme.repayment_due_soon only." }
        days_overdue: { type: integer, description: "programme.repayment_overdue only." }
    EarlyPaymentTotals:
      type: object
      properties:
        to_pay: { type: object, properties: { count: { type: integer }, amount: { type: number } } }
        owed: { type: object, properties: { count: { type: integer }, amount: { type: number } } }
        overdue: { type: object, properties: { count: { type: integer }, amount: { type: number } } }
        repaid: { type: object, properties: { count: { type: integer }, amount: { type: number } } }
        next_due_date: { type: [string, 'null'], format: date }
    EarlyPayment:
      type: object
      properties:
        offer_id: { type: string, format: uuid }
        state: { type: string, enum: [to_pay, due, overdue, repaid] }
        buyer: { type: object, properties: { id: { type: string, format: uuid }, legal_name: { type: string }, tax_id: { type: string }, tax_country: { type: string }, attached: { type: boolean, description: The buyer's programme is attached to you now. } } }
        supplier: { type: object, properties: { legal_name: { type: string }, tax_id: { type: [string, 'null'] }, tax_country: { type: [string, 'null'] } } }
        invoice: { type: object, properties: { id: { type: string, format: uuid }, ref: { type: [string, 'null'] }, amount: { type: number }, due_date: { type: string, format: date } } }
        offer: { type: object, properties: { net_amount: { type: number }, invoice_amount: { type: number }, discount_amount: { type: number }, discount_bps: { type: integer }, pay_date: { type: string, format: date }, accepted_at: { type: [string, 'null'], format: date-time } } }
        early_payment:
          type: [object, 'null']
          properties: { id: { type: string, format: uuid }, amount: { type: number }, value_date: { type: string, format: date }, bank_reference: { type: [string, 'null'] }, reason: { type: [string, 'null'] }, channel: { type: string, enum: [portal, api, service, db] }, recorded_at: { type: string, format: date-time } }
        repayment:
          type: [object, 'null']
          properties:
            id: { type: string, format: uuid }
            amount: { type: number, description: What the buyer owes you, the invoice amount. }
            due_date: { type: string, format: date }
            days_to_due: { type: integer }
            state: { type: string, enum: [due, overdue, paid] }
            paid: { type: [object, 'null'], properties: { amount: { type: number }, value_date: { type: string, format: date }, bank_reference: { type: [string, 'null'] }, reason: { type: [string, 'null'] }, channel: { type: string, enum: [portal, api] }, recorded_at: { type: string, format: date-time } } }
