# Santa Fe Tenders Scraper & Monitor (`stefano_seggio/santafe-compras-monitor`) Actor

Scrape and monitor every public tender of the Province of Santa Fe, Argentina: licitaciones, concursos, contrataciones directas of ministries and hospitals with buyer, budget, deadlines, rubros, expediente and pliego/circular/acta PDF links. Delta mode for new, status-changed and amended tenders.

- **URL**: https://apify.com/stefano\_seggio/santafe-compras-monitor.md
- **Developed by:** [Stefano Seggio](https://apify.com/stefano_seggio) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Santa Fe Tenders Scraper & Monitor (Licitaciones Santa Fe) — Store Overview

**Actor ID:** `jfoq1flE7KqKb3qAb` · **Store URL:** https://apify.com/stefano\_seggio/santafe-compras-monitor · **Version:** 2.0 (latest patch per Changelog: 2.0.1)

***

### Executive Summary & Business Use Case

Santa Fe Tenders Scraper & Monitor extracts and monitors the official **Gestiones de Compra register of the Province of Santa Fe, Argentina** (`santafe.gov.ar/gestionesdecompras`), reading the site's own internal JSON search endpoint (`AppAjax.php?a=consultas.getContrataciones`) and the public detail page of every process. This is the single, official record of every *licitación pública*, *licitación privada*, *concurso*, *contratación directa*, *subasta* and *convenio marco* run by the province's ministries, hospitals, SAMCOs, Aguas Santafesinas, airports and the Lotería, roughly 1,100 new processes a year and over 31,000 since 2000. For every process the Actor returns the buyer (*comprador*) and requesting body (*organismo comitente*), the published budget (*Monto Original*, with currency), the submission deadline and bid-opening date, the rubro/sub-rubro classification, the expediente number with a link to the province's file tracker, institutional contact details, and direct links to the pliego, circulares, actas de apertura and preadjudicación documents. In delta mode it also tags every record as a `NEW_LISTING`, a `STATUS_CHANGE` (the process moved from one estado to another) or an `UPDATED` amendment, none of which the site itself signals in any visible way.

The register has no publication-date column in its listing, no RSS, no e-mail alerts and a CSV export that strips ids, amounts and document links — so anyone tracking Santa Fe procurement today either re-searches the portal by hand or subscribes to a commercial alert service built for humans, not for systems. This Actor is the missing structured layer between the register and a business process.

Three concrete uses the real data supports: (1) **suppliers to the provincial health system** — pharmaceutical and medical-supply distributors, cleaning and catering contractors to hospitals and SAMCOs — use `rubroNames`, `comprador` and `submissionDeadline` to catch a matching tender inside its short bid window (a contratación directa published on a Friday can close the following Monday) and pull the pliego straight from `documents`; (2) **construction, IT, security and facility-service contractors** use `objeto`, `organismoComitente`, `montoOriginalAmount` and `isElectronic`/`bidUrl` to route province-wide opportunities to the right sales owner and register on the electronic-bid portal before the deadline; (3) **bid consultants and *gestores de licitaciones*** run the Actor on a schedule with `onlyNew` on and watch for `event_type = UPDATED` together with `hasCircular` or a new `openingNote` to know when a client's open tender needs its draft offer revisited. Because `montoOriginalAmount` carries a real published budget figure (in ARS or USD, never converted), spending-analysis use cases — by transparency NGOs, journalists or competitors benchmarking who is awarded what via `hasAdjudicacion`/`hasOrdenProvision` — are also directly supported by the data, unlike registers that expose no monetary field at all.

### Technical Features & V2 Architecture Highlights

**Delta persistence.** With `onlyNew: true` the Actor keeps a private, named key-value store per filter set — `santafe-compras-monitor-state-<deltaStateName>` — that remembers, for every process it has ever delivered, the estado it was last seen in and a fingerprint (`contentHash`) of its detail page. `deltaStateName` defaults to a fingerprint of the run's own filters (so unrelated schedules never collide) but can be set explicitly to make two tasks share one memory, and `resetState: true` wipes it to force a fresh baseline. This state persists **across runs**, which is what makes scheduled monitoring return only genuinely new material instead of the same processes every time.

**Event types — domain-specific, not the generic set.** This actor's `event_type` enum is exactly `NEW_LISTING`, `STATUS_CHANGE`, `UPDATED` — there is **no `CLOSED` event**. That is a deliberate fit to how the register works: a tender is never "closed" in the sense of being removed, it moves between three visible lists — `AP` (Para Apertura), `ET` (En Trámite), `CO` (Concluida) — so a transition is modeled as `STATUS_CHANGE` with `previousEstado` recording where it came from, rather than as a close event. `UPDATED` exists because the listing itself never changes when a *circular aclaratoria*, an *acta de apertura* or a *preadjudicación* report is published — those only show up on the detail page, so the Actor re-reads and fingerprints it to detect them.

**`onlyNew` — exact behaviour per its own schema.** Per `input_schema.json`: *"Remembers every process it has delivered (per filter set, in a named key-value store) with the estado it was in and a fingerprint of its detail page, and returns only processes that are new, moved to another estado, or were amended since. Each estado list is walked newest-first and stops as soon as it reaches already-known records."* Practically: the AP and ET lists are small enough to be walked in full every run, so a process that vanished from them is probed on its own detail page and delivered as `STATUS_CHANGE` even if the CO list isn't being monitored. Amendment detection additionally depends on `recheckWindowDays` (default 30): known processes opening within that many past days, or any time in the future, get their detail page re-read every run — re-reads that find no change are **not charged**.

**Field count.** This actor's own `README.md` and `dataset_schema.json` confirm **84 total output fields**: a 6-field **integration envelope** (`record_id`, `event_type`, `scraped_at`, `is_new`, `source_url`, `data_source`) — described in the README as identical across this developer's other public-register Actors, so one webhook parser serves all of them — plus 78 process-specific fields (the version-1 fields kept verbatim, normalised UTC/amount/boolean twins, and the full detail-page extraction). This is not the generic "18 base fields" pattern sometimes used elsewhere in the fleet; Santa Fe's own schema is the source of truth here and it declares 84.

**Cost-relevant architecture detail.** `fetchDetail` (default `true`) controls whether each record costs a `result` (full detail page: budget, deadline, rubros, contact, expediente, document links, fingerprint) or a cheaper `result-summary` (listing-only, or a process the site reports as not yet published). Detail pages are fetched concurrently (`maxConcurrency`, default 5, max 10) since the site tolerated 10 parallel requests without throttling in verification.

### Input Schema & JSON Configuration Example

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `estados` | array (`AP`|`ET`|`CO`) | `["AP"]` | Which lists to read. AP = Para Apertura (published, offers not yet opened - where every new tender appears first), ET = En Trámite (opened, being evaluated - actas and preadjudicación land here), CO = Concluida (finished). Each is a separate server-side query. |
| `anio` | integer | *(none)* | Year of the process number (anioGestion). The site's own UI always applies the current year; leave empty for all years (2000 onwards). |
| `objeto` | string | *(none)* | Case-insensitive phrase search over the tender subject, e.g. 'limpieza', 'medicamentos', 'servicio de vigilancia'. Word order matters ('servicio de limpieza' matches, 'limpieza servicio' does not). |
| `tipoGestion` | array (13 codes) | `[]` | One server-side query per selected type. Codes are the site's own (L = Licitación Pública, P = Licitación Privada, T = Contratación Directa, ...). |
| `tipoModalidad` | string (enum) | *(none)* | Contracting modality code from the site. |
| `comprador` | string | *(none)* | The organism running the procedure, as its site id (idOrganismoLey12510, e.g. 27) or a distinctive part of its name (e.g. 'Administración Provincial de Impuestos', 'Hospital Cullen'). Names are matched against the site's own organism list at run start; an ambiguous name fails with the candidates listed. |
| `solicitante` | string | *(none)* | The organism the purchase is for, same id space and name matching as 'Buyer' (e.g. 'Ministerio de Salud'). |
| `rubro` | string | *(none)* | Product/service category, as the site's idEspecie (e.g. 29) or part of its name (e.g. 'medicinales', 'limpieza', 'alimentos'). Matched against the site's 78 rubros at run start. |
| `subrubro` | string | *(none)* | Sub-category within the selected rubro, as idFamilia or part of its name. Requires 'Category (rubro)'. |
| `nroGestion` | string | *(none)* | Exact process number as printed on the site, e.g. '18' or '02' (combine with the year: several organisms share the same numbering). |
| `nroExpediente` | string | *(none)* | Exact, full expediente number, e.g. 'EE-2026-00001797-APPSF-OD' (partial values match nothing on the site). |
| `openingFrom` | string (date) | *(none)* | Only tenders whose bid opening (fecha de apertura) is on or after this date. Absolute (2026-09-01) or relative: '7 days' counts back from today, '+7 days' counts forward (Santa Fe calendar). Applied client-side after fetching the listing (the site has no date filter) - rows outside the window are simply skipped and not remembered. |
| `openingTo` | string (date) | *(none)* | Only tenders opening on or before this date. Absolute or relative ('+30 days' = opening within the next month). Client-side. |
| `eventTypes` | array (`NEW_LISTING`|`STATUS_CHANGE`|`UPDATED`) | all three | NEW\_LISTING = a process never delivered before; STATUS\_CHANGE = a known process that moved to another estado (AP -> ET -> CO); UPDATED = a known open process whose detail page changed (a circular aclaratoria, an acta de apertura, a preadjudicación report, a new opening date...). The last two exist in delta mode only. |
| `onlyNew` | boolean | `false` (prefill `true`) | Remembers every process it has delivered (per filter set, in a named key-value store) with the estado it was in and a fingerprint of its detail page, and returns only processes that are new, moved to another estado, or were amended since. Each estado list is walked newest-first and stops as soon as it reaches already-known records. |
| `recheckWindowDays` | integer | `30` | Delta mode with detail: known processes whose opening date is within this many days in the past (or any time in the future) get their detail page re-read every run to detect amendments (UPDATED). The register shows no 'last modified' signal, so this re-read is the only way to see a new circular or acta. 0 disables it. Re-reads are not charged unless something changed. |
| `sortBy` | string (enum) | `"newest"` | 'newest' (idGestion descending = most recently created first) is required for delta mode. 'openingSoonest' / 'openingLatest' order by bid-opening date; 'mostViewed' by the site's own view counter (full runs only). |
| `deltaStateName` | string | fingerprint of filters | Optional label for the memory of a monitoring task. Defaults to a fingerprint of your filters, so different schedules never interfere. Set the same name on two tasks to make them share one memory. |
| `resetState` | boolean | `false` | Forget every previously delivered process for this delta state and re-baseline (the run then returns up to 'Max records' newest processes). |
| `maxItems` | integer | `100` | Hard cap on delivered records (and therefore on cost: you pay per record). In delta mode anything beyond the cap is simply delivered by the next run. |
| `fetchDetail` | boolean | `true` | Opens each process page (one extra request) for the publication timestamp, budget (Monto Original), submission deadline, places, rubros, requesting organism, contact, expediente and the pliego / circular / acta / preadjudicación document links. Off = listing-only summary records (cheaper 'result-summary' price; no UPDATED detection and no status sweep). |
| `maxConcurrency` | integer | `5` | How many process pages are fetched at once. The site answers a page in 0.1-0.3 s and tolerated 10 in parallel without throttling; 5 is a polite default. |
| `dateRange` | string (hidden, deprecated) | *(none)* | Kept for tasks created with version 1: '24h', '7d' or '30d' are interpreted as an opening-date window of that many days before AND after today. |

#### JSON configuration example

```json
{
  "estados": ["AP", "ET"],
  "anio": 2026,
  "objeto": "medicamentos",
  "tipoGestion": ["T"],
  "comprador": "Hospital Cullen",
  "rubro": "medicinales",
  "eventTypes": ["NEW_LISTING", "STATUS_CHANGE", "UPDATED"],
  "onlyNew": true,
  "recheckWindowDays": 30,
  "sortBy": "newest",
  "deltaStateName": "hospital-cullen-medicinales",
  "resetState": false,
  "maxItems": 300,
  "fetchDetail": true,
  "maxConcurrency": 5
}
```

### Output Dataset Sample & Data Dictionary

| Field | Type | Description |
| --- | --- | --- |
| `record_id` | string | Same value as idGestion - stable across runs (e.g. 138825). |
| `event_type` | string | NEW\_LISTING (never delivered before), STATUS\_CHANGE (known process moved AP -> ET -> CO), UPDATED (known open process whose detail page changed: circular, acta, preadjudicación, new date...). |
| `scraped_at` | string | ISO-8601 UTC timestamp of this extraction (same for every record of one run). |
| `is_new` | boolean | true when this process was never delivered by a previous run of this delta state. |
| `source_url` | string | The official detail page (gestion.php?idGestion=...). |
| `data_source` | string | Attribution string (Gobierno de Santa Fe, CC BY-SA 2.5 AR). |
| `idGestion` | string | The register's own numeric process id, as a string. |
| `estado` | string | The list the process was found in: AP (Para Apertura), ET (En Trámite), CO (Concluida). For a STATUS\_CHANGE found by the status sweep, the estado the detail page reports. |
| `tipoGestion` | string | null | Procedure type as printed, e.g. LICITACIÓN PÚBLICA, CONTRATACIÓN DIRECTA. |
| `numeroGestion` | string | null | Process number within the organism and year, e.g. 18. |
| `anioGestion` | string | null | Year of the process number, e.g. 2026. |
| `fechaHoraApertura` | string | null | Opening date as the listing prints it, DD-MM-YYYY. Null for a record rebuilt from the detail page only. |
| `objeto` | string | null | Short subject of the tender. |
| `comprador` | string | null | Buying organism (organismo licitante) as listed. |
| `valorPliego` | string | null | Price of the bid documents as free text ('NO APLICA', 'SIN COSTO', '$ 8209,50 (PESOS ...)'). |
| `numeroExpediente` | string | null | File number as the listing prints it - often blank; see expediente for the detail-page value. |
| `detail` | object | null | The version-1 detail object kept for compatibility: fields (label -> value), rubros\[] and documentos\[] {tipo, nombre, url}. Null when fetchDetail=false or the page is unavailable. |
| `idGestionNumber` | integer | idGestion as a number - the register's creation order and the delta engine's ordering key. |
| `numeroAnio` | string | null | Human reference 'número-año', e.g. 18-2026. |
| `tipoGestionCode` | string | null | The site's letter code for tipoGestion (L, P, A, T, B, V, C, I, D, S, X, Y, O). |
| `tipoModalidad` | string | null | Contracting modality (Sin Modalidad, Convenio Marco, ...). |
| `idOrganismoGestion` | string | null | The listing's internal organism id (a different id space from the comprador filter's idOrganismoLey12510). |
| `objetoCompleto` | string | null | Full subject text from the listing. |
| `destinos` | string | null | Delivery / recipient organism text (ET and CO rows only). |
| `fechaHoraAperturaFija` | string | null | Opening timestamp as the API prints it, YYYY-MM-DD HH:mm:ss Santa Fe time. |
| `openingAt` | string | null | Bid opening instant, UTC ISO-8601 (Santa Fe is UTC-3). |
| `openingDate` | string | null | YYYY-MM-DD, Santa Fe calendar. |
| `daysUntilOpening` | integer | null | Negative once the opening has passed. |
| `isOpeningInFuture` | boolean | null | Whether opening is still ahead. |
| `valorPliegoAmount` | number | null | Numeric price of the bid documents when one is quoted. |
| `valorPliegoCurrency` | string | null | ARS or USD. |
| `valorPliegoIsFree` | boolean | null | true for 'NO APLICA' / 'SIN COSTO' / '$ 0'; false when a price is quoted; null when undecidable. |
| `previousEstado` | string | null | For STATUS\_CHANGE: the estado the process was last delivered in. |
| `isElectronic` | boolean | true when the expediente matches the pattern the site uses to show its 'Ofertar' button (bids via gestionvirtual.santafe.gob.ar). |
| `bidUrl` | string | null | gestionvirtual.santafe.gob.ar bid form for electronic procedures. |
| `printPdfUrl` | string | Print-ready PDF of the whole record (output.php?a=gestiones.ver\&print=1). |
| `documentsUrl` | string | Documents-only view of the record (solodocs=1). |
| `detailFetched` | boolean | true when the detail page was read and parsed (charged as 'result'); false for listing-only records ('result-summary'). |
| `detailError` | string | null | UNPUBLISHED when the site says the process does not exist / is not published yet; otherwise null. |
| `estadoLabel` | string | null | The detail page's own Estado text, e.g. 'PARA APERTURA', 'EN TRÁMITE - Análisis de ofertas', 'CONCLUIDA'. |
| `estadoStage` | string | null | Evaluation stage suffix of the estado label, when present. |
| `estadoFromDetail` | string | null | AP / ET / CO derived from estadoLabel. |
| `publishedAtLocal` | string | null | 'DD-MM-YYYY HH:mm Hs.' as printed. |
| `publishedAt` | string | null | Publication instant, UTC ISO-8601 - the only true publication timestamp on the register (never changes, even when documents are added later). |
| `publishedDate` | string | null | YYYY-MM-DD, Santa Fe calendar. |
| `daysSincePublished` | integer | null | Days since publication. |
| `modalidad` | string | null | Modalidad (detail). |
| `alcance` | string | null | Scope, e.g. NACIONAL. |
| `descripcion` | string | null | Full description. |
| `rubros` | array | Category / sub-category pairs ('RUBRO / SUBRUBRO' split) as {rubro, subrubro, raw}. |
| `rubroNames` | array | Rubro names. |
| `subrubroNames` | array | Subrubro names. |
| `organismoComitente` | array | Requesting body / bodies the purchase is for. |
| `organismoLicitante` | string | null | Organism running the procedure (detail page). |
| `submissionPlace` | string | null | Where / how offers are submitted (often an e-mail or the gestionvirtual link). |
| `submissionDeadlineLocal` | string | null | Offer submission deadline as printed. |
| `submissionDeadline` | string | null | Offer submission deadline, UTC ISO-8601 - distinct from the opening; the date suppliers schedule against. |
| `daysUntilDeadline` | integer | null | Days until the submission deadline. |
| `openingPlace` | string | null | Lugar de apertura. |
| `openingAtDetailLocal` | string | null | Fecha de apertura (detail, raw). |
| `openingNote` | string | null | Text after the opening date on the detail page, e.g. '(\*\*\* NUEVA FECHA \*\*\*)'. |
| `deliveryPlaceAndDate` | string | null | Lugar y fecha de entrega. |
| `contactInfo` | string | null | Institutional contact text as published (phone / e-mail). |
| `contactEmails` | array | E-mail addresses found in the contact and submission fields, lower-cased. |
| `contactPhones` | array | Contact phone numbers. |
| `valorPliegoDetail` | string | null | Valor del pliego (detail). |
| `montoOriginalText` | string | null | Budget / estimated value as printed, e.g. '$ 207.302.040,00' or 'U$S 60.000,00'. |
| `montoOriginalAmount` | number | null | Numeric budget. Under Argentine inflation compare with publishedDate; never converted. |
| `montoOriginalCurrency` | string | null | ARS or USD. |
| `expedientes` | array | File numbers from the detail page with the tracker link, as {label, code, url}. |
| `expediente` | string | null | First expediente code from the detail page (the listing's numeroExpediente is often blank). |
| `expedienteUrl` | string | null | Link to the province's file tracker. |
| `notes` | array | Free-form 'IMPORTANTE' blocks some buyers add to the page. |
| `documents` | array | Every attachment as {kind, tipo, nombre, url, id}. Kinds: pliego, circular, llamado, acta\_apertura, nomina\_oferentes, cuadro\_comparativo, informe\_comision, preadjudicacion, adjudicacion, orden\_provision, documento\_provision, planimetria, otros. |
| `documentCount` | integer | Number of documents. |
| `documentKinds` | array | Distinct document kinds present. |
| `hasPliego` | boolean | Bid-document pack published. |
| `hasCircular` | boolean | A circular aclaratoria/modificatoria was published - the pliego changed. |
| `hasActaApertura` | boolean | Offers were opened. |
| `hasPreadjudicacion` | boolean | A pre-award report exists. |
| `hasAdjudicacion` | boolean | A 'Norma Legal de Adjudicación' (award decision) was published. |
| `hasOrdenProvision` | boolean | A purchase order was issued. |
| `hasCuadroComparativo` | boolean | A price comparison table was published. |
| `contentHash` | string | null | SHA-1 fingerprint of the detail page's data and documents - the delta engine's change key (null for listing-only records). |

#### Sample dataset record

```json
{
  "record_id": "139402",
  "event_type": "NEW_LISTING",
  "scraped_at": "2026-09-08T09:15:32.117Z",
  "is_new": true,
  "source_url": "https://www.santafe.gov.ar/gestionesdecompras/site/gestion.php?idGestion=139402",
  "data_source": "Gestiones de Compra - Gobierno de la Provincia de Santa Fe (santafe.gov.ar/gestionesdecompras), CC BY-SA 2.5 AR",
  "idGestion": "139402",
  "estado": "AP",
  "tipoGestion": "CONTRATACIÓN DIRECTA",
  "numeroGestion": "112",
  "anioGestion": "2026",
  "fechaHoraApertura": "22-09-2026",
  "objeto": "ADQUISICIÓN DE INSUMOS DESCARTABLES Y MEDICAMENTOS PARA EL SERVICIO DE TERAPIA INTENSIVA",
  "comprador": "HOSPITAL J. B. ITURRASPE",
  "valorPliego": "NO APLICA",
  "numeroExpediente": "",
  "idGestionNumber": 139402,
  "numeroAnio": "112-2026",
  "tipoGestionCode": "T",
  "tipoModalidad": "Sin Modalidad",
  "idOrganismoGestion": "44",
  "objetoCompleto": "ADQUISICIÓN DE INSUMOS DESCARTABLES Y MEDICAMENTOS PARA EL SERVICIO DE TERAPIA INTENSIVA DEL HOSPITAL J. B. ITURRASPE",
  "destinos": null,
  "fechaHoraAperturaFija": "2026-09-22 10:00:00",
  "openingAt": "2026-09-22T13:00:00.000Z",
  "openingDate": "2026-09-22",
  "daysUntilOpening": 14,
  "isOpeningInFuture": true,
  "valorPliegoAmount": null,
  "valorPliegoCurrency": null,
  "valorPliegoIsFree": true,
  "previousEstado": null,
  "isElectronic": true,
  "bidUrl": "https://gestionvirtual.santafe.gob.ar/#/bandeja_proveedores/create/form/68a1c2b3d4e5f6789abc0123?expedienteCode=EE-2026-00007912-APPSF-PE",
  "printPdfUrl": "https://www.santafe.gov.ar/gestionesdecompras/site/output.php?a=gestiones.ver&idGestion=139402&print=1",
  "documentsUrl": "https://www.santafe.gov.ar/gestionesdecompras/site/gestion.php?idGestion=139402&solodocs=1",
  "detailFetched": true,
  "detailError": null,
  "estadoLabel": "PARA APERTURA",
  "estadoStage": null,
  "estadoFromDetail": "AP",
  "publishedAtLocal": "05-09-2026 11:20 Hs.",
  "publishedAt": "2026-09-05T14:20:00.000Z",
  "publishedDate": "2026-09-05",
  "daysSincePublished": 3,
  "modalidad": "Sin Modalidad",
  "alcance": "PROVINCIAL",
  "descripcion": "Adquisición de insumos descartables y medicamentos para reposición de stock del servicio de Terapia Intensiva.",
  "rubros": [
    { "rubro": "PRODUCTOS MEDICINALES Y FARMACEUTICOS", "subrubro": "MEDICAMENTOS", "raw": "PRODUCTOS MEDICINALES Y FARMACEUTICOS / MEDICAMENTOS" }
  ],
  "rubroNames": ["PRODUCTOS MEDICINALES Y FARMACEUTICOS"],
  "subrubroNames": ["MEDICAMENTOS"],
  "organismoComitente": ["HOSPITAL J. B. ITURRASPE"],
  "organismoLicitante": "HOSPITAL J. B. ITURRASPE",
  "submissionPlace": "EL PROVEEDOR A EFECTOS DE LA PRESENTACIÓN DE SU OFERTA, DEBERÁ INGRESAR AL SIGUIENTE LINK: HTTPS://GESTIONVIRTUAL.SANTAFE.GOB.AR",
  "submissionDeadlineLocal": "22-09-2026 10:00 Hs.",
  "submissionDeadline": "2026-09-22T13:00:00.000Z",
  "daysUntilDeadline": 14,
  "openingPlace": "DIRECCIÓN DE COMPRAS DEL HOSPITAL J. B. ITURRASPE",
  "openingAtDetailLocal": "22-09-2026 10:00 Hs.",
  "openingNote": null,
  "deliveryPlaceAndDate": "FARMACIA DEL HOSPITAL, DENTRO DE LOS 10 DÍAS DE NOTIFICADA LA ORDEN DE COMPRA",
  "contactInfo": "(0342) 457-3357 - COMPRAS.ITURRASPE@SANTAFE.GOV.AR",
  "contactEmails": ["compras.iturraspe@santafe.gov.ar"],
  "contactPhones": ["(0342) 457-3357"],
  "valorPliegoDetail": "NO APLICA",
  "montoOriginalText": "$ 4.850.000,00",
  "montoOriginalAmount": 4850000,
  "montoOriginalCurrency": "ARS",
  "expedientes": [
    { "label": "Expediente", "code": "EE-2026-00007912-APPSF-PE", "url": "https://www.santafe.gov.ar/expedientes-web/expediente-timbo/?anioTimbo=2026&numeroTimbo=00007912&tipoReparticion=APPSF&reparticionTimbo=PE&tipoTimbo=1&buscarTimbo=Buscar" }
  ],
  "expediente": "EE-2026-00007912-APPSF-PE",
  "expedienteUrl": "https://www.santafe.gov.ar/expedientes-web/expediente-timbo/?anioTimbo=2026&numeroTimbo=00007912&tipoReparticion=APPSF&reparticionTimbo=PE&tipoTimbo=1&buscarTimbo=Buscar",
  "notes": [],
  "documents": [
    { "kind": "pliego", "tipo": "Pliego", "nombre": "PLIEGO DE BASES Y CONDICIONES PARTICULARES", "url": "https://www.santafe.gov.ar/gestionesdecompras/descargar.php?m=anexo&id=172340&hash=3a7fbe11c0d2e6ab8f5c9d1e6a2b7c40&panel=0", "id": "172340" }
  ],
  "documentCount": 1,
  "documentKinds": ["pliego"],
  "hasPliego": true,
  "hasCircular": false,
  "hasActaApertura": false,
  "hasPreadjudicacion": false,
  "hasAdjudicacion": false,
  "hasOrdenProvision": false,
  "hasCuadroComparativo": false,
  "contentHash": "9e21f8b4c7a03d5e6f1b8290ac4d7e5f13b6c890"
}
```

A `STATUS_CHANGE` carries the same shape with `"previousEstado": "AP"` and `"estado": "ET"`; an `UPDATED` record carries `"is_new": false` and typically `"hasCircular": true` or a populated `openingNote` such as `"(*** NUEVA FECHA ***)"`.

### Multi-language Integration Snippets

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/stefano_seggio~santafe-compras-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "estados": ["AP", "ET"],
    "rubro": "medicinales",
    "onlyNew": true,
    "maxItems": 300
  }'
