# Goodmoves.org Jobs Scraper (`memo23/goodmoves-scraper`) Actor

Scrape Scottish charity-sector job postings from Goodmoves.org — title, salary, workplace type, employer, posted/closing dates with time, full description, real lat/lng coordinates, OSCR charity number and apply email or apply URL. Works with any listing or vacancy URL. JSON or CSV out.

- **URL**: https://apify.com/memo23/goodmoves-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Jobs, Automation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.90 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Goodmoves.org Scraper

**Turn Goodmoves.org into structured Scottish charity-sector job data.** Scrape every vacancy from any Goodmoves listing URL — title, salary band, workplace type, employer, posted/closing dates with time, full description, location with real lat/long coordinates, OSCR charity number, apply email + apply URL — straight out of the page. JSON or CSV out, no compute charge per run, just per result.

#### How it works

![How Goodmoves Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-goodmoves.png)

#### ✨ Why use this scraper?

Tracking Scottish third-sector hiring? Building salary benchmarks across SCVO-listed charities? Need a clean dataset of charity vacancies without scrolling Goodmoves manually?

- 🎯 **Two starting points.** Paste a Goodmoves listing URL (`/jobs-in/{location}`, `/search?...`, `/browse/...`) or a direct vacancy URL — both classified automatically.
- 📋 **JSON-LD–backed accuracy.** Title, salary, location, dates, employment type, full description, and the org's address all come from the page's `application/ld+json` block — same data Google reads.
- 📍 **Real coordinates, not just postcodes.** Each row carries `coordinates.latitude` + `coordinates.longitude` parsed directly from the embedded map marker.
- 🏛 **OSCR charity numbers.** Each row includes the Scottish Charity Register number (e.g. `SC039119`) — perfect for joining to OSCR's open dataset.
- 📧 **Apply email + apply URL captured.** The "Application notes" section yields the recruiter's mailto and any outbound application page — no resolver step needed.
- 🧰 **No anti-bot, no auth, no pagination.** A Goodmoves listing returns every match in one HTTP call. Listings + 80 vacancy pages typically scrape in well under a minute.
- 📤 **Clean exports.** One row per vacancy with org enrichment merged in. No duplicate rows. JSON + CSV exported automatically.

#### 🎯 Use cases

| Team | What they build |
|------|-----------------|
| **Scottish recruitment / agencies** | Daily new-vacancy feeds for the SCVO/Goodmoves audience, sliced by region or sector |
| **Charity-sector analysts** | Hiring-trend dashboards for Scotland's third sector |
| **Compensation & benefits** | Salary benchmarks for charity roles by region, contract type, and employer size |
| **Talent acquisition (in-house)** | Competitive intelligence on what other Scottish charities are paying |
| **Researchers / journalists** | Datasets on workforce shifts in the Scottish voluntary sector |
| **OSCR data joiners** | Vacancy data joined to the Scottish Charity Register via `oscrCharityNumber` |

#### 📥 Supported inputs

You can pass two kinds of URL in `startUrls`. Each URL is classified automatically.

| URL pattern | Behaviour |
|---|---|
| `https://goodmoves.org/jobs-in/{location}` | **Listing** — extracts every vacancy link in one HTTP call (no pagination) |
| `https://goodmoves.org/search?keywords=...&location=...` | **Listing** (search results) |
| `https://goodmoves.org/browse/...` | **Listing** (any browse facet) |
| `https://goodmoves.org/vacancy/{salesforce-id}/{slug}` | **Vacancy detail** — routed straight to the parser |

Easiest workflow: apply your filters on goodmoves.org in the browser (location, sector, contract type, salary, workplace), copy the URL out of the address bar, paste into `startUrls`.

**Not supported:**

