Skip to content

Reading tenders

A tender is keyed by the request id (tender_id == request_id): reading one returns the tender's current projected state — the structured, priced result Mercura produces — carrying everything on the corresponding PDF the customer sees:

  • status — lifecycle state (NEW, IN_PROGRESS, DONE, CANCELLED, PARSING, PARSING_FAILED). DONE means the tender has been completed (released to the partner API via the seller's Finalize / Export → API action — which is what stamps completed_at and fires tender.completed).
  • completed_at — when the tender was last completed, or null if it never was. Refreshed on every completion, so a re-export moves it forward (see the completion feed below).
  • customer_id — the direct customer (Sold-To) reference only (your BusinessPartner.external_id); resolve name / address / contact / custom fields via GET /customers/{customer_id}. Null when the tender has no customer.
  • indirect_customer_id — the indirect customer (Mercura's indirekter Kunde) reference only; resolve the full record via GET /customers/{customer_id}. Distinct from customer_id. Null when the tender has no indirect customer.
  • project_id — the project reference only; resolve the full record via GET /projects/{project_id}. Null when the tender has no project.
  • project_name — the project's display name, surfaced inline (same value as name on GET /projects/{project_id}) so you need no second call. Null when the tender has no project.
  • object_number — your object number (Objektnummer) for this tender: the identifier your ERP opens the job under, surfaced inline so you need no second call. It is the tender's own number when one is maintained — an ERP that opens one object per incoming tender gives sibling tenders on the same project different numbers — otherwise the project's object_number. null when neither carries one. Read-only here: Mercura users maintain it in the app, and POST /projects/{project_id}/acknowledgements writes the project-level one (see the Projects tag).
  • submission_date — the bid-submission date (Submissions-/Abgabetermin) as originally supplied on the project: an ISO date or free text, null when unknown. This is the tender's submission deadline, not an offer-validity (gültig bis) date. Mirrors the project's submission_date.
  • deadline — Mercura's internal handling deadline for the request (typically the submission date minus a buffer): an ISO date or free text, null when unset. Informational only — not the submission deadline and not an offer-validity date.
  • user_email — the responsible Mercura user for the tender (mirrors the integration-export user_email).
  • branch — the primary Mercura branch (Niederlassung) assigned to the tender as { id, name }, or null when none is assigned.
  • request_custom_fields — custom fields on the underlying request, keyed by display label (multi_select values resolved to their option labels). Writable on PATCH (see Editing a tender).
  • user_custom_fields — custom fields on the responsible user (user_email), keyed by display label — e.g. a user's SGI. null when the tender has no responsible user or the user has no custom fields. (You can still resolve the same fields via GET /users?email={user_email}.)
  • export_fields — what the user entered in the ERP export dialog when releasing the tender: your organisation's own export fields (e.g. the customer or ship-to number to book the offer under), keyed by the field key configured for your organisation. Reflects the latest release through that dialog; null when there was none or your organisation configures no such fields. Read-only.
  • chapters[] — the title tree. Each chapter carries an id, chapter_number, name, is_pretext (a Vorbemerkung), sequence, nested chapters[], and positions[].
  • positions[] (per chapter) — one entry per line, each with:
    • id — an opaque, re-match-stable handle (the position's request-scoped number); the key you pass back to edit the line.
    • line_type — ARTICLE / TEXT / DIVERSE.
    • labels[] — role/label overlay, each { text, type } (type is CUSTOM / ALTERNATIVE / ACCESSORY / PARTS_LIST); a CUSTOM label carries your org-defined text (product groups, "Bestellware", …). On PATCH it is writable in exactly one place — marking a new sub-line as an alternative or an accessory (see Editing a tender); on an edit it is ignored, so a GET body round-trips.
    • gaeb_position_type — the GAEB Positionsart (BASE, OPTIONAL_WITH_TOTAL, OPTIONAL_WITHOUT_TOTAL, ALTERNATIVE) or null.
    • article_number, manufacturer_article_number, name, description, additional_text, quantity, unit, list_price, discount_percentage, net_price, line_net, line_gross.
    • parent_line_id — set only on an article-note line: the id of the line it annotates (both sit on the same position). Null everywhere else.
    • name — the matched article's name: the article text maintained in Mercura (the title shown in the UI). Null for a free-text line.
    • description — the matched article's own description field (distinct from name), or the free-text for a text line.
    • description_lines — description split into its lines (trailing whitespace and trailing empty lines dropped), for an ERP that keeps a line's text as fixed-length rows, e.g. SAP's two 40-character rows. Your organisation can have the text of DIVERSE lines entered as a fixed number of rows of a maximum length; each row then arrives as typed. Read-only.
    • specification_text — the source LV's own long text for this ordinal number (the Ausschreibungstext, verbatim), independent of what Mercura matched to it and identical on every line sharing a position_number. Use this — not description — when you import the Leistungsverzeichnis itself rather than the priced offer. Null when the source LV carried no long text.
    • page_number — the 1-based page of the source document this ordinal number was read from, identical on every line sharing a position_number. Use it when the request document refers to its items by page rather than by number, e.g. to group your quote lines by page. It counts the pages of the file as Mercura received it; it is not a page label printed on the page. Null when no page is known (GAEB and other structured files, positions added by hand). Not part of the ETag; ignored on PATCH.
    • manufacturer — the matched article's manufacturer / supplier name (Hersteller/Lieferant), or null for a free-text line.
    • custom_attributes — the matched article's catalogue custom attributes (same shape as GET /articles/{id}'s custom_attributes, e.g. sales_unit, the article type article_type, and other source-system unit/extra fields), or null for a free-text line.
    • For a DIVERSE line matched to a generic "Divers" placeholder article, description is the operator-typed text (what you see in the matching UI), not the placeholder article's catalogue text.
    • is_counted_in_total — false for lines excluded from the totals (alternatives, Bedarfsposition ohne Gesamtbetrag).
    • partner_pricing_override_at — when a partner last overrode the line's price via PATCH, else null.
    • is_deleted / deleted_at — whether this line was removed from the tender, and when. Only ever set when you ask for removed lines (include_deleted=true, see Removed lines and positions).
    • is_lv_only — true for an ordinal number that carries no priced line at all. Only ever set when you ask for the whole LV (include_all_positions=true, see The complete Leistungsverzeichnis).
    • sequence — where the line stands in Mercura's order (see Line order).
  • totals — positions_subtotal, additional_discount_percentage, net_total, gross_total (EUR), and partner_totals_override_at. positions_subtotal is a derived helper: the sum across lines with is_counted_in_total = true (excludes alternatives and Bedarfspositionen ohne Gesamtbetrag). net_total / gross_total are the authoritative amounts that match the PDF — they are after the header discount and may include optional positions or other adjustments, so they can legitimately differ from positions_subtotal. Treat net_total as the amount owed.
  • erp_offer_id — the partner-side ERP offer id when known (populated from your acknowledgement's external_id, or from a Mercura-managed ERP export).
  • acknowledgement — your last reported import outcome for this tender (status, external_id, message, metadata, acknowledged_at), or null until you acknowledge it (see below).

You can:

  • GET /tenders — cursor-paginated list. Use modified_since for delta-sync catch-up scans, or status to filter by lifecycle state.
  • GET /tenders/{tender_id} — one tender in full. This is what the tender.completed webhook points you at. The response carries a strong ETag over the tender content; pass it back as If-Match on PATCH.