```

#### Python (apify-client)

```python
from apify_client import ApifyClient

client = ApifyClient(token)
run = client.actor("stefano_seggio/santafe-compras-monitor").call(
    run_input={
        "estados": ["AP", "ET"],
        "rubro": "medicinales",
        "onlyNew": True,
        "maxItems": 300,
    }
)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(
        item["event_type"],
        item["numeroAnio"],
        item["objeto"],
        item["comprador"],
        item["montoOriginalAmount"],
        item["submissionDeadline"],
    )
```

#### Node.js (apify-client)

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

const client = new ApifyClient({ token });
const run = await client.actor('stefano_seggio/santafe-compras-monitor').call({
    estados: ['AP', 'ET'],
    rubro: 'medicinales',
    onlyNew: true,
    maxItems: 300,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems({ desc: true });
for (const tender of items) {
    console.log(
        tender.event_type,
        tender.comprador,
        tender.objeto,
        tender.submissionDeadline,
        tender.montoOriginalAmount,
    );
}
```

### Pricing Model Explanation

| Event | Price | What triggers it on this actor |
| --- | --- | --- |
| `result` | **$0.003** per record | A record delivered with the full detail page fetched (`fetchDetail: true`, the default) — publication timestamp, budget (Monto Original), submission deadline, rubros, requesting organism, contact, expediente and the pliego/circular/acta/preadjudicación document links, plus the `contentHash` fingerprint. |
| `result-summary` | **$0.001** per record | A listing-only record — either `fetchDetail: false` (no extra page fetched, so no detail fields, no `UPDATED` detection and no status sweep for that record), or a process the site itself reports as not yet published (`detailError: "UNPUBLISHED"`). |
| `apify-actor-start` | **$0.00005** | Once per run, regardless of how many records it delivers. |