- Organisation profile URLs as a starting point (they're fetched automatically as enrichment when org enrichment is on)
- Hosts outside `goodmoves.org` / `www.goodmoves.org`

#### 🔄 How it works

1. **Classify each `startUrl`** as a listing URL or a single vacancy URL.
2. **Fetch each listing** — Goodmoves returns every match on one page, so no pagination loop.
3. **Fetch each vacancy detail page** in parallel via a global sliding window.
4. **Parse the JSON-LD `JobPosting` block** for the bulk of structured data, and the page's "Application notes" section for the apply email + apply URL.
5. **Optionally enrich each unique organisation** by fetching `/organisation/{id}/{slug}` once for the company website, domain, and OSCR charity number. Cached per slug — every job for that org reuses the same fetch.
6. **Push one merged row per vacancy** to the dataset and export `data.csv` + `data.json` at the end.

#### ⚙️ Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | `["https://goodmoves.org/jobs-in/glasgow"]` | Goodmoves listing URLs and/or vacancy URLs. Mix both freely. |
| `enrichOrganisation` | boolean | `true` | Fetch each unique organisation profile once for `companyWebsite`, `companyDomain`, and `oscrCharityNumber`. The vacancy JSON-LD already contains the company description, so disable this if you want maximum speed and don't need website/domain/OSCR. |
| `maxItems` | integer | `1000` | Hard cap on jobs collected. Goodmoves listings often return 80+ vacancies in one page; this cap limits billing. |
| `maxConcurrency` / `minConcurrency` | integer | `10` / `1` | Parallel HTTP request limits. |
| `maxRequestRetries` | integer | `5` | Retries before a request is given up. |
| `proxy` | object | Apify residential | Apify proxy configuration. Goodmoves has no anti-bot, so a small pool (or no proxy) usually works. |

#### 📊 Output overview

Each scraped vacancy is one **single dataset row** of `type: "job"`. When `enrichOrganisation` is `true`, the organisation's website, domain and OSCR charity number are merged into the same row — no separate organisation rows, so the dataset row count equals the job count exactly.

#### 📦 Output sample

One merged row per vacancy (trimmed to the most useful fields):

```json
{
    "type": "job",
    "jobId": "a4sP1000001g24rIAA",
    "salesforceId": "a4sP1000001g24rIAA",
    "jobUrl": "https://goodmoves.org/vacancy/a4sP1000001g24rIAA/head-of-communications",
    "title": "Head of Communications",
    "companyName": "Sistema Scotland",
    "companyProfileUrl": "https://goodmoves.org/organisation/0010N000044qNHSQA2/sistema-scotland",
    "organisationSlug": "sistema-scotland",
    "logoUrl": "https://storage.googleapis.com/elasticsauce.appspot.com/goodmoves-files/...png",
    "location": "Hybrid working between our Big Noise centres and home working ...",
    "streetAddress": "Big Noise centre",
    "postcode": "FK8 1RD",
    "addressLocality": "Stirling",
    "addressRegion": "Stirling",
    "country": "Scotland",
    "coordinates": { "latitude": 56.129547, "longitude": -3.945531 },
    "workplaceType": "Hybrid",
    "salary": {
        "currency": "GBP",
        "min": 50296,
        "max": 54266,
        "value": "£50296 – £54266 pro-rata",
        "unit": "YEAR",
        "raw": "£50,296 – £54,266 pro-rata"
    },
    "employmentType": ["Part time"],
    "workHours": "(new staff start on the bottom point of the scale) 21 hours per week.",
    "qualifications": null,
    "responsibilities": null,
    "skills": null,
    "industry": ["Marketing/PR", "Communications"],
    "occupationalCategory": ["Communications", "Marketing"],
    "postedDate": "2026-04-27T13:51:34",
    "closingDate": "2026-05-11T22:59:00",
    "closingDateLabel": "Closing 11th May 2026",
    "description": "Sistema Scotland's vision is to improve lives and strengthen communities... (full text)",
    "applicationNotes": "<p>Please apply by ...</p> ... (HTML)",
    "applyType": "email",
    "applyUrl": "https://goodmoves.org/vacancy/a4sP1000001g24rIAA/head-of-communications",
    "applyEmail": "recruitment@sistemascotland.org.uk",
    "externalApplyUrl": "http://www.makeabignoise.org.uk/work-with-us",
    "companyDescription": "Sistema Scotland is a registered charity working to transform...",
    "companyHeadquarters": { "postcode": "FK8 1RD", "country": "Scotland" },
    "companyWebsite": "https://www.makeabignoise.org.uk/sistema-scotland/",
    "companyDomain": "makeabignoise.org.uk",
    "oscrCharityNumber": "SC039119",
    "ogImage": "https://storage.googleapis.com/elasticsauce.appspot.com/goodmoves-files/...png",
    "scrapedAt": "2026-05-08T22:11:14.221Z"
}
````

#### 🗂 Key output fields

| Group | Fields |
|---|---|
| **Identifiers** | `type`, `jobId` / `salesforceId` (Goodmoves' own 18-char Salesforce ID), `jobUrl`, `scrapedAt` |
| **Role** | `title`, `description` (plain text), `applicationNotes` (HTML), `industry[]`, `occupationalCategory[]` |
| **Dates** | `postedDate` (ISO datetime), `closingDate` (ISO datetime including time of day), `closingDateLabel` (human-readable) |
| **Employer** | `companyName`, `companyProfileUrl`, `organisationSlug`, `organisationSalesforceId`, `logoUrl` |
| **Location** | `location` (display string), `streetAddress`, `postcode`, `addressLocality`, `addressRegion`, `country`, `coordinates.{latitude,longitude}`, `workplaceType` (`On-site` / `Hybrid` / `Remote`) |
| **Compensation** | `salary.{currency,min,max,value,unit,raw}`, `employmentType[]`, `workHours` |
| **Apply flow** | `applyType` (`email` / `external` / `unknown`), `applyUrl` (the Goodmoves page), `applyEmail` (recruiter mailto when present), `externalApplyUrl` (recruiter site when present) |
| **Company enrichment** *(merged into the same row when `enrichOrganisation: true`)* | `companyDescription`, `companyWebsite`, `companyDomain`, `companyHeadquarters.{postcode,country}`, `oscrCharityNumber` (Scottish Charity Register, e.g. `SC039119`) |

#### ❓ FAQ

**Which Goodmoves URLs are supported?**
Listing URLs (`/jobs-in/...`, `/search?...`, `/browse/...`) and direct vacancy URLs (`/vacancy/{id}/{slug}`). Organisation pages used as starting points and any host outside `goodmoves.org` are skipped.

**Why are most jobs `applyType: "email"` or `"external"` and never `"internal"`?**
Goodmoves doesn't host applications itself — every vacancy directs candidates either to the recruiter's email (most common in the Scottish charity sector) or to the recruiter's own careers page. The actor captures both.

**What's `oscrCharityNumber` and where does it come from?**
It's the official Scottish Charity Register identifier (e.g. `SC012838`). Goodmoves links each org's profile to OSCR's register, and we extract the number from that link. You can join it to OSCR's open dataset for accreditation, financials, and trustees.

**Do I need to paginate?**
No. Goodmoves returns every matching vacancy on a single listing page, so the actor makes one HTTP call per listing URL plus one per vacancy detail.

**Can I scrape private pages or applicant data?**
No. The scraper accesses only publicly available pages — no logged-in content, no recruiter-only views, no candidate data.

**How do I limit results?**
Set `maxItems`. The actor stops queuing new vacancies as soon as the cap is reached.

#### 💬 Support

- For issues or feature requests, please use the **Issues** tab on the actor's Apify Console page.
- Author's website: <https://muhamed-didovic.github.io/>
- Email: <muhamed.didovic@gmail.com>

#### 🛠 Additional services

- Custom output shape, additional fields, or one-off datasets: <muhamed.didovic@gmail.com>
- Need a similar scraper for other UK or regional job boards (CharityJob, S1 Jobs, TotalJobs, etc.)? Drop an email.
- For API access (no Apify fee, just a usage fee for the API): <muhamed.didovic@gmail.com>

#### 🔎 Explore more scrapers

If this Goodmoves Scraper was useful, see other scrapers and actors at [memo23's Apify profile](https://apify.com/memo23) — covering job boards, real estate, social media, and more.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Goodmoves, the Scottish Council for Voluntary Organisations (SCVO), or any of their subsidiaries or affiliates. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available vacancy and organisation-profile pages on goodmoves.org — no authenticated endpoints, recruiter-only features, or content behind a Goodmoves login. Users are responsible for ensuring their use complies with goodmoves.org's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organisation.

***

### SEO Keywords

goodmoves scraper, scrape goodmoves, goodmoves api, goodmoves.org scraper, Apify goodmoves, scottish charity jobs scraper, scotland charity jobs api, scvo jobs scraper, third sector scotland scraper, scottish nonprofit jobs data, charity sector scotland hiring data, scottish voluntary sector jobs, oscr charity register data, scottish charity jobs salary benchmark, scotland third sector recruitment, scottish nonprofit talent pipeline, scottish charity vacancies, glasgow charity jobs scraper, edinburgh charity jobs scraper, charityjob alternative scraper, s1 jobs alternative scraper

# Actor input Schema

## `startUrls` (type: `array`):

Full goodmoves.org URLs to crawl. Mix listing and vacancy URLs in the same array if useful.

## `enrichOrganisation` (type: `boolean`):

When enabled, each unique organisation profile is fetched once to add `companyWebsite`, `companyDomain`, and `oscrCharityNumber`. The vacancy JSON-LD already contains the company description, so disable this if you only need the description and want to skip the extra HTTP calls.

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

Hard cap on the number of jobs collected. Goodmoves listings often return 80+ vacancies in a single page; use this cap to limit billing.

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

Maximum number of vacancy pages processed in parallel.

## `minConcurrency` (type: `integer`):

Minimum number of vacancy pages processed in parallel.

## `maxRequestRetries` (type: `integer`):

Number of retries before a failed request is given up.

## `proxy` (type: `object`):

Apify proxy settings. Goodmoves has no anti-bot, so a small residential pool (or even no proxy) usually works fine.

## Actor input object example

```json
{
  "startUrls": [
    "https://goodmoves.org/jobs-in/glasgow"
  ],
  "enrichOrganisation": true,
  "maxItems": 1000,
  "maxConcurrency": 10,
  "minConcurrency": 1,
  "maxRequestRetries": 5,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "startUrls": [
        "https://goodmoves.org/jobs-in/glasgow"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/goodmoves-scraper").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 = {
    "startUrls": ["https://goodmoves.org/jobs-in/glasgow"],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/goodmoves-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://goodmoves.org/jobs-in/glasgow"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call memo23/goodmoves-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=memo23/goodmoves-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Goodmoves.org Jobs Scraper",
        "description": "Scrape Scottish charity-sector job postings from Goodmoves.org — title, salary, workplace type, employer, posted/closing dates with time, full description, real lat/lng coordinates, OSCR charity number and apply email or apply URL. Works with any listing or vacancy URL. JSON or CSV out.",
        "version": "0.0",
        "x-build-id": "iMkr4abcZOVR9G3Z3"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~goodmoves-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-goodmoves-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~goodmoves-scraper/runs": {
            "post": {
                "operationId": "runs-sync-memo23-goodmoves-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~goodmoves-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-goodmoves-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "Goodmoves URLs",
                        "type": "array",
                        "description": "Full goodmoves.org URLs to crawl. Mix listing and vacancy URLs in the same array if useful.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "enrichOrganisation": {
                        "title": "Fetch organisation profile (adds website + domain + OSCR charity number)",
                        "type": "boolean",
                        "description": "When enabled, each unique organisation profile is fetched once to add `companyWebsite`, `companyDomain`, and `oscrCharityNumber`. The vacancy JSON-LD already contains the company description, so disable this if you only need the description and want to skip the extra HTTP calls.",
                        "default": true
                    },
                    "maxItems": {
                        "title": "Maximum items to scrape",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on the number of jobs collected. Goodmoves listings often return 80+ vacancies in a single page; use this cap to limit billing.",
                        "default": 1000
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Maximum number of vacancy pages processed in parallel.",
                        "default": 10
                    },
                    "minConcurrency": {
                        "title": "Min concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Minimum number of vacancy pages processed in parallel.",
                        "default": 1
                    },
                    "maxRequestRetries": {
                        "title": "Max request retries",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Number of retries before a failed request is given up.",
                        "default": 5
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify proxy settings. Goodmoves has no anti-bot, so a small residential pool (or even no proxy) usually works fine.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
