Browse the documentation

MCP tools

Manual tenders, items and participation

MCP tools for creating manual tenders and managing their items, marking the items you bid on and choosing the product for each.

A manual tender is a tender you enter yourself for a request that never appeared on Etimad or NUPCO. Your organization owns it, no other organization sees it, and it is the only kind of tender these tools can edit or delete. Tenders from Etimad and NUPCO are shared and read-only.

Participation, product selection and supplier prices work on any tender you can see, manual or published, and they belong to the whole organization: what a teammate marks, you see. Tender and item IDs come from tenders_get and tenders_search.

Tip:Pricing items has its own tools in Bids and bid pricing. The NUPCO files and the cover letter read the participation marks you set here, together with the prices, in Bid files and background jobs.
ToolWhat it does
tenders_createCreate a manual tender
tenders_updateUpdate a manual tender
tenders_deleteDelete a manual tender
tender_items_createAdd an item to a manual tender
tender_items_updateUpdate an item
tender_items_deleteRemove an item
tender_item_participation_listList participating items
tender_item_participation_set_batchSet participation for many items
tenders_product_links_listList a tender's product links
tender_item_product_selection_setSelect a product for an item
tender_item_price_levels_setSet what one unit of many items is
tender_item_product_selection_clearClear an item's product selection
tenders_product_links_auto_linkLink products to items automatically
tenders_catalog_pricingPrice a tender from the catalog
tenders_create_products_from_itemsCreate products from items
tenders_sourcing_price_addRecord a supplier price for an item
tenders_badail_poa_importImport NUPCO Badail POA requests

Manual tenders

Three tools create, edit and delete a manual tender. They need the owner or admin role.

tenders_create

Creates a tender you enter by hand, with its items if you send them. Use it for a request that never appeared on Etimad or NUPCO, so that bids, RFQs and quotations can be prepared on it like on any other tender. The tender is private to your organization.

Changes data · scope tenders.write · roles: owner, admin · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_namestringYesThe tender's name, 1 to 500 characters.
agency_namestringYesThe government agency that issued the tender, up to 300 characters.
branch_namestringNoThe agency's branch or department, up to 200 characters.
tender_numberstringNoThe tender number as the agency states it, up to 100 characters. Search finds the tender by this number.
reference_numberstringNoThe reference number, up to 100 characters. Search finds the tender by it too.
tender_typestringNoThe tender type as free text, up to 100 characters.
tender_statusstringNoThe tender's status as free text, up to 100 characters.
source_urlstringNoA link to the original announcement, up to 2,000 characters.
last_enquiries_datestringNoThe last date for questions to the agency. An ISO 8601 timestamp; a value without a time zone is read as Saudi local time.
last_offer_datestringNoThe submission deadline: when the tender closes. The deadline column, the remaining days, the calendar and the alerts all read it. A single date given for a tender goes here, not in submission_date. An ISO 8601 timestamp; a value without a time zone is read as Saudi local time.
offers_opening_datestringNoWhen the offers are opened. An ISO 8601 timestamp; a value without a time zone is read as Saudi local time.
submission_datestringNoThe date the tender was published or announced. It is not the deadline, which belongs in last_offer_date. An ISO 8601 timestamp; a value without a time zone is read as Saudi local time.
booklet_pricenumberNoThe booklet price. In SAR, zero or more. Left out or sent as null, it is stored as 0.
financial_feesnumberNoThe financial fees. In SAR, zero or more. Left out or sent as null, it is stored as 0.
invitation_costnumberNoThe invitation cost. In SAR, zero or more. Left out or sent as null, it is stored as 0.
buying_costnumberNoThe buying cost. In SAR, zero or more. Left out or sent as null, it is stored as 0.
itemsobject[]NoThe tender's starting items, up to 2,000. Every one is added as a new item, in order.
items[].idintegerNoNot used when creating: every item is added as new.
items[].item_namestringYesThe item's name, 1 to 1,000 characters.
items[].descriptionstringNoThe item's description, up to 4,000 characters.
items[].quantitynumberNoThe quantity requested, zero or more.
items[].unitstringNoThe unit of measure, up to 50 characters.
items[].estimated_pricenumberNoThe estimated unit price in SAR, zero or more.
items[].material_codestringNoThe NUPCO material code, up to 100 characters. It is how the platform matches the item to catalog products and price history.
{
  "tender_name": "Supply of disposable syringes",
  "agency_name": "Eastern Region Health Cluster",
  "tender_number": "ERHC-2026-0457",
  "last_offer_date": "2026-11-18T12:00:00",
  "items": [
    {
      "item_name": "Syringe 5 ml with needle, sterile",
      "quantity": 20000,
      "unit": "Piece",
      "material_code": "4111610529900"
    },
    {
      "item_name": "Examination gloves, nitrile, medium",
      "quantity": 500,
      "unit": "Box"
    }
  ]
}
Example arguments