The two-tier `result` vs `result-summary` split maps directly to the `fetchDetail` input: it is a **full detail-page fetch versus a listing-only summary**, not an old-vs-new distinction. Turning `fetchDetail` off is the deliberate way to pull large volumes cheaply (e.g. an archive sweep for spending analysis) when you don't need documents, contact info or amendment detection.

When `onlyNew: true` is on, an unchanged process is **never delivered and therefore never billed** — it is not created as a `result` or `result-summary` event at $0, it is simply not emitted at all, because the delta engine recognizes it as already-known (same estado, same `contentHash`) and skips it. The only unconditional cost on a quiet monitoring run is the one-time `apify-actor-start` fee. Per the README's worked examples: a daily monitor of AP + ET finding roughly 8 new tenders and 4 amendments a day costs about $0.04/day (~$1/month); a 500-record filtered pull with detail costs about $1.50; a listing-only pull of the entire ~31,000-process archive costs about $31 (about $93 with full detail).

***

*Written for the Apify Store listing of `stefano_seggio/santafe-compras-monitor` (Actor ID `jfoq1flE7KqKb3qAb`). All field names verified against this actor's own `.actor/input_schema.json` and `.actor/dataset_schema.json`; domain facts verified against `README.md` and `CHANGELOG.md` in the same repository.*

