# Start forecasting

Use your historic attendance data to generate AI-driven forecasts for people, teams, and locations, helping predict future space needs.

{% tabs %}
{% tab title="Node.js" %}

### Prerequisites

* Completed **Add historic attendance** (including session finish if you batched)
* Node.js v18+ and npm v9+
* A valid gospace API key in your `.env` file
* At least one populated **location** with historic occupancy data

{% hint style="info" %}
**Note:** Any fields ending with `_inc` include adjustments for minimum targets, people intentions (bookings), and contingencies.
{% endhint %}

***

### 1) Trigger a forecast run

If your project is configured for automatic rebuilds, you can skip this step. Otherwise, trigger forecasting explicitly.

Create `start-forecast.ts`:

```ts
import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  // Kick off a forecast rebuild for a location and optional date range
  const res = await gospace.system.startForecast({
    location_id: "68499cf4af8729934aae208a",
    // Optional time window. If omitted, backend will choose sensible defaults.
    // starts_at: "2025-06-20T00:00:00Z",
    // ends_at: "2025-07-31T23:59:59Z",
    // Optional control flags
    // force_rebuild: true
  });

  console.log(JSON.stringify(res.data, null, 2));
  // Expect a job or task identifier you can poll
}

main().catch((err) => {
  console.error("Start forecast failed:", err);
  process.exit(1);
});
```

***

### 2) (Optional) Poll job status

If `startForecast` returns a job, poll until it’s complete.

```ts
import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

const JOB_ID = "your_forecast_job_id";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  for (;;) {
    const status = await gospace.system.getForecastJob({ job_id: JOB_ID });
    console.log(status.data.state);
    if (status.data.state === "completed") break;
    if (status.data.state === "failed") throw new Error("Forecast job failed");
    await new Promise((r) => setTimeout(r, 3000));
  }

  console.log("Forecast ready.");
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});
```

***

### 3) Fetch forecasts

#### A) People forecast (per person, optionally scoped to team)

Create `get-people-forecast.ts`:

```ts
import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  const res = await gospace.system.getPeopleForecast({
    location_id: "68499cf4af8729934aae208a",
    // Optional filters:
    // people_id: "68518a559c86c18f01ee84e4",
    // team_id: "68518a549c86c18f01ee84b0",
    starts_at: "2025-06-29T23:00:00Z",
    ends_at: "2025-07-07T22:59:00Z",
    skip: 0,
    limit: 25,
  });

  // Example shape (truncated):
  // {
  //   success: true,
  //   data: { forecast: [ { starts_at, ends_at, location_id, people_id, team_id, forecasted_desk, forecasted_room, forecasted_total }, ... ] },
  //   pagination: { current_results: { from, to }, total_results },
  //   identifier: "get_forecast_successful"
  // }

  console.log(JSON.stringify(res.data, null, 2));
}

main().catch((err) => {
  console.error("Get people forecast failed:", err);
  process.exit(1);
});
```

#### B) Team forecast (aggregated by team)

Create `get-team-forecast.ts`:

```ts
import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  const res = await gospace.system.getTeamForecast({
    location_id: "68499cf4af8729934aae208a",
    starts_at: "2025-06-20T23:00:00Z",
    ends_at: "2025-06-22T22:59:00Z",
    skip: 0,
    limit: 25,
  });

  // Records include *_inc fields:
  // forecasted_desks, forecasted_rooms, forecasted_total,
  // forecasted_desks_inc, forecasted_rooms_inc, forecasted_total_inc

  console.log(JSON.stringify(res.data, null, 2));
}

main().catch((err) => {
  console.error("Get team forecast failed:", err);
  process.exit(1);
});
```

#### C) Location forecast (location‑level totals)

Create `get-location-forecast.ts`:

```ts
import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  const res = await gospace.system.getLocationForecast({
    location_id: "68499cf4af8729934aae208a",
    starts_at: "2025-06-20T23:00:00Z",
    ends_at: "2025-07-23T22:59:00Z",
    skip: 0,
    limit: 25,
  });

  // Records include *_inc fields for adjusted capacity planning.

  console.log(JSON.stringify(res.data, null, 2));
}

main().catch((err) => {
  console.error("Get location forecast failed:", err);
  process.exit(1);
});
```

***

### 4) Turn forecasts into capacity requirements

#### Daily desk and room requirements (using \*\_inc)

```ts
type LocationForecast = {
  starts_at: string;
  ends_at: string;
  location_id: string;
  forecasted_desks_inc: number;
  forecasted_rooms_inc: number;
  forecasted_total_inc: number;
};

function summarizeCapacity(rows: LocationForecast[]) {
  return rows.reduce(
    (acc, r) => {
      acc.maxDesks = Math.max(acc.maxDesks, r.forecasted_desks_inc);
      acc.maxRooms = Math.max(acc.maxRooms, r.forecasted_rooms_inc);
      acc.maxTotal = Math.max(acc.maxTotal, r.forecasted_total_inc);
      return acc;
    },
    { maxDesks: 0, maxRooms: 0, maxTotal: 0 }
  );
}

// Example usage:
// const summary = summarizeCapacity(res.data.forecast);
// console.log(summary); // { maxDesks, maxRooms, maxTotal }
```

#### Aggregating per‑team to size team neighborhoods

```ts
type TeamForecast = {
  team_id: string;
  starts_at: string;
  forecasted_desks_inc: number;
};

function peakPerTeam(rows: TeamForecast[]) {
  const map = new Map<string, number>();
  for (const r of rows) {
    map.set(r.team_id, Math.max(map.get(r.team_id) ?? 0, r.forecasted_desks_inc));
  }
  return map; // team_id -> peak desks required
}
```

#### Checking person‑level confidence

Use people forecasts to validate outliers (e.g., unexpected spikes for specific individuals or teams) before making seating or room allocation changes.

***

### Tips

* Use `_inc` fields to plan **for the real world** (targets, bookings, contingencies).
* Choose consistent **day boundaries** (`starts_at`/`ends_at`) that match your business day/timezone.
* Use pagination (`skip`, `limit`) to iterate long horizons.
* Rebuild forecasts after **significant new history** or **policy changes** (e.g., new minimum targets).
  {% endtab %}
  {% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developer.gospace.com/start-building/start-forecasting.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
