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.
  • 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}.)
  • chapters[] — the title tree. Each chapter carries an id, chapter_number, name, is_pretext (a Vorbemerkung), 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_typeARTICLE / 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", …).
    • 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.
    • 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).
  • totalspositions_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.