# Actor input Schema

## `estados` (type: `array`):

Which lists to read. AP = Para Apertura (published, offers not yet opened - where every new tender appears first), ET = En Trámite (opened, being evaluated - actas and preadjudicación land here), CO = Concluida (finished). Each is a separate server-side query.

## `anio` (type: `integer`):

Year of the process number (anioGestion). The site's own UI always applies the current year; leave empty for all years (2000 onwards).

## `objeto` (type: `string`):

Case-insensitive phrase search over the tender subject, e.g. 'limpieza', 'medicamentos', 'servicio de vigilancia'. Word order matters ('servicio de limpieza' matches, 'limpieza servicio' does not).

## `tipoGestion` (type: `array`):

One server-side query per selected type. Codes are the site's own (L = Licitación Pública, P = Licitación Privada, T = Contratación Directa, ...).

## `tipoModalidad` (type: `string`):

Contracting modality code from the site.

## `comprador` (type: `string`):

The organism running the procedure, as its site id (idOrganismoLey12510, e.g. 27) or a distinctive part of its name (e.g. 'Administración Provincial de Impuestos', 'Hospital Cullen'). Names are matched against the site's own organism list at run start; an ambiguous name fails with the candidates listed.

## `solicitante` (type: `string`):

The organism the purchase is for, same id space and name matching as 'Buyer' (e.g. 'Ministerio de Salud').