Returns: The new tender's id and its web_url, the address of its page in the web app.

  • Only the owner and admin roles can create, edit or delete a manual tender. Sales and purchasing members can still add and edit its items with the item tools below.
  • A tender is saved with all of its items or not at all: if the items cannot be saved, no tender is created.

tenders_update

Edits a manual tender: its header fields and, when you send items, its whole list of items. A header field you leave out keeps its stored value and null clears it, but the tender name and the agency name are required on every call. Tenders from Etimad and NUPCO cannot be edited.

Changes data · scope tenders.write · roles: owner, admin · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe tender's ID. It must be a manual tender of your organization.
tender_namestringYesThe tender's name, 1 to 500 characters. Required on every call: send the current value when you are not changing it.
agency_namestringYesThe government agency that issued the tender, up to 300 characters. Required on every call: send the current value when you are not changing it.
branch_namestringNoThe agency's branch or department, up to 200 characters. Send null to clear it.
tender_numberstringNoThe tender number as the agency states it, up to 100 characters. Search finds the tender by this number. Send null to clear it.
reference_numberstringNoThe reference number, up to 100 characters. Search finds the tender by it too. Send null to clear it.
tender_typestringNoThe tender type as free text, up to 100 characters. Send null to clear it.
tender_statusstringNoThe tender's status as free text, up to 100 characters. Send null to clear it.
source_urlstringNoA link to the original announcement, up to 2,000 characters. Send null to clear it.
last_enquiries_datestringNoThe last date for questions to the agency. An ISO 8601 timestamp; a value without a time zone is read as Saudi local time. Send null to clear it.
last_offer_datestringNoThe submission deadline: when the tender closes. The deadline column, the remaining days, the calendar and the alerts all read it. A single date given for a tender goes here, not in submission_date. An ISO 8601 timestamp; a value without a time zone is read as Saudi local time. Send null to clear it.
offers_opening_datestringNoWhen the offers are opened. An ISO 8601 timestamp; a value without a time zone is read as Saudi local time. Send null to clear it.
submission_datestringNoThe date the tender was published or announced. It is not the deadline, which belongs in last_offer_date. An ISO 8601 timestamp; a value without a time zone is read as Saudi local time. Send null to clear it.
booklet_pricenumberNoThe booklet price. In SAR, zero or more. Left out, it stays as it is; null stores 0.
financial_feesnumberNoThe financial fees. In SAR, zero or more. Left out, it stays as it is; null stores 0.
invitation_costnumberNoThe invitation cost. In SAR, zero or more. Left out, it stays as it is; null stores 0.
buying_costnumberNoThe buying cost. In SAR, zero or more. Left out, it stays as it is; null stores 0.
itemsobject[]NoThe complete list of items, up to 2,000. It replaces the stored list: an item with an id is updated, one without is added, and any stored item missing from it is removed. Leave it out to keep the items as they are; [] removes them all.
items[].idintegerNoThe ID of a stored item of this tender, to update it in place. Leave it out to add a new item. An ID that does not belong to this tender is treated as a new item.
items[].item_namestringYesThe item's name, 1 to 1,000 characters.
items[].descriptionstringNoThe item's description, up to 4,000 characters. Send null to clear it.
items[].quantitynumberNoThe quantity requested, zero or more. Send null to clear it.
items[].unitstringNoThe unit of measure, up to 50 characters. Send null to clear it.
items[].estimated_pricenumberNoThe estimated unit price in SAR, zero or more. Send null to clear it.
items[].material_codestringNoThe NUPCO material code, up to 100 characters. It is how the platform matches the item to catalog products and price history. Send null to clear it.
{
  "id": 4412,
  "tender_name": "Supply of disposable syringes",
  "agency_name": "Eastern Region Health Cluster",
  "last_offer_date": "2026-11-25T12:00:00"
}
Example arguments

