# TenderBrief - Procurement Notice to JSON (`zahi90/tenderbrief`) Actor

Convert procurement notice text into structured, evidence-linked JSON with buyers, deadlines, values, CPV codes, requirements, and explicit uncertainty flags.

- **URL**: https://apify.com/zahi90/tenderbrief.md
- **Developed by:** [Zahi Mansour](https://apify.com/zahi90) (community)
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 notice processeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## TenderBrief — Procurement Notice to JSON

**TenderBrief converts procurement notices and tender text into consistent, evidence-linked JSON for AI agents, procurement automation, data pipelines, and downstream analysis.**

Give TenderBrief a supported procurement notice and it extracts useful commercial fields while preserving uncertainty instead of inventing missing information.

### What TenderBrief extracts

TenderBrief can identify and normalize:

- Tender or notice title
- Buyer / contracting authority
- Tender reference
- Submission deadline
- Publication date
- Location
- Stated contract value
- Currency
- Value type, such as estimated value
- CPV codes
- Notice status when supported
- Requirement excerpts
- Evidence supporting extracted fields
- Missing-field warnings
- Extraction warnings and limitations

The output is designed to be easy for another AI agent, procurement workflow, ETL pipeline, database, or application to consume.

### Why use TenderBrief?

Procurement notices are often inconsistent.

The same information can appear under different labels, date formats, currencies, languages, or document structures. Automated systems therefore spend unnecessary time repeatedly interpreting similar information.

TenderBrief provides a lightweight normalization layer between raw procurement information and the software that needs to use it.

Instead of returning only extracted values, TenderBrief also preserves supporting evidence and uncertainty.

For supported text and HTML inputs, evidence can include the source line and supporting quote.

For supported OCDS input, the source structure is preserved where possible.

Missing information is returned as unknown rather than guessed.

### Supported input

#### Single notice

For the easiest use case, paste one procurement notice into `noticeText`.

Example:

```text
Title: Example Network Services Contract
Buyer: Example Borough Council
Reference: EX-2026-001
Submission deadline: 15 October 2026 at 14:00 UTC
Estimated value: GBP 250000
Location: London
CPV: 72400000
The supplier must provide 24/7 network monitoring.
```

#### Batch processing

Advanced users can submit up to 50 notices in the `notices` array.

A batch item can contain supported procurement material such as:

- `text` — plain notice text
- `html` — supplied HTML
- `ocds` — a supported OCDS release object

Optional metadata can include:

- `id`
- `sourceUrl`

`sourceUrl` is retained as metadata only.

**TenderBrief does not fetch the URL.**

### Languages

TenderBrief recognizes a defined set of common procurement labels in:

- English
- French
- Spanish

Supported labels include common equivalents for fields such as buyer, contracting authority, deadline, value, reference, location, publication date, and CPV code.

Language support is intentionally narrow and should not be interpreted as full natural-language understanding of every tender format.

### Example output

A successful result can look like:

```json
{
  "schemaVersion": "1.0",
  "inputId": "notice-1",
  "inputType": "text",
  "extractionMethod": "deterministic_labels_v1",
  "title": "Example Network Services Contract",
  "buyer": "Example Borough Council",
  "reference": "EX-2026-001",
  "location": "London",
  "deadline": {
    "raw": "15 October 2026 at 14:00 UTC",
    "date": "2026-10-15",
    "time": "14:00:00",
    "timezone": "UTC",
    "utc": "2026-10-15T14:00:00Z"
  },
  "values": [
    {
      "raw": "GBP 250000",
      "amount": "250000",
      "currency": "GBP",
      "valueType": "estimated"
    }
  ],
  "cpvCodes": [
    "72400000"
  ],
  "requirementExcerpts": [
    {
      "quote": "The supplier must provide 24/7 network monitoring."
    }
  ],
  "warnings": [
    "cpv_codes_not_validated_against_codelist"
  ],
  "missingFields": [],
  "status": "partial"
}
```

The full result can also contain:

- Field-level evidence
- Source excerpts
- Content hashes
- Processing metadata
- Missing-field information
- Explicit limitations
- Duplicate-processing identifiers

### Designed for AI agents

TenderBrief is useful when an AI agent needs procurement information in a predictable structure instead of repeatedly interpreting differently formatted notices.

Potential workflows include:

- Procurement opportunity monitoring
- Tender-data normalization
- Bid-management workflows
- Procurement research agents
- Automated opportunity databases
- Cross-source procurement pipelines
- Tender screening and routing
- Structured context for downstream AI systems

TenderBrief currently uses deterministic parsing for supported fields rather than relying on a generative AI model for every notice.

This makes the output easier to reproduce and reduces the risk of unsupported values being invented.

### Evidence-linked extraction

TenderBrief attempts to preserve evidence for extracted fields.

For example:

```json
{
  "buyer": [
    {
      "line": 2,
      "quote": "Buyer: Example Borough Council",
      "basis": "cleaned_text",
      "untrustedSourceText": true
    }
  ]
}
```

This allows downstream systems to inspect not only the extracted value, but also the source text that supported it.

Source excerpts are treated as **untrusted data**, not instructions for a consuming AI agent.

### Requirement excerpts

TenderBrief can identify text containing supported requirement-style language, for example:

```text
The supplier must provide 24/7 network monitoring.
```

These excerpts are returned as source evidence.

They are **not** legal interpretations and are **not** determinations of bidder eligibility.

### Date handling

TenderBrief normalizes supported dates.

For ambiguous numeric dates such as:

```text
03/04/2026
```

you can choose:

- `Auto` — do not guess when genuinely ambiguous
- `DMY` — interpret as day/month/year
- `MDY` — interpret as month/day/year

The default is:

```text
Auto
```

For supported date-time formats, TenderBrief can return:

- Raw source value
- Normalized date
- Normalized time
- Time zone
- UTC timestamp
- Precision
- Parsing issues

### Duplicate detection

TenderBrief generates a content hash for processed notices.

Within supported workflows, this helps identify duplicate notice content and avoid unnecessary repeated processing.

### Output status

Results can include statuses such as:

- `structured` — supported fields were extracted successfully
- `partial` — useful structure was extracted but warnings or unresolved validation remain
- `unstructured` — insufficient supported structure was identified

A `partial` result is not necessarily a failed extraction.

For example, a notice may be successfully parsed while still carrying a warning that a CPV code has not been independently checked against the official CPV code list.

Warnings are intentional.

They help prevent downstream agents from treating uncertain information as established fact.

### Pricing

TenderBrief uses Apify pay-per-event pricing.

The primary paid event is:

```text
notice-processed
```

It represents one unique procurement notice successfully delivered as a structured or partially structured result.

Invalid inputs, duplicates, and notices with insufficient supported structure are not intended to trigger the notice-processing result event.

A separate Actor-start event may still apply according to the pricing shown on the Apify Store listing.

Always refer to the Store pricing section for the current price.

### Important limitations

TenderBrief is deliberately conservative.

It does **not** currently:

- Fetch URLs supplied in the input
- Download linked attachments
- Read PDF files directly
- Perform OCR
- Render JavaScript-heavy webpages
- Provide legal advice
- Provide procurement advice
- Determine whether a bidder is legally eligible
- Guarantee that a procurement notice is complete
- Guarantee that a procurement notice is current
- Independently authenticate the source document
- Independently validate every CPV code against the official CPV code list
- Treat missing information as proof that a requirement does not exist
- Automatically resolve every complex lot structure
- Automatically combine multiple amendments into a complete procurement history
- Reliably understand every free-form procurement notice

The quality of the result depends on the material supplied.

Free-form prose with no recognizable supported structure may be rejected rather than guessed.

### Security and trust

Procurement notice content should be treated as untrusted input.

TenderBrief returns source excerpts as data only.

A downstream AI system should not interpret instructions found inside procurement text as instructions to the AI itself.

Do not include:

- Passwords
- API keys
- Private credentials
- Confidential information you are not authorized to process

### Get started

For a quick test:

1. Open TenderBrief.
2. Paste a procurement notice into `noticeText`.
3. Leave ambiguous date handling on `Auto`.
4. Run the Actor.
5. Open the default dataset.
6. Review the normalized JSON and supporting evidence.

Example input:

```text
Title: Example Network Services Contract
Buyer: Example Borough Council
Reference: EX-2026-001
Submission deadline: 15 October 2026 at 14:00 UTC
Estimated value: GBP 250000
Location: London
CPV: 72400000
The supplier must provide 24/7 network monitoring.
```

### Automated use

TenderBrief can be incorporated into automated workflows through Apify's supported APIs, SDKs, integrations, and agent-compatible tooling.

A typical workflow is:

```text
Procurement notice
        ↓
TenderBrief
        ↓
Structured JSON
        ↓
AI agent / database / ETL pipeline / procurement workflow
```

TenderBrief is designed to act as the normalization step between messy notice text and structured downstream processing.

### Best use cases

TenderBrief is most suitable when:

- You already have procurement notice text
- You want standardized JSON
- You need evidence linked to extracted values
- You want missing information made explicit
- You need deterministic processing of supported fields
- You are processing multiple notices through an automated workflow

TenderBrief is not intended to replace a full procurement search platform or legal review service.

### Support

If TenderBrief fails on a notice format that should reasonably be supported, open an Issue on the Actor and include:

- A non-confidential example, or
- A simplified reproduction of the problematic notice

Please do not post confidential procurement documents, credentials, personal information, or commercially sensitive material in a public Issue.

# Actor input Schema

## `noticeText` (type: `string`):

Paste one procurement notice here. For batch processing, leave this empty and use the Advanced batch input below instead.

## `notices` (type: `array`):

Optional. Process up to 50 notices at once. Use either this field or the single notice field above, not both.

## `dateOrder` (type: `string`):

How should dates such as 03/04/2026 be interpreted? Auto leaves genuinely ambiguous dates unresolved.

## `includeCleanedText` (type: `boolean`):

Include the normalized source text in each result. Usually leave this off to keep outputs smaller.

## Actor input object example

```json
{
  "noticeText": "Title: Example Network Services Contract\nBuyer: Example Borough Council\nReference: EX-2026-001\nSubmission deadline: 15 October 2026 at 14:00 UTC\nEstimated value: GBP 250000\nLocation: London\nCPV: 72400000\nThe supplier must provide 24/7 network monitoring.",
  "dateOrder": "auto",
  "includeCleanedText": false
}
```

# Actor output Schema

## `notices` (type: `string`):

Delivered procurement notices converted into structured JSON.

## `report` (type: `string`):

Shows delivered notices, duplicates, rejected inputs, and processing status.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "noticeText": `Title: Example Network Services Contract
Buyer: Example Borough Council
Reference: EX-2026-001
Submission deadline: 15 October 2026 at 14:00 UTC
Estimated value: GBP 250000
Location: London
CPV: 72400000
The supplier must provide 24/7 network monitoring.`
};

// Run the Actor and wait for it to finish
const run = await client.actor("zahi90/tenderbrief").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "noticeText": """Title: Example Network Services Contract
Buyer: Example Borough Council
Reference: EX-2026-001
Submission deadline: 15 October 2026 at 14:00 UTC
Estimated value: GBP 250000
Location: London
CPV: 72400000
The supplier must provide 24/7 network monitoring.""" }

# Run the Actor and wait for it to finish
run = client.actor("zahi90/tenderbrief").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "noticeText": "Title: Example Network Services Contract\\nBuyer: Example Borough Council\\nReference: EX-2026-001\\nSubmission deadline: 15 October 2026 at 14:00 UTC\\nEstimated value: GBP 250000\\nLocation: London\\nCPV: 72400000\\nThe supplier must provide 24/7 network monitoring."
}' |
apify call zahi90/tenderbrief --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zahi90/tenderbrief"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0ngkVZCubP2BQBNGI/builds/GW5e2qIu63cacXSIa/openapi.json