## `rubro` (type: `string`):

Product/service category, as the site's idEspecie (e.g. 29) or part of its name (e.g. 'medicinales', 'limpieza', 'alimentos'). Matched against the site's 78 rubros at run start.

## `subrubro` (type: `string`):

Sub-category within the selected rubro, as idFamilia or part of its name. Requires 'Category (rubro)'.

## `nroGestion` (type: `string`):

Exact process number as printed on the site, e.g. '18' or '02' (combine with the year: several organisms share the same numbering).

## `nroExpediente` (type: `string`):

Exact, full expediente number, e.g. 'EE-2026-00001797-APPSF-OD' (partial values match nothing on the site).

## `openingFrom` (type: `string`):

Only tenders whose bid opening (fecha de apertura) is on or after this date. Absolute (2026-09-01) or relative: '7 days' counts back from today, '+7 days' counts forward (Santa Fe calendar). Applied client-side after fetching the listing (the site has no date filter) - rows outside the window are simply skipped and not remembered.

## `openingTo` (type: `string`):

Only tenders opening on or before this date. Absolute or relative ('+30 days' = opening within the next month). Client-side.

## `eventTypes` (type: `array`):

NEW\_LISTING = a process never delivered before; STATUS\_CHANGE = a known process that moved to another estado (AP -> ET -> CO); UPDATED = a known open process whose detail page changed (a circular aclaratoria, an acta de apertura, a preadjudicación report, a new opening date...). The last two exist in delta mode only.