Returns: The tender's id and its web_url.

  • items replaces the list: an item with the id of a stored item is updated in place, an item without an id is added, and every stored item missing from the list is removed ([] removes them all). A removed item is only hidden: its prices, RFQ lines and participation marks are kept, and it comes back when you send its id again or call tender_items_update with restore.
  • Answers 404 when the tender does not exist or belongs to another organization, and 403 when it is a published tender rather than a manual one.

tenders_delete

Deletes a manual tender permanently, together with its items, bids, notes, RFQs, quotations and product selections. It cannot be undone, and tenders from Etimad and NUPCO cannot be deleted. To drop only some lines, use tender_items_delete.

Deletes or overwrites data · scope tenders.write · roles: owner, admin · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe tender's ID. It must be a manual tender of your organization.

Returns: A confirmation, success: true.

  • Sales orders, purchase orders, deliveries and invoices that mention the tender are kept and lose only the link to it.
  • Answers 404 for an unknown tender or another organization's, and 403 for a published one.

Items of a manual tender

Add, change and remove the items of a manual tender one at a time. Removing an item only hides it, so the prices and marks attached to it survive.

tender_items_create

Adds one item to a manual tender. The item number is assigned for you, one above the highest number ever used on the tender, so the number of a removed item is never reused. To send the whole list at once, use tenders_update.

Changes data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerYesThe tender's ID. It must be a manual tender of your organization.
item_namestringYesThe item's name, 1 to 1,000 characters.
descriptionstringNoThe item's description, up to 4,000 characters.
quantitynumberNoThe quantity requested, zero or more.
unitstringNoThe unit of measure, up to 50 characters.
estimated_pricenumberNoThe estimated unit price in SAR, zero or more.
material_codestringNoThe NUPCO material code, up to 100 characters. It is how the platform matches the item to catalog products and price history.
{
  "tender_id": 4412,
  "item_name": "IV cannula 20G, sterile",
  "quantity": 3000,
  "unit": "Piece",
  "material_code": "4111610530118"
}
Example arguments

Returns: The saved item as item, with its id and item_number.

  • Answers 404 when the tender does not exist or belongs to another organization, and 403 when it is a published tender rather than a manual one.

tender_items_update

Changes one item of a manual tender. Only the fields you send change, and null clears an optional one. Send restore: true to bring back an item that was removed.

Changes data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe item's ID, from tenders_get.
item_namestringNoThe new name, 1 to 1,000 characters. It cannot be cleared.
descriptionstringNoThe item's description, up to 4,000 characters. Send null to clear it.
quantitynumberNoThe quantity requested, zero or more. Send null to clear it.
unitstringNoThe unit of measure, up to 50 characters. Send null to clear it.
estimated_pricenumberNoThe estimated unit price in SAR, zero or more. Send null to clear it.
material_codestringNoThe NUPCO material code, up to 100 characters. It is how the platform matches the item to catalog products and price history. Send null to clear it.
restorebooleanNotrue puts an item that was removed back on the tender's list.
{
  "id": 902114,
  "quantity": 3500,
  "estimated_price": 1.8
}
Example arguments

Returns: The item after the change, as item.

  • A call that names no field to change is refused with 400.
  • Answers 404 when the item does not exist or its tender belongs to another organization, and 403 when its tender is a published one rather than a manual one.

tender_items_delete

Removes an item from a manual tender's list by hiding it; the item is not erased. Its prices, RFQ lines and participation marks are kept. To undo, use tender_items_update with restore: true.

Deletes or overwrites data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe item's ID.

Returns: A confirmation, success: true.

  • Answers 404 when the item does not exist or its tender belongs to another organization, and 403 when its tender is a published one rather than a manual one.

Participation

Participation says which items your organization bids on. It is shared by the whole organization and decides what the bid files contain. These tools work on any tender you can see.

tender_item_participation_list

Lists the items your organization has marked as participating, newest first, for one tender or for all of them. The marks are the whole organization's, whoever set them.

Read-only · scope tenders.read · all roles · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerNoOnly marks on this tender's items. Left out, the marks of every tender come back.

Returns: A list of marks, each with id, tender_id, tender_item_id and created_at.

  • The list is not paged. Pass tender_id to narrow it to one tender.

tender_item_participation_set_batch

