# Resource Booking Overlap Evidence Report (`h_murdock/resource-booking-overlap-audit`) Actor

Find same-resource booking and setup/teardown overlaps across normalized schedule exports. Keep every source row, flag conflicting booking identities and incomplete coverage. Mapped CSV or JSON with downloadable evidence; no calendar writes.

- **URL**: https://apify.com/h_murdock/resource-booking-overlap-audit.md
- **Developed by:** [Gilad Ronen](https://apify.com/h_murdock) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.25 / completed report

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?

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

### What does Resource Booking Overlap Evidence Report do?

Find **same-resource booking overlaps across exported schedules**, including conflicts caused only by setup or teardown time. Upload normalized JSON rows or paste mapped CSV from the systems you already use. The report shows the two source bookings, the precise shared interval, and the original input row references for each finding.

This is useful for facilities teams reviewing meeting rooms, venue operators checking revised schedules, or equipment coordinators comparing exports from more than one booking source. Run it at a daily or weekly handoff, or after a schedule revision. It works with a finite snapshot you provide through the Apify input form or API. No calendar connection or external model is needed.

### How to check a room or equipment booking export

1. Normalize each row to one opaque resource ID, one source ID and one booking ID. A booking using multiple resources needs one row per resource with distinct source booking identities; this Actor does not expand a multi-resource field.
2. Declare the exact resource IDs, source IDs, comparison window and snapshot coverage. Include relevant bookings and buffers crossing the window boundary.
3. Supply `bookings` as an array, including `[]` for an explicitly empty snapshot, or remove that array and supply `bookingsCsv`. Choose one format.
4. Run the Actor, inspect the summary and pair evidence, then download the full JSON, flat overlap CSV, identity findings CSV or standalone HTML.
5. Retain the export for review and run a new snapshot when the schedule changes.

The prefilled example includes a real overlap between two sources using the same booking ID, a harmless back-to-back booking, another resource and a cancelled booking. Replace the example with your own rows before using the result operationally.

### Input format and coverage

See the input tab for full configuration options. Each booking requires these fields:

| Field | Meaning |
| --- | --- |
| `sourceId`, `bookingId`, `resourceId` | Literal, nonempty opaque strings. Leading zeros and case are preserved. |
| `start`, `end` | Real RFC3339 instants with seconds and an explicit `Z` or numeric `±HH:mm` offset. Start must precede end. |
| `status` | Exactly `active` or `cancelled`. |
| `setupMinutes`, `teardownMinutes` | Explicit nonnegative integer minutes, each at most 1,440. Use zero where no buffer applies. |

Timestamps may contain one to three fractional second digits. Local times without an offset, unknown `-00:00` offsets, leap seconds, invalid dates, recurrence, all-day fields and extra fields are rejected. Convert recurring or all-day events to individual timed rows in your source system before exporting; the Actor does not guess a timezone or expand events.

`coverage` must be `complete`, `incomplete` or `unknown`. Complete means that the rows cover every declared resource and source throughout `[scopeStart,scopeEnd)`, including bookings whose setup or teardown enters the window. This is your statement about the snapshot; the Actor cannot independently establish export completeness. Unknown or incomplete coverage produces an unresolved finding even when no pair overlaps.

CSV accepts a UTF-8 BOM and standard quoting, including embedded commas. Quoted newlines are parsed, but values must pass the field rules: opaque IDs cannot contain newline or other control characters. The default headers are `sourceId,bookingId,resourceId,start,end,status,setupMinutes,teardownMinutes`. Supply `bookingColumns` to map every canonical field to a distinct export header. Only the eight mapped columns are accepted. Duplicate headers, missing columns, irregular records and ambiguous numeric cells fail validation. Header-only CSV is an explicitly empty snapshot. Remove the prefilled bookings array before entering CSV.

### How are overlaps calculated?

For an active booking, the effective interval is `[start - setupMinutes, end + teardownMinutes)`. The engine clips that interval to the declared window and compares it against distinct source-plus-booking identities on exactly the same resource. The end is exclusive: bookings that only touch are harmless unless their buffers overlap.

`booking_overlap` means the unbuffered booking intervals share time inside the window. `buffer_overlap` means only their expanded intervals share time. Output intervals use UTC and durations use integer milliseconds. Cancelled rows and active rows wholly outside the effective comparison window stay in the full evidence and counts but do not produce overlap pairs.

A booking identity is the exact pair of source ID and booking ID. The same booking ID in two sources is a separate identity. Identical repeated rows remain in the full evidence and compare once, with every row reference attached. If one identity has differing intervals, resources, status or buffers, every version stays visible and a conflicting identity finding is emitted. Pairs involving it have `unknown` severity. Such version pairs are evidence for review, rather than a count of confirmed distinct reservations. Multiple versions can therefore yield more than one evidence pair for the same two booking identities.

### Output and downloads

Each completed run produces one dataset item containing the complete report, a `rows` array of overlap evidence pairs, a `bookings` array preserving all input rows, and identity or coverage findings. The dataset overview exposes the compared row and version counts, cancellations, out of scope rows, booking and buffer pair counts, ambiguous pairs and declared scope.

| Download | Contents |
| --- | --- |
| Complete JSON (`OUTPUT`) | Full report, source rows, scope, rules and evidence. |
| `evidence.csv` | Flat overlap pairs, identifiers, UTC intervals, severity and source references. |
| `findings.csv` | Duplicate identity and coverage findings. |
| `report.html` | Standalone escaped report with all source rows. Download and open locally. |

You can also download the dataset using Apify's export formats such as JSON, CSV or Excel. For this nested report, the dedicated flat CSV is the clearest spreadsheet view. CSV cells beginning with spreadsheet formula prefixes are neutralized; complete JSON preserves the original identifiers.

### Cost, limits and recovery

The price is **$0.25 per completed report**, including platform usage. There is one `report-completed` event and no startup or per-dataset-item fee. Invalid input, excessive pair density and oversized exports fail before that report event. One new run of the same input is a new billable report.

Inputs are limited to 4 MB of serialized JSON and 2,000 booking rows. The report emits at most 10,000 overlap evidence pairs. Full JSON must be below 8 MB and each export below 9 MB. These limits apply together: repeated source evidence or long identifiers can reach an export size limit below 10,000 pairs. Split dense snapshots by a useful resource or time scope; avoid losing crossing buffers when splitting time windows. The default runtime is 1,024 MB and 180 seconds.

All exports are prepared and size-checked before publishing the dataset item and charging its event. An interrupted run can leave partial export files. Resuming the same run rewrites them and verifies the saved report and input before reuse; it keeps one dataset item and at most one completed-report charge. A run interrupted between saving the dataset and confirming the event may need recovery before it is considered complete. The separate downloads are not an atomic transaction.

### Scope, privacy and support

This report is finite exported schedule evidence for human review. It does not prevent live double bookings, write to calendars, optimize assignments, analyze staffing or legality, or guarantee a reservation. A `no_overlaps_in_declared_scope` result applies only to the declared complete snapshot. Use your booking system to resolve findings and enforce reservations.

Use opaque IDs and only data you are authorized to process. Do not include names, contact details or attendee information. Inputs and results remain in Apify cloud run storage according to your account's retention settings; the Actor does not delete them. It accepts no remote URLs, FTP, credentials or proxy settings. For validation errors, check field names, explicit timestamp offsets, scope membership and CSV mapping first. Use the Issues tab for feedback and the API tab for programmatic access.

# Actor input Schema

## `snapshotId` (type: `string`):

Caller snapshot reference; opaque literal string. No clock inference.

## `scopeStart` (type: `string`):

Explicit real RFC3339 instant: YYYY-MM-DDTHH:mm:ss\[.sss]Z or numeric ±HH:mm offset. Seconds required, at most millisecond precision. Reject local time, -00:00 unknown offset and leap seconds. The finite comparison window is \[scopeStart,scopeEnd).

## `scopeEnd` (type: `string`):

Explicit real RFC3339 instant: YYYY-MM-DDTHH:mm:ss\[.sss]Z or numeric ±HH:mm offset. Seconds required, at most millisecond precision. Reject local time, -00:00 unknown offset and leap seconds. The finite comparison window is \[scopeStart,scopeEnd).

## `resourceIds` (type: `array`):

Explicit nonempty list of unique opaque scope IDs. Every row must belong to the declared resources and sources. A complete coverage declaration covers all listed IDs and the full scope window, including boundary buffers.

## `sourceIds` (type: `array`):

Explicit nonempty list of unique opaque scope IDs. Every row must belong to the declared resources and sources. A complete coverage declaration covers all listed IDs and the full scope window, including boundary buffers.

## `coverage` (type: `string`):

Declare whether the supplied rows cover all listed resources and sources during the full window, including setup/teardown crossing its boundaries. Incomplete or unknown never produces a no-overlap conclusion.

## `bookings` (type: `array`):

Rows: sourceId, bookingId, resourceId, start, end, status (active/cancelled), setupMinutes and teardownMinutes (integers0–1440). All fields required, no extra fields. IDs are literal strings. Same source+booking identity conflicts are retained and flagged. Explicit \[] is allowed. Supply this array OR CSV; remove this array when using CSV. Max2000rows;4MB totalJSON;10000overlap pairs.

## `bookingsCsv` (type: `string`):

Alternative to bookings array: remove bookings when supplying nonempty CSV. Exact canonical headers unless mapping supplied. BOM and quoted fields accepted. Duplicate/unknown headers, irregular records, blank numeric cells and noncanonical integers are rejected. Header-only CSV means an explicitly empty snapshot.

## `bookingColumns` (type: `object`):

Optional mapping from EVERY canonical field (sourceId, bookingId, resourceId, start, end, status, setupMinutes, teardownMinutes) to a distinct CSV header. Omit for canonical headers. Canonical mapping is harmless with arrays; custom mapping requires bookingsCsv.

## Actor input object example

```json
{
  "snapshotId": "schedule-2026-10-02",
  "scopeStart": "2026-10-02T08:00:00+03:00",
  "scopeEnd": "2026-10-02T18:00:00+03:00",
  "resourceIds": [
    "room-01",
    "projector-01"
  ],
  "sourceIds": [
    "calendar-A",
    "calendar-B"
  ],
  "coverage": "complete",
  "bookings": [
    {
      "sourceId": "calendar-A",
      "bookingId": "001",
      "resourceId": "room-01",
      "start": "2026-10-02T09:00:00+03:00",
      "end": "2026-10-02T10:00:00+03:00",
      "status": "active",
      "setupMinutes": 0,
      "teardownMinutes": 0
    },
    {
      "sourceId": "calendar-B",
      "bookingId": "001",
      "resourceId": "room-01",
      "start": "2026-10-02T09:30:00+03:00",
      "end": "2026-10-02T10:30:00+03:00",
      "status": "active",
      "setupMinutes": 0,
      "teardownMinutes": 0
    },
    {
      "sourceId": "calendar-A",
      "bookingId": "002",
      "resourceId": "room-01",
      "start": "2026-10-02T10:30:00+03:00",
      "end": "2026-10-02T11:30:00+03:00",
      "status": "active",
      "setupMinutes": 0,
      "teardownMinutes": 0
    },
    {
      "sourceId": "calendar-A",
      "bookingId": "003",
      "resourceId": "projector-01",
      "start": "2026-10-02T09:00:00+03:00",
      "end": "2026-10-02T10:00:00+03:00",
      "status": "active",
      "setupMinutes": 0,
      "teardownMinutes": 0
    },
    {
      "sourceId": "calendar-B",
      "bookingId": "004",
      "resourceId": "room-01",
      "start": "2026-10-02T09:00:00+03:00",
      "end": "2026-10-02T12:00:00+03:00",
      "status": "cancelled",
      "setupMinutes": 0,
      "teardownMinutes": 0
    }
  ],
  "bookingColumns": {
    "sourceId": "sourceId",
    "bookingId": "bookingId",
    "resourceId": "resourceId",
    "start": "start",
    "end": "end",
    "status": "status",
    "setupMinutes": "setupMinutes",
    "teardownMinutes": "teardownMinutes"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

One complete report containing overlap pairs, every booking source row, identity findings and coverage.

## `json` (type: `string`):

No description

## `evidence` (type: `string`):

No description

## `findings` (type: `string`):

No description

## `html` (type: `string`):

Escaped standalone HTML; download and open locally.

# 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 = {
    "snapshotId": "schedule-2026-10-02",
    "scopeStart": "2026-10-02T08:00:00+03:00",
    "scopeEnd": "2026-10-02T18:00:00+03:00",
    "resourceIds": [
        "room-01",
        "projector-01"
    ],
    "sourceIds": [
        "calendar-A",
        "calendar-B"
    ],
    "coverage": "complete",
    "bookings": [
        {
            "sourceId": "calendar-A",
            "bookingId": "001",
            "resourceId": "room-01",
            "start": "2026-10-02T09:00:00+03:00",
            "end": "2026-10-02T10:00:00+03:00",
            "status": "active",
            "setupMinutes": 0,
            "teardownMinutes": 0
        },
        {
            "sourceId": "calendar-B",
            "bookingId": "001",
            "resourceId": "room-01",
            "start": "2026-10-02T09:30:00+03:00",
            "end": "2026-10-02T10:30:00+03:00",
            "status": "active",
            "setupMinutes": 0,
            "teardownMinutes": 0
        },
        {
            "sourceId": "calendar-A",
            "bookingId": "002",
            "resourceId": "room-01",
            "start": "2026-10-02T10:30:00+03:00",
            "end": "2026-10-02T11:30:00+03:00",
            "status": "active",
            "setupMinutes": 0,
            "teardownMinutes": 0
        },
        {
            "sourceId": "calendar-A",
            "bookingId": "003",
            "resourceId": "projector-01",
            "start": "2026-10-02T09:00:00+03:00",
            "end": "2026-10-02T10:00:00+03:00",
            "status": "active",
            "setupMinutes": 0,
            "teardownMinutes": 0
        },
        {
            "sourceId": "calendar-B",
            "bookingId": "004",
            "resourceId": "room-01",
            "start": "2026-10-02T09:00:00+03:00",
            "end": "2026-10-02T12:00:00+03:00",
            "status": "cancelled",
            "setupMinutes": 0,
            "teardownMinutes": 0
        }
    ],
    "bookingsCsv": "",
    "bookingColumns": {
        "sourceId": "sourceId",
        "bookingId": "bookingId",
        "resourceId": "resourceId",
        "start": "start",
        "end": "end",
        "status": "status",
        "setupMinutes": "setupMinutes",
        "teardownMinutes": "teardownMinutes"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("h_murdock/resource-booking-overlap-audit").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 = {
    "snapshotId": "schedule-2026-10-02",
    "scopeStart": "2026-10-02T08:00:00+03:00",
    "scopeEnd": "2026-10-02T18:00:00+03:00",
    "resourceIds": [
        "room-01",
        "projector-01",
    ],
    "sourceIds": [
        "calendar-A",
        "calendar-B",
    ],
    "coverage": "complete",
    "bookings": [
        {
            "sourceId": "calendar-A",
            "bookingId": "001",
            "resourceId": "room-01",
            "start": "2026-10-02T09:00:00+03:00",
            "end": "2026-10-02T10:00:00+03:00",
            "status": "active",
            "setupMinutes": 0,
            "teardownMinutes": 0,
        },
        {
            "sourceId": "calendar-B",
            "bookingId": "001",
            "resourceId": "room-01",
            "start": "2026-10-02T09:30:00+03:00",
            "end": "2026-10-02T10:30:00+03:00",
            "status": "active",
            "setupMinutes": 0,
            "teardownMinutes": 0,
        },
        {
            "sourceId": "calendar-A",
            "bookingId": "002",
            "resourceId": "room-01",
            "start": "2026-10-02T10:30:00+03:00",
            "end": "2026-10-02T11:30:00+03:00",
            "status": "active",
            "setupMinutes": 0,
            "teardownMinutes": 0,
        },
        {
            "sourceId": "calendar-A",
            "bookingId": "003",
            "resourceId": "projector-01",
            "start": "2026-10-02T09:00:00+03:00",
            "end": "2026-10-02T10:00:00+03:00",
            "status": "active",
            "setupMinutes": 0,
            "teardownMinutes": 0,
        },
        {
            "sourceId": "calendar-B",
            "bookingId": "004",
            "resourceId": "room-01",
            "start": "2026-10-02T09:00:00+03:00",
            "end": "2026-10-02T12:00:00+03:00",
            "status": "cancelled",
            "setupMinutes": 0,
            "teardownMinutes": 0,
        },
    ],
    "bookingsCsv": "",
    "bookingColumns": {
        "sourceId": "sourceId",
        "bookingId": "bookingId",
        "resourceId": "resourceId",
        "start": "start",
        "end": "end",
        "status": "status",
        "setupMinutes": "setupMinutes",
        "teardownMinutes": "teardownMinutes",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("h_murdock/resource-booking-overlap-audit").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 '{
  "snapshotId": "schedule-2026-10-02",
  "scopeStart": "2026-10-02T08:00:00+03:00",
  "scopeEnd": "2026-10-02T18:00:00+03:00",
  "resourceIds": [
    "room-01",
    "projector-01"
  ],
  "sourceIds": [
    "calendar-A",
    "calendar-B"
  ],
  "coverage": "complete",
  "bookings": [
    {
      "sourceId": "calendar-A",
      "bookingId": "001",
      "resourceId": "room-01",
      "start": "2026-10-02T09:00:00+03:00",
      "end": "2026-10-02T10:00:00+03:00",
      "status": "active",
      "setupMinutes": 0,
      "teardownMinutes": 0
    },
    {
      "sourceId": "calendar-B",
      "bookingId": "001",
      "resourceId": "room-01",
      "start": "2026-10-02T09:30:00+03:00",
      "end": "2026-10-02T10:30:00+03:00",
      "status": "active",
      "setupMinutes": 0,
      "teardownMinutes": 0
    },
    {
      "sourceId": "calendar-A",
      "bookingId": "002",
      "resourceId": "room-01",
      "start": "2026-10-02T10:30:00+03:00",
      "end": "2026-10-02T11:30:00+03:00",
      "status": "active",
      "setupMinutes": 0,
      "teardownMinutes": 0
    },
    {
      "sourceId": "calendar-A",
      "bookingId": "003",
      "resourceId": "projector-01",
      "start": "2026-10-02T09:00:00+03:00",
      "end": "2026-10-02T10:00:00+03:00",
      "status": "active",
      "setupMinutes": 0,
      "teardownMinutes": 0
    },
    {
      "sourceId": "calendar-B",
      "bookingId": "004",
      "resourceId": "room-01",
      "start": "2026-10-02T09:00:00+03:00",
      "end": "2026-10-02T12:00:00+03:00",
      "status": "cancelled",
      "setupMinutes": 0,
      "teardownMinutes": 0
    }
  ],
  "bookingsCsv": "",
  "bookingColumns": {
    "sourceId": "sourceId",
    "bookingId": "bookingId",
    "resourceId": "resourceId",
    "start": "start",
    "end": "end",
    "status": "status",
    "setupMinutes": "setupMinutes",
    "teardownMinutes": "teardownMinutes"
  }
}' |
apify call h_murdock/resource-booking-overlap-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,h_murdock/resource-booking-overlap-audit"
        }
    }
}
```

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/RJ9Cfk0ALXfMGVut6/builds/8nmXPBkBWHA4WACsm/openapi.json
