# NYC Government Contracts & Procurement - Awards & Solicitations (`j0401/nyc-contracts`) Actor

New York City contract awards (53,868) and open solicitations (45,257) from the Office of Citywide Procurement (public open data). Search by agency, vendor, PIN, category or date; look up one notice; or aggregate awards by agency or category. The historical bid tabulations are a third corpus.

- **URL**: https://apify.com/j0401/nyc-contracts.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 nyc contract records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## NYC Government Contracts & Procurement - Awards & Solicitations

New York City's own procurement register: **~53,900 contract awards** and
**~45,300 open solicitations** from the Office of Citywide Procurement, plus the
historical **bid tabulations**. Who the city awarded, to which vendor, for how
much - and what is open for bids right now, and until when.

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold.** Pay only for the records
you actually receive - the whole register stays queryable, and you are never
billed for the scan behind it.

### Three registers, one shape

- **`awards`** (default) - contracts NYC has awarded: agency, vendor, amount,
  PIN, selection method, start date. ~53,900 awards back to 2003.
- **`solicitations`** - open requests for bids and proposals: agency, category,
  the PIN, and the **response due date**. ~45,300 notices.
- **`bids`** - the bid tabulations: which bidder priced which line item and at
  what price. 57,704 lines. This table is **frozen** - its most recent bid dates
  to 2021 and it was last updated in 2023; it is a historical pricing register.

### Find awards and opportunities

- **Agency** - `agency="Parks"`, `"Police"`, `"Sanitation"`.
- **Vendor** - `vendor="Dell"` (awards only).
- **Category** - `category` is one of 6 (Goods, Services, Construction ).
- **Method** - `selectionMethod="Sole Source"`, `"Request for Proposals"`.
- **When** - `dateFrom` / `dateTo` (start), `dueFrom` / `dueTo` (deadline).
- **How much** - `minAmount` / `maxAmount` (awards).

```json
{ "corpus": "solicitations", "category": "Construction/Construction Services",
  "dueFrom": "2026-11-01", "maxResults": 50 }
```

```json
{ "corpus": "awards", "vendor": "Dell", "minAmount": 100000, "maxResults": 50 }
```

### Look up one notice

`mode=record` returns a single notice by its request id (or the bid number for
the bids corpus):

```json
{ "mode": "record", "requestId": "20261005010" }
```

### Or roll it up

`mode=aggregate` returns one count row per group - **agency**, **category**,
**selection method** or **year**. Every group comes back; this mode is not cut
off by `maxResults`.

```json
{ "corpus": "awards", "aggregate": true, "groupBy": "agency" }
```

```
Citywide Administrative Services                13,350
Health and Mental Hygiene                        5,368
Dept. of Social Svcs/Human Resources Administration   4,353
```

### Example output

**One award** - `mode=record`, `corpus=awards`:

```json
{
 "platform": "nyc-contracts",
 "corpus": "awards",
 "requestId": "20261005010",
 "pin": "05625U0007001R001",
 "agencyName": "Police Department",
 "category": "Services (other than human services)",
 "selectionMethod": "Renewal",
 "shortTitle": "Training for Forensic Interviewing",
 "contractAmount": "213940",
 "vendorName": "National Children's Advocacy Center",
 "startDate": "2026-10-09",
 "mode": "record"
}
```

### Notes on the data, from the source

- **One row = one procurement notice** (one award or one solicitation). The
  request id is unique on each table.
- **A solicitation has no vendor yet** - that is why `vendor` applies to awards
  only; ask for it against solicitations and the actor says so rather than
  returning nothing.
- **The award amount is populated on ~15% of solicitations** (an estimate) and
  on most awards. Blank means the source did not state one.
- **`due_date` is blank when the source has no deadline** (the source stores a
  far-future placeholder such as 2099-12-31); it is never shown as a real date,
  and a `dueFrom` / `dueTo` filter excludes those open-ended records.
- **The event-location columns in the source are empty** on essentially every
  row, so they are not published. The real submission address is
  `addressToRequest`, present on 96% of solicitations.
- **The registers refresh daily.** Awards and solicitations go back to 2003; the
  bid tabulations stopped in 2023.

# Actor input Schema

## `corpus` (type: `string`):

awards = contracts NYC has awarded (~53,900, has vendor + amount). solicitations = open requests for bids/proposals (~45,300, has due date). bids = historical bid tabulations (which bidder priced which line item) - NOTE: frozen; its newest bid dates to 2021, last updated 2023.

## `mode` (type: `string`):

search = filter notices. record = one notice by requestId (or bidNumber for bids). aggregate = one row per group with a count. Blank auto-routes.

## `requestId` (type: `string`):

With mode=record: the procurement request id, e.g. "20261005010" (awards / solicitations), or the bid number for the bids corpus.

## `agency` (type: `string`):

Agency name contains (e.g. "Parks", "Police", "Sanitation"). Awards & solicitations only.

## `vendor` (type: `string`):

Awarded vendor name contains (e.g. "Dell"). Awards only - solicitations have no vendor yet.

## `bidder` (type: `string`):

Bidder name contains (bids corpus only).

## `pin` (type: `string`):

Exact procurement PIN (awards / solicitations only), e.g. "82727W0007001".

## `bidNumber` (type: `string`):

Exact bid number (bids corpus only).

## `category` (type: `string`):

Procurement category. Blank = all. Awards & solicitations only.

## `selectionMethod` (type: `string`):

Selection method contains (e.g. "Sole Source", "Request for Proposals", "Competitive Sealed Bids"). Awards & solicitations only.

## `title` (type: `string`):

Short title contains (e.g. "environmental", "records").

## `dateFrom` (type: `string`):

Notice start date lower bound, ISO YYYY-MM-DD (e.g. "2026-01-01").

## `dateTo` (type: `string`):

Notice start date upper bound, ISO YYYY-MM-DD.

## `dueFrom` (type: `string`):

Response due-date lower bound, ISO YYYY-MM-DD (solicitations).

## `dueTo` (type: `string`):

Response due-date upper bound, ISO YYYY-MM-DD (solicitations).

## `minAmount` (type: `number`):

Minimum contract amount (USD), awards only.

## `maxAmount` (type: `number`):

Maximum contract amount (USD), awards only.

## `aggregate` (type: `boolean`):

When on, returns one summary record per group with a count, instead of notices.

## `groupBy` (type: `string`):

Blank = a default dimension for the selected dataset. agency / category / selectionMethod / year (awards & solicitations); the bids corpus only supports year.

## `maxResults` (type: `integer`):

Cap the number of records pushed (0 = a default of 50).

## Actor input object example

```json
{
  "corpus": "awards",
  "aggregate": false,
  "groupBy": "",
  "maxResults": 50
}
```

# Actor output Schema

## `recordsUrl` (type: `string`):

NYC contract awards, solicitations and bid records - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/nyc-contracts").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/nyc-contracts").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 '{}' |
apify call j0401/nyc-contracts --silent --output-dataset

```

## MCP server setup

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

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/cOeT8rrPzsssD5pNV/builds/9yQeaAI4IsAnnQN0G/openapi.json
