Browse the documentation

MCP tools

Bid files and background jobs

MCP tools for generating the files you submit with a bid (the response workbook, the attachments file and the cover letter) and following the background jobs behind the large ones.

These tools produce the files you submit with a bid: the NUPCO response workbook, the NUPCO attachments file and the Arabic cover letter. Each file is built from what you have saved in the platform: the prices on the tender's items, the items marked as participating, the products selected for them and the quotations you generated. Four more tools follow the background jobs behind the files that take a while. The bid files explains how the same files are made from the app. For the offers on the iNUPCO portal itself, there is a step-by-step walkthrough.

Tip:The order that works: price the items with `bid_pricing_set_batch` or `sheet_import`, create their quotations with `tender_quotations_generate`, approve them with `quotations_set_approval`, then generate the files with the approved quotations' IDs from `tender_quotations_list`.
Note:All three files cover only items priced above zero and marked as participating. A priced item whose participation mark was cleared is left out and counted in the report as priced_items_not_participating; `tender_item_participation_set_batch` puts the mark back. An item priced 0 is left out whatever its mark and counted as zero_priced_items, since a zero is not a bid price.

The three tools take an optional quotation_ids; with it, the files cover and cite only the items those quotations quote. The saved bid prices stay the authority: a selected quotation that states a different price is reported, never used to change the file. Each tool also takes report: true to return a JSON report instead of the file, so use it first when you want to know what is still missing. The three tools belong to the Pro and Enterprise plans.

ToolWhat it does
tenders_nupco_response_fillFill the NUPCO response file
tenders_nupco_attachments_fillGenerate the NUPCO attachments file
tenders_cover_letter_pdfGenerate the tender cover letter
generation_jobs_listList generation jobs
generation_jobs_getGet a generation job
generation_jobs_partDownload a generation job part
generation_jobs_cancelCancel a generation job

The three bid files

None of these tools changes your records: they read your saved prices and generate a file from them.

tenders_nupco_response_fill

Fills the response workbook you downloaded from NUPCO's e-portal with your saved prices, VAT and selected products for one tender, and returns the same workbook. The template must be the portal's own file for that tender: it cannot be made from scratch, and a file for another tender is refused.

Read-only · scope bids.read · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerYesThe tender's ID, from tenders_list.
template_base64stringYesThe response workbook (.xlsx) exactly as downloaded from the NUPCO portal, as base64. About 3 MB is the practical ceiling, because the server refuses any request over about 4.5 MB. On WhatsApp the assistant passes the attachment's reference in its place.
filenamestringNoThe original file name, up to 300 characters.
vat_percentnumberNoThe default VAT percentage, 0 to 100, for rows whose selected product sets none. 15 when omitted. A product's own rate always wins.
quotation_idsinteger[]NoThe quotation IDs, from `tender_quotations_list`, normally the approved run. The file covers only the items those quotations quote and cites exactly them. Every ID must be one of your organization's quotations on this tender, or the call answers 400 quotation_tender_mismatch. From 1 to 5,000 IDs. Omit it to cover every priced participating item of the tender.
reportbooleanNotrue returns the fill report as JSON, with a download link for the file, instead of the file itself.
{
  "tender_id": 48213,
  "template_base64": "UEsDBBQABgAIAAAAIQAk3kP1...",
  "filename": "NPT0024-26-response.xlsx",
  "vat_percent": 15,
  "quotation_ids": [
    5312,
    5313
  ],
  "report": true
}
Example arguments

