Back

    Buyamia Directory API

    v1.1.0

    RFQ & Quotes

    The core procurement integration. RFQ routes check their scopes individually — rfq.read for reads, rfq.write for writes (and rfq.write also satisfies the RFQ list/detail read checks), quotes.write to record a supplier quote.

    POST
    /v1/rfq/inbound

    Create an RFQ with its line items. Returns 201 with `{ data, items_created }`. Fires `rfq.created`.

    rfq.write

    Required: title, buyer_name, and a non-empty items array — otherwise 400. When buyer_email is supplied, the buyer record is matched by email or created.

    Request bodyjson
    {
      "external_rfq_id": "PROC-2026-0042",
      "title": "Office furniture — Q3",
      "buyer_name": "Andi Pratama",
      "buyer_company": "Nusantara Works",
      "buyer_email": "andi@nusantara.example",
      "buyer_phone": "+6281…",
      "delivery_location": "Denpasar, Bali",
      "delivery_date": "2026-10-15",
      "priority": "medium",
      "notes": "Split delivery acceptable.",
      "items": [
        {
          "name": "Ergonomic office chair",
          "description": "Mesh back, adjustable lumbar",
          "category_slug": "furniture",
          "quantity": 40,
          "unit_of_measure": "piece",
          "target_price": 1500000,
          "target_currency": "IDR",
          "notes": "Black only"
        }
      ]
    }
    • Items accept either category_id or category_slug; the slug is resolved server-side and becomes null if unknown.
    • unit_of_measure defaults to piece, target_currency to IDR, priority to medium.
    • Line items are numbered in array order (item_number starts at 1).
    • Store the returned data.id — every other RFQ route is keyed by it, not by external_rfq_id.
    GET
    /v1/rfq

    List RFQs with their line items. Flat list envelope, supports `limit` / `offset` and status filtering.

    rfq.read (or rfq.write)
    GET
    /v1/rfq/:id

    Single RFQ with line items.

    rfq.read (or rfq.write)
    PUT
    /v1/rfq/:id

    Update an RFQ. When `status` changes, fires `rfq.status_changed` including the `external_rfq_id`.

    rfq.write
    POST
    /v1/rfq/:id/suppliers

    Attach a supplier (business) to the RFQ so it can be quoted.

    rfq.write
    DELETE
    /v1/rfq/:id/suppliers/:supplierId

    Detach a supplier from the RFQ.

    rfq.write
    GET
    /v1/rfq/:id/quotes

    All supplier quotes for an RFQ. 404 when the RFQ does not exist.

    rfq.read
    Response shape (not the list envelope)json
    {
      "rfq_id": "9f31…",
      "external_rfq_id": "PROC-2026-0042",
      "rfq_number": "RFQ-2026-0117",
      "title": "Office furniture — Q3",
      "suppliers": [
        {
          "supplier_id": "c3a1…",
          "business_name": "Bali Teak Works",
          "business_slug": "bali-teak-works",
          "status": "quoted",
          "quoted_price": 56000000,
          "quoted_unit_price": 1400000,
          "quoted_currency": "IDR",
          "quoted_lead_time_days": 21,
          "quoted_payment_terms": "50% down, 50% on delivery",
          "quoted_notes": "Price valid 14 days.",
          "contacted_at": "2026-09-01T04:11:00Z",
          "response_received_at": "2026-09-02T02:40:00Z",
          "is_selected": false
        }
      ]
    }
    GET
    /v1/rfq/:id/quotes/:supplierId

    One supplier's full quote row. 404 when that supplier is not on the RFQ.

    rfq.read
    POST
    /v1/rfq/:id/quotes

    Record a supplier quote. Sets the supplier status to `quoted` and stamps `response_received_at`. Returns 201. Fires `rfq.quote_submitted`.

    quotes.write
    Request bodyjson
    {
      "supplier_id": "c3a1…",
      "quoted_price": 56000000,
      "quoted_unit_price": 1400000,
      "quoted_currency": "IDR",
      "quoted_lead_time_days": 21,
      "quoted_payment_terms": "50% down, 50% on delivery",
      "quoted_notes": "Price valid 14 days."
    }

    supplier_id is required (400 otherwise) and the supplier must already be attached to the RFQ. quoted_currency defaults to IDR when omitted — always send it explicitly.

    Current as of API 1.1.0 — released 7 September 2026