Marks or clears participation on up to 500 items of one tender in a single call. Use it to mark a whole tender or to drop a group of items at once.

Changes data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerYesThe tender's ID.
item_idsinteger[]YesThe item IDs, from 1 to 500. A repeated ID counts once.
participatingbooleanYestrue marks the items as participating, false removes the mark.
{
  "tender_id": 48213,
  "item_ids": [
    902114,
    902115,
    902118
  ],
  "participating": true
}
Example arguments

Returns: updated, the IDs of the items the change was applied to, and failed, the IDs that are not live items of the tender.

  • The valid items are saved even when some fail, so check failed after every call.
  • Answers 404 when the tender is not visible to you. A key whose creator was deleted is refused with 403 when marking.

A product is a candidate for a NUPCO material code when it is linked to that code in your catalog. A selection is the one product your organization will supply for a particular item.

Shows, for one tender, which catalog products are candidates for each NUPCO material code on its items and which product your organization has selected for each item. Run it before auto-linking or creating products, to see what is already linked.

Read-only · scope tenders.read · all roles · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe tender's ID.

Returns: links: one entry per material code that has candidates (nupco_code and products, each with id, product_name, description, nupco_product_code, manufacturers, is_default and packing), and selections: one entry per item with a selection (tender_item_id, product_id, product_name, catalogue_number, archived, packing, the item's stored level, level and conversion). Each candidate and selection also carries the product's catalog cost (cost_price in cost_currency, null when none is recorded) when your role may see cost pricing, and each selection then carries cost_sar_per_tender_unit too. They carry the sale price (sale_price_sar) when your role may see bid pricing, and each selection then carries sale_price_per_tender_unit too.

  • A code with no candidate does not appear in links. archived: true marks a selected product that has since been moved to the trash.
  • packing is the product's levels: the unit (unit_of_measure), the pack (package_type, holding package_size units), the case (case_type, holding units_per_case units) and what one unit holds (content_quantity of content_unit), with price_basis, the level its cost and sale prices are stated per. null means not stated: the price is used as is.
  • level says what one unit of the item is of the selected product: the level level (unit, pack, case or content) times count, in measure for content. Its status is set (chosen with tender_item_price_levels_set or tender_item_product_selection_set), matched (read from the item's unit, name and description) or check (unsure: priced at one unit of the product until checked, with a suggestion). stated_count is the pack count the item's description states, if any.
  • The item's stored level is price_level, price_level_count, price_level_measure and price_level_product_id; null means automatic, and a stored level applies only while price_level_product_id is the selected product. sale_price_per_tender_unit is the product's sale price for one unit of the item, to four decimals, which is what tenders_catalog_pricing bids, and cost_sar_per_tender_unit is the product's cost in SAR for one unit of the item. conversion is null when the product's price can be converted to the item's unit, else no_conversion with missing (package_size, units_per_case, content_quantity or measure_family): fill the count with products_update or set the item's level.
  • Candidates come from the links between products and NUPCO codes, which product_nupco_link and product_nupco_unlink add and remove.

tender_item_product_selection_set

Chooses the one catalog product your organization will supply for a tender item, replacing any earlier choice. It also links the product to the item's NUPCO material code, so the product shows up as a candidate wherever the code recurs.

Changes data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerYesThe tender's ID.
tender_item_idintegerYesThe item's ID. It must be a live item of the tender you name.
product_idintegerYesThe ID of a product in your organization's catalog that is not in the trash, from products_list.
price_levelstringNoWhat one unit of the item is of this product: unit (one unit of the product), pack (one pack of package_size units), case (one case of units_per_case units) or content (one content_unit of what a unit holds), times price_level_count. Left out, it stays as it is while the product stays the same and returns to automatic when the product changes. null returns it to automatic.
price_level_countnumberNoHow many of price_level make one unit of the item, from 0.0001 to 1,000,000 with at most four decimals. Defaults to 1, and is sent only with price_level.
price_level_measurestringNoWith content only: the measure one unit of the item is counted in when it differs from the product's content_unit but is of the same kind, such as l for a product whose unit holds 500 ml. Left out, the product's own content_unit is used.
{
  "tender_id": 48213,
  "tender_item_id": 902114,
  "product_id": 3071,
  "price_level": "pack"
}
Example arguments

Returns: The saved selection: id, tender_id, tender_item_id, product_id, nupco_code and the stored level (price_level, price_level_count, price_level_measure and price_level_product_id), plus level, what one unit of the item is as the server reads it (as in tenders_product_links_list).

  • Answers 400 with product_not_found when the product is not a live product of your catalog, 400 with item_not_found when the item is not a live item of the tender, and 404 when the tender is not visible to you.
  • Answers 400 with level_missing when the product lacks the count the level needs, with field naming the field to fill with products_update. A level never changes a saved price: it changes what the product's price and cost convert to when pricing from the catalog or by margin. For many items at once, use tender_item_price_levels_set.

tender_item_price_levels_set

Sets, for up to 500 items of one tender, what one unit of each item is of the product selected for it, or returns it to automatic. It changes neither the product nor a saved price: it changes what the product's price and cost convert to when pricing from the catalog or by margin.

Changes data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_idintegerYesThe tender's ID.
itemsobject[]YesThe items, from 1 to 500, each item once.
items[].tender_item_idintegerYesThe item's ID.
items[].price_levelstringYesWhat one unit of the item is of its selected product: unit, pack, case or content, times price_level_count. null returns it to automatic.
items[].price_level_countnumberNoHow many of price_level make one unit of the item, from 0.0001 to 1,000,000 with at most four decimals. Defaults to 1.
items[].price_level_measurestringNoWith content only: the measure one unit of the item is counted in when it differs from the product's content_unit but is of the same kind.
{
  "tender_id": 48213,
  "items": [
    {
      "tender_item_id": 902114,
      "price_level": "pack"
    },
    {
      "tender_item_id": 902115,
      "price_level": "unit",
      "price_level_count": 2
    },
    {
      "tender_item_id": 902118,
      "price_level": null
    }
  ]
}
Example arguments

Returns: updated: the items whose level was saved, each with tender_item_id, product_id, price_level, price_level_count, price_level_measure and price_level_product_id. failed: the items not saved, each with tender_item_id, reason and error. With updated_count and failed_count.

  • Failure reasons: item_not_found for an item that is not a live item of the tender, no_selection for an item with no selected product (select one with tender_item_product_selection_set, which takes the level too), product_not_found for an item whose selected product is no longer in the catalog (select a live one), level_missing for a level whose count the product lacks, with field naming the field to fill with products_update, and selection_changed for an item whose product changed during the call.
  • The valid items are saved even when some fail, and a repeated tender_item_id rejects the whole request. After setting the units, run tenders_catalog_pricing with replace_existing: true to re-price.
  • Answers 404 when the tender is not visible to you.

tender_item_product_selection_clear

Removes the product your organization chose for an item. The link between the product and the item's NUPCO code stays, so the product remains a candidate for that code.

Deletes or overwrites data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
tender_item_idintegerYesThe item's ID.

Returns: A confirmation, success: true.

  • The call succeeds even when the item had no selection.

Selects a product for every item where the choice is obvious: the item's NUPCO code has exactly one candidate product in your catalog. It never overwrites a selection, leaves codes with several candidates alone, and can safely be run again.

Changes data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe tender's ID.

Returns: linked, the number of selections made, and selections, each with tender_item_id, product_id and nupco_code.

  • Removed items, items without a material code and items that already have a selection are skipped. For items with several candidates, choose yourself with tender_item_product_selection_set.

tenders_catalog_pricing

Prices every item your catalog has a product for at the product's sale price (sale_price_sar) converted to the item's unit, and marks the item participating. It is the tender page's "Price from catalog" button.

Changes data · scope bids.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe tender's ID.
dry_runbooleanNotrue reports what would be priced and writes nothing. Defaults to false.
replace_existingbooleanNotrue also re-prices items that already have a price, a zero included. Defaults to false, which keeps every price already entered.
{
  "id": 48213,
  "dry_run": true
}
Example arguments

Returns: priced: the items priced (or that would be, on a dry run), each with tender_item_id, product_id, unit_price (for one unit of the item), source (selected, only, default or lowest), catalog_price (the sale price as in the catalog), basis, price_level, level_count, level_measure, level_status, level_reason, suggestion and factor. unit_check lists the priced items whose unit is unsure, already_priced counts the items whose price was kept, skipped counts the items left alone by reason (ambiguous, no_sale_price, no_product, no_conversion, rounds_to_zero), skipped_items lists them, messages says what to do about each case, and lowest_price_allowed says which rule applied.

  • The product for each item: the one selected for the item, else the only product linked to the item's NUPCO code, else the code's default product (set with product_nupco_link and is_default: true), else the lowest sale price among the code's products, unless the owner turned that off in organization settings (it is on by default). Anything else is left as ambiguous.
  • A product with no sale price is left as no_sale_price and never swapped for another. A product the call picks becomes the item's selected product.
  • The catalog sale price is stated per the product's price_basis and is converted to what one unit of the item is, rounded to four decimals: the level set for the item, else the one read from the item's unit, name and description. A product with no price_basis is priced as is. The lowest price is compared after conversion, among the products whose unit for the item is sure first.
  • An item whose unit is unsure is priced at one unit of the product and listed in unit_check with a suggestion: check it, set its unit with tender_item_price_levels_set, then re-price with replace_existing: true. An item whose price cannot be converted because a packing count is missing (no_conversion, with missing) or rounds to 0.0000 (rounds_to_zero) is left alone.
  • Run it with dry_run: true first and show the person the result, then run it for real once they agree.

tenders_create_products_from_items

Creates one catalog product for each item you name, taking the product's name, description and NUPCO code from the item, and selects it as that item's product. It is how an item with no NUPCO code gets a linked product. Every call creates new products.

Changes data · scope products.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe tender's ID.
item_idsinteger[]YesThe item IDs, from 1 to 500. Each item becomes one product. The tool takes no product text: the product's data comes from the item alone.
{
  "id": 48213,
  "item_ids": [
    902114,
    902115
  ]
}
Example arguments

Returns: created: the products made, each with tender_item_id, product_id, product_name, description and nupco_code, and created_count with their number.

  • It is not safe to repeat: running it twice creates duplicate products. Check tenders_product_links_list first.
  • It replaces any product already selected for these items. The earlier product stays in your catalog and stays a candidate for the code.
  • The whole request is checked before anything is created. It answers 400 with items_not_found when an ID is not a live item of the tender, 400 with item_unnamed for an item with no name, and 402 with plan_limit_reached (plus limit and current) when the products would pass your plan's limit.
  • If the reply carries selections_failed: true, the products were created but could not be selected for their items. Do not run it again; select them with tender_item_product_selection_set.

Supplier prices

Record what a supplier quoted for an item without sending an RFQ. For full RFQs, see RFQs and supplier quotes.

tenders_sourcing_price_add

Records the price a supplier quoted you for one tender item, typed in by hand with no RFQ sent. Name the supplier by manufacturer_id from your directory or by supplier_name. Each call adds a new quote, and the quote joins your sourcing history for items with the same product or NUPCO code on other tenders.

Changes data · scope tenders.write · roles: owner, admin, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe tender's ID.
tender_item_idintegerYesThe item's ID. It must be a live item of this tender.
unit_pricenumberYesThe unit price as the supplier quoted it, in the supplier's currency, zero or more. Do not convert it yourself.
currencystringNoThe three-letter currency code (ISO 4217), such as SAR, EUR or CNY. Defaults to USD. The supported currencies are listed by fx_rates_get.
fx_ratenumberNoUnits of the currency per 1 USD. Left out, the platform picks a default: USD and SAR are fixed (1 and 3.75), currencies pegged to the dollar use their peg, and the rest use the latest European Central Bank rate. A currency with no known rate (such as KWD or EGP) needs this field.
manufacturer_idintegerNoThe ID of the manufacturer in your directory the quote came from, from manufacturers_list. Send null to leave it empty.
supplier_namestringNoThe supplier's name as free text, up to 200 characters. Required when you do not send manufacturer_id. Leave the field out rather than sending null.
supplier_companystringNoThe supplier's company, up to 200 characters.
supplier_emailstringNoThe supplier's email address. It must be a valid address, up to 320 characters.
supplier_phonestringNoThe supplier's phone number, up to 50 characters.
incotermsstringNoThe delivery term, such as CIF or EXW, up to 100 characters.
lead_time_daysintegerNoThe lead time in days, from 0 to 3,650. Send null to leave it empty.
catalog_nostringNoThe supplier's catalog number, up to 100 characters. Send null to leave it empty.
weight_kgnumberNoThe unit weight in kilograms, zero or more. Send null to leave it empty.
units_per_caseintegerNoUnits per case, a positive whole number. Send null to leave it empty.
product_idintegerNoThe ID of the catalog product the quote is for, from products_list. Send null to leave it empty.
notesstringNoNotes on the quote, up to 2,000 characters. Send null to leave them empty.
{
  "id": 48213,
  "tender_item_id": 902114,
  "unit_price": 0.34,
  "currency": "EUR",
  "supplier_name": "Medline Europe GmbH",
  "incoterms": "CIF",
  "lead_time_days": 60,
  "units_per_case": 1000
}
Example arguments

Returns: The recorded quote: rfq_id (the tender's sourcing record that holds the quote), response_id, supplier_name, currency and fx_rate.

  • The price is kept as the supplier quoted it, in its own currency, with the exchange rate used when you recorded it. Comparisons run in USD and show the original price beside it.
  • Either manufacturer_id or supplier_name is required, and one is enough. The supplier's optional text fields are left out when unused, never sent as null.
  • Answers 400 with invalid_items when the item is not a live item of this tender, and 400 with manufacturer_not_found when the manufacturer is not in your directory. An unsupported currency, or one with no rate, answers 400 with a message that names what to send.
  • A key whose creator was deleted is refused with 403.

The Badail POA import

The one tool on this page that writes outside your organization: it creates shared NUPCO tenders that every organization sees.

tenders_badail_poa_import

Reads the Pay On Account (POA) export of the Badail program downloaded from the NUPCO portal and creates one NUPCO tender per POA request, with the request's products as items. The tenders join the shared NUPCO list that every organization sees, so the tool is limited to platform admins and members granted Etimad collection access. The server reads the whole workbook: send the file itself, never rows you copied from it.

Changes data · scope tenders.write · roles: owner, admin, sales, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
content_base64stringNoOne .xlsx file downloaded from the POA Requests list in the NUPCO portal, encoded as base64. It may be up to 5 MB once decoded, and the server refuses a request larger than about 4.5 MB. Always send the real file. Send this or files, never both.
filenamestringNoThe original name of the content_base64 file, up to 300 characters. The reply names rows by it; it does not affect the import.
filesobject[]NoSeveral exports imported together instead of content_base64, from 1 to 20, read in the order sent. Together they may be up to 5 MB once decoded.
files[].content_base64stringYesThe .xlsx file, encoded as base64. Always send the real file.
files[].filenamestringNoThe original file name, up to 300 characters. The reply names the file by it; left out, files are called file 1, file 2 and so on.
statusesstring[]NoThe portal statuses to import, such as PAY_ON_ACCOUNT_BY_BADAIL, up to 50, matched without regard to letter case. Left out, every row is imported.
dry_runbooleanNotrue reports what would be created or updated and writes nothing. Defaults to false.
{
  "content_base64": "UEsDBBQABgAIAAAAIQ...",
  "filename": "poaRequest_12.xlsx",
  "statuses": [
    "PAY_ON_ACCOUNT_BY_BADAIL"
  ],
  "dry_run": true
}
Example arguments

Returns: The counters created, updated, failed and dry_run; requests, one per POA request with poa_request, tender_id, outcome (one of created, updated, would_create, would_update, failed), items, deadline, status, file and web_url; skipped and warnings, each with the sheet row, its file and a message; filtered_out and status_counts, the number of requests per portal status; and files, each file with the number of requests taken from it.

  • Each item's material code is the first half of the portal's generic code (4111610529900_4111610529905 becomes 4111610529900). The request date is read as day-month-year. The deadline, last_offer_date, is the end of the fifth Saudi working day (Sunday to Thursday) after the request day; public holidays are not counted.
  • Importing a newer file again updates the requests already on file in their header only (status, customer, purchase order and name). It never touches their items or dates, so the prices and quotations built on them stay intact.
  • Rows missing the request number, the customer name, a valid date or the generic code, and repeated request numbers, are listed in skipped and nothing is imported from them. Rows whose packed lists do not line up are imported with a note in warnings.
  • With several files, a request that appears more than once is taken from the first file it appears in, and its repeats in later files are listed in skipped, naming that first file. A file that cannot be read refuses the whole import with a 422 naming it, before anything is written.
  • Besides the scope, whoever created the key or connection must be a platform admin or hold Etimad collection access; the organization role does not grant it, and without it the call is refused with 403. A file that is not a valid POA export answers 422.