Returns: The filled workbook as a file (filename, content_type, size_bytes, base64). With report: true, an object with filename, download_url and the fill report.

  • Only rows of items priced above zero and marked as participating are filled. Rows without a saved price stay as they are and come back hidden rather than deleted, so NUPCO's upload still reads them. A row the fill cannot decide (a material code shared by several rows, a missing mandatory field, no product selected) is reported with its row number, never guessed, and stays visible.
  • The report carries template_rows, filled_rows, hidden_rows, issues, missing_mandatory (the row, the material code and the missing fields), not_applicable (service lines: the cells that describe goods, such as manufacturer and catalog number, which are empty and not missing), unmatched_priced_codes, and the counts priced_items_not_participating, zero_priced_items and priced_items_outside_selection. With quotation_ids it adds quotation_scope and per-row issues: quotation_price_mismatch (a selected quotation states another price than the saved bid price, and the bid price is what the file gets), quotation_not_approved (a quotation still in draft) and multiple_quotations (several selected quotations cover one item, and the newest approved one is cited).
  • A 400 comes back with wrong_template_tender when the file is for another tender, invalid_file_type when it is not an xlsx, missing_columns (its detail names them), no_participating_items when items are priced but none is marked, no_bid_pricing when nothing is priced above zero, and quotation_scope_empty when the selected quotations quote none of the tender's items. A tender your organization cannot see answers 404 tender_not_found.

tenders_nupco_attachments_fill

Builds the NUPCO attachments packet for one tender from scratch: the tab-delimited text file that NUPCO's SRM upload takes, whose columns name PDF files, plus every PDF it names under exactly that name, so the extracted files are the upload set. It is built in the background; the tool waits for it and returns the file, or the job when it takes longer.

Read-only · scope bids.read · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerYesThe tender's ID, from tenders_list.
rfx_response_numberstringYesThe SRM RFx response number shown on the bid in NUPCO's e-portal, such as 5000061479. It is printed on every line of the file, so it must be the real one: ask the bid's owner and never invent it. Plain text, 1 to 40 characters.
quotation_idsinteger[]NoThe quotation IDs, from `tender_quotations_list`, normally the approved run. The file covers only the items those quotations quote and cites exactly them. Every ID must be one of your organization's quotations on this tender, or the call answers 400 quotation_tender_mismatch. From 1 to 5,000 IDs. Omit it to cover every priced participating item of the tender.
reportbooleanNotrue returns the job with its report, which lists the missing files per line, the list of files and the part links, instead of delivering the file.
wait_secondsintegerNoSeconds the tool waits for the packet before it answers with the job: 40 by default, 120 at most. A small packet usually finishes inside the default.
{
  "tender_id": 48213,
  "rfx_response_number": "5000061479",
  "quotation_ids": [
    5312,
    5313
  ],
  "wait_seconds": 60
}
Example arguments

Returns: When the packet finishes within wait_seconds as one ZIP under 4 MB, the file (filename, content_type, size_bytes, base64) comes back with its report. Otherwise the job comes back: job_id, status, progress, parts (each with a download_url valid for an hour once the job has succeeded), report and next_step.

  • A large packet comes in several ZIP parts (about 47 MB each): fetch each part with `generation_jobs_part` and extract all of them into one folder. A packet still being built answers with its job_id and progress and keeps building in the background; follow it with `generation_jobs_get`, or find it in the Generated files card on the quotations page.
  • One packet builds per tender at a time. While one is being built, the tool answers with that job and already_running: true; it may have been started for another selection or another RFx number. Cancel it with `generation_jobs_cancel` to start over.
  • Each line of the file is an item priced above zero and marked as participating, with Change Option C. For every item the packet cites the item's own quotation PDF, a cover letter (the quotation line's one-page product summary followed by the product's stored catalog; without a stored catalog the cover ships alone and the report flags catalog_pages_missing), and its MDMA or SFDA document, which is the stored certificate or a compliance letter generated when the product is under registration or has no certificate, cited in both the SFDA Certificates and MDMA Annex columns. Every PDF is named item-<serial>-<slot>.pdf (the slots are quote, catalog, sfda and mdma) and stays under 40 characters.
  • The report lists, per line, what is missing in missing_files, the slots a service line does not carry (no catalog, SFDA certificate or MDMA annex: not missing) in not_applicable_files, and every file in files, with the same exclusion counts and quotation issues as the response file. The quick checks fail before any job starts: invalid_rfx_response_number, no_bid_pricing, no_participating_items and quotation_scope_empty, and a tender your organization cannot see answers 404 tender_not_found.