## `onlyNew` (type: `boolean`):

Remembers every process it has delivered (per filter set, in a named key-value store) with the estado it was in and a fingerprint of its detail page, and returns only processes that are new, moved to another estado, or were amended since. Each estado list is walked newest-first and stops as soon as it reaches already-known records.

## `recheckWindowDays` (type: `integer`):

Delta mode with detail: known processes whose opening date is within this many days in the past (or any time in the future) get their detail page re-read every run to detect amendments (UPDATED). The register shows no 'last modified' signal, so this re-read is the only way to see a new circular or acta. 0 disables it. Re-reads are not charged unless something changed.

## `sortBy` (type: `string`):

'newest' (idGestion descending = most recently created first) is required for delta mode. 'openingSoonest' / 'openingLatest' order by bid-opening date; 'mostViewed' by the site's own view counter (full runs only).

## `deltaStateName` (type: `string`):

Optional label for the memory of a monitoring task. Defaults to a fingerprint of your filters, so different schedules never interfere. Set the same name on two tasks to make them share one memory.

## `resetState` (type: `boolean`):

Forget every previously delivered process for this delta state and re-baseline (the run then returns up to 'Max records' newest processes).

## `maxItems` (type: `integer`):

Hard cap on delivered records (and therefore on cost: you pay per record). In delta mode anything beyond the cap is simply delivered by the next run.