tenders_cover_letter_pdf

Generates the Arabic cover letter a supplier submits with its bid, as a PDF. It addresses the buying body, states the offer with its VAT breakdown and carries the regulatory attestation. The item count and the amounts are read from your saved bid, never typed in.

Read-only · scope bids.read · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerYesThe tender's ID, from tenders_list.
letter_numberstringNoYour organization's own outgoing-letter reference, such as DPC-1909, printed on the letter-number line. Omit it to leave the line off. Never invent one: the platform keeps no register of outgoing letters, so an invented number can collide with a real one. Up to 60 characters.
recipientstringNoThe addressee line, in Arabic. When omitted, the buying body the tender names is addressed. Up to 300 characters.
recipient_departmentstringNoThe second addressee line, in Arabic, such as the contracts and procurement department. Up to 300 characters.
notesstringNoAn extra Arabic paragraph printed before the closing, up to 1,000 characters.
quotation_idsinteger[]NoThe quotation IDs, from `tender_quotations_list`, normally the approved run. The file covers only the items those quotations quote and cites exactly them. Every ID must be one of your organization's quotations on this tender, or the call answers 400 quotation_tender_mismatch. From 1 to 5,000 IDs. Omit it to cover every priced participating item of the tender.
reportbooleanNotrue returns the item count, the offer, the VAT and the total as JSON, with a download link for the file, instead of the PDF itself.
{
  "tender_id": 48213,
  "letter_number": "DPC-1909",
  "recipient_department": "إدارة العقود والمشتريات",
  "quotation_ids": [
    5312,
    5313
  ],
  "report": true
}
Example arguments

Returns: The letter as a PDF file (filename, content_type, size_bytes, base64). With report: true, an object with filename, download_url and a report holding item_count, subtotal, vat, total, vat_review, quotation_scope and quotation_price_review.

  • The letter is in Arabic only and does not list enclosed documents, because the platform cannot see what was uploaded to the portal. It works for any tender, not only NUPCO's.
  • The letter states the items priced above zero and marked as participating (within quotation_ids when sent). VAT is summed per line at the rate of the item's selected product: 15% when the product sets none or no product is selected, and 0% for a product the catalog zero-rates, exactly as the NUPCO response file computes it, so the two never contradict. The stated total includes VAT and is also written out in words, over a table that separates the offer from the VAT.
  • Check vat_review before sending: it lists the lines whose VAT rate contradicts the product's medical flag, in either direction (a non-medical product that is zero-rated, which understates the bid, or a medical product at the standard rate), with the VAT each would move. The letter prints the same rate as the response file, so fix the product's VAT in the catalog first. quotation_price_review lists selected quotations that state another unit price than the saved bid price the letter totals.
  • A 400 comes back with no_participating_items when items are priced but none is marked, no_bid_pricing when nothing is priced above zero, and quotation_scope_empty when the selected quotations quote none of the tender's items. A tender your organization cannot see answers 404 tender_not_found.

Background jobs

Two kinds of file are too big for one request, so they are built in the background as jobs: the NUPCO attachments packet (nupco_attachments, started by `tenders_nupco_attachments_fill`) and the quotations bundle (quotation_packages, started by `quotation_packages_bundle`). A job is queued, running, succeeded, failed or cancelled. Jobs belong to the organization, so you see the ones your colleagues started, and a finished job is kept for 24 hours. One packet builds per tender and one bundle per member at a time. The finished file is one ZIP part or more: extract all the parts into one folder.

generation_jobs_list

Lists your organization's background jobs from the last 24 hours, newest first, whoever started them, each with its status and progress. Use it to find a job a colleague started, or one you started and lost the ID of.

Read-only · scope bids.read or quotations.read · roles: owner, admin, sales, purchasing, viewer · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerNoOnly this tender's jobs.
kindstringNoOnly jobs of one kind: nupco_attachments for attachments packets, or quotation_packages for quotations bundles.

Returns: jobs: a list, each with job_id, kind, status, progress (done, total, unit), parts (index, name and size), expires_at after success, error when it failed and a next_step hint. There is no report and there are no download links: read a single job with generation_jobs_get.

  • At most 30 jobs come back. A key sees the kinds its scopes cover: bids.read for attachments packets and quotations.read for quotations bundles, and asking for a kind your scopes do not cover answers 403.

generation_jobs_get

Reads one job: its status and progress, and once it has succeeded its report and its ZIP parts. It can wait up to 120 seconds for the job to finish. The parts of a finished job are delivered with generation_jobs_part.

Read-only · scope bids.read or quotations.read · roles: owner, admin, sales, purchasing, viewer · Pro and Enterprise plans

ParameterTypeRequiredDescription
job_idstringYesThe job's ID (a UUID): the job_id in the reply of the tool that started it, or in generation_jobs_list.
wait_secondsintegerNoWaits up to this many seconds for the job to finish, from 0 to 120. The default is 0: answer at once.

Returns: The job: job_id, kind, status, progress, parts (each with index, filename, size_bytes and a download_url valid for an hour), waiting when nothing has moved it for a while, report and expires_at after success, error with its code and detail on failure, and next_step. On WhatsApp the links are left out; use generation_jobs_part to send a part as a document.

  • Reading a job also moves its work along: when nothing is working on it, the read starts its next stretch of work. A job that nothing has moved for 30 minutes fails with the code stalled.
  • An attachments packet's report is the one described under its tool. A quotations bundle's report names every quotation included with the part it is in, and every quotation that produced nothing by its number with a reason: not_found, render_failed or too_large.
  • An unknown job, or one that belongs to another organization, answers 404, and a key without the scope of the job's kind answers 403: bids.read for an attachments packet and quotations.read for a quotations bundle.

generation_jobs_part

Delivers one ZIP part of a finished job, by the part number generation_jobs_get lists. On WhatsApp the part reaches the person as a document; elsewhere it comes back as base64 when under 4 MB, otherwise as a download link valid for an hour.

Read-only · scope bids.read or quotations.read · roles: owner, admin, sales, purchasing, viewer · Pro and Enterprise plans

ParameterTypeRequiredDescription
job_idstringYesThe job's ID (a UUID).
partintegerNoThe part number, starting at 1; defaults to 1. A part that does not exist answers 404.

Returns: The part as a file (filename, content_type, size_bytes, base64) when it is under 4 MB. Otherwise filename, size_bytes and a download_url valid for an hour, with a note that the file is too large to embed.

  • One part is delivered per call, so a packet in three parts takes three calls, and all the parts are extracted into one folder.
  • A job that has not finished answers 409 job_not_finished: its parts exist only once it has succeeded. The scope of the job's kind is needed, bids.read for an attachments packet and quotations.read for a quotations bundle, and any other answers 403.

generation_jobs_cancel

Stops a queued or running job. The parts built so far are deleted, and the job stays listed as cancelled for 24 hours. Use it before starting a new attachments packet for a tender whose packet is still being built, or a new quotations bundle while your last one is still building.

Deletes or overwrites data · scope bids.read or quotations.read · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
job_idstringYesThe job's ID (a UUID).

Returns: The job after cancellation, with the status cancelled.

  • A job that is no longer queued or running answers 409 job_not_active, with the job. The scope of the job's kind is needed: bids.read for an attachments packet and quotations.read for a quotations bundle.
  • Work in progress stops at its next save, and the parts already built are deleted and cannot be recovered.