## `fetchDetail` (type: `boolean`):

Opens each process page (one extra request) for the publication timestamp, budget (Monto Original), submission deadline, places, rubros, requesting organism, contact, expediente and the pliego / circular / acta / preadjudicación document links. Off = listing-only summary records (cheaper 'result-summary' price; no UPDATED detection and no status sweep).

## `maxConcurrency` (type: `integer`):

How many process pages are fetched at once. The site answers a page in 0.1-0.3 s and tolerated 10 in parallel without throttling; 5 is a polite default.

## `dateRange` (type: `string`):

Kept for tasks created with version 1: '24h', '7d' or '30d' are interpreted as an opening-date window of that many days before AND after today.

## Actor input object example

```json
{
  "estados": [
    "AP",
    "ET"
  ],
  "tipoGestion": [],
  "eventTypes": [
    "NEW_LISTING",
    "STATUS_CHANGE",
    "UPDATED"
  ],
  "onlyNew": true,
  "recheckWindowDays": 30,
  "sortBy": "newest",
  "resetState": false,
  "maxItems": 100,
  "fetchDetail": true,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `resultsNewestFirst` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `excel` (type: `string`):

No description

## `overview` (type: `string`):

No description

## `deadlines` (type: `string`):

No description

## `documents` (type: `string`):

No description

## `buyers` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# 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 = {
    "estados": [
        "AP",
        "ET"
    ],
    "onlyNew": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("stefano_seggio/santafe-compras-monitor").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 = {
    "estados": [
        "AP",
        "ET",
    ],
    "onlyNew": True,
}

# Run the Actor and wait for it to finish
run = client.actor("stefano_seggio/santafe-compras-monitor").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 '{
  "estados": [
    "AP",
    "ET"
  ],
  "onlyNew": true
}' |
apify call stefano_seggio/santafe-compras-monitor --silent --output-dataset

```

## MCP server setup

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

```

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/jfoq1flE7KqKb3qAb/builds/c502RbdIJ3tHJAgi3/openapi.json
