{
  "openapi": "3.0.1",
  "info": {
    "title": "Freelancer.nl Opdrachten Scraper - Freelance & ZZP Projects",
    "description": "Scrape freelancer.nl for Dutch freelance opdrachten and ZZP listings. Filter by city or keyword, enrich with full detail pages including budget and duration, and track new or changed listings incrementally.",
    "version": "0.1",
    "x-build-id": "X36YMUv5tCQ3QA7XR"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/blackfalcondata~freelancer-nl-opdrachten-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-blackfalcondata-freelancer-nl-opdrachten-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/blackfalcondata~freelancer-nl-opdrachten-scraper/runs": {
      "post": {
        "operationId": "runs-sync-blackfalcondata-freelancer-nl-opdrachten-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/blackfalcondata~freelancer-nl-opdrachten-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-blackfalcondata-freelancer-nl-opdrachten-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": {
          "query": {
            "title": "🔍 Search Term(s)",
            "type": "string",
            "description": "Keyword to filter listings (e.g. \"php\", \"webdesign\"). Strict match with proper pagination. Leave empty for all listings."
          },
          "location": {
            "title": "📍 Location",
            "type": "string",
            "description": "Filter by Dutch city (e.g. \"eindhoven\", \"rotterdam\", \"groningen\"). Maps to /opdrachten/{city} — a real strict filter on freelancer.nl with exact total counts. When combined with query, location takes precedence and the query is applied as a client-side title post-filter."
          },
          "daysOld": {
            "title": "Max Age (days)",
            "minimum": 0,
            "maximum": 365,
            "type": "integer",
            "description": "Drop listings older than N days (post-filter on parsed publishedAt). 0 = no filter.",
            "default": 0
          },
          "budgetType": {
            "title": "Budget Type",
            "enum": [
              "",
              "hourly",
              "fixed",
              "tbd"
            ],
            "type": "string",
            "description": "Filter by budget type. \"hourly\" = Per uur, \"fixed\" = Vaste prijs, \"tbd\" = In overleg (budget not specified). Applied as a post-filter on parsed budget data.",
            "default": ""
          },
          "budgetMin": {
            "title": "Budget Minimum (EUR)",
            "minimum": 0,
            "type": "integer",
            "description": "Minimum budget in euros. Listings whose upper bound is below this are dropped. Applied as a post-filter on parsed budget data."
          },
          "budgetMax": {
            "title": "Budget Maximum (EUR)",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum budget in euros. Listings whose lower bound is above this are dropped. Applied as a post-filter on parsed budget data."
          },
          "startUrls": {
            "title": "🔗 Start URLs",
            "type": "array",
            "description": "Override listing URLs (e.g. category pages: https://www.freelancer.nl/opdrachten/php). Leave empty to use query/location filters or scrape all listings.",
            "items": {
              "type": "string"
            }
          },
          "maxResults": {
            "title": "💯 Max Results",
            "minimum": 0,
            "maximum": 2000,
            "type": "integer",
            "description": "Maximum listings to return (0 = unlimited).",
            "default": 50
          },
          "maxPages": {
            "title": "Max Pages",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "Maximum listing pages per source.",
            "default": 5
          },
          "includeDetails": {
            "title": "📋 Include Full Details",
            "type": "boolean",
            "description": "Fetch each listing's detail page for the full description (~3500 chars). Doubles the request count.",
            "default": true
          },
          "descriptionMaxLength": {
            "title": "✂️ Description Max Length",
            "minimum": 0,
            "type": "integer",
            "description": "Truncate description to this many characters. 0 = no limit.",
            "default": 0
          },
          "compact": {
            "title": "📦 Compact Output",
            "type": "boolean",
            "description": "Return only core fields (title, location, tags, URL, postedAt). Useful for AI / MCP workflows.",
            "default": false
          },
          "incrementalMode": {
            "title": "♻️ Incremental Mode",
            "type": "boolean",
            "description": "Track changes between runs. Requires stateKey.",
            "default": false
          },
          "stateKey": {
            "title": "🔑 State Key",
            "type": "string",
            "description": "Optional stable identifier for the tracked search universe. Leave empty to auto-derive a stable identifier from your search inputs — different keyword/location/filter combinations get isolated state automatically."
          },
          "skipReposts": {
            "title": "🚫 Skip Reposts",
            "type": "boolean",
            "description": "Exclude listings detected as reposts of previously seen jobs.",
            "default": false
          },
          "emitUnchanged": {
            "title": "Emit Unchanged",
            "type": "boolean",
            "description": "Also emit listings that haven't changed since last run.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit Expired",
            "type": "boolean",
            "description": "Also emit listings that disappeared since last run.",
            "default": false
          },
          "telegramToken": {
            "title": "📱 Telegram Bot Token",
            "type": "string",
            "description": "Telegram bot token from @BotFather. Pairs with Telegram Chat ID. Pair with Incremental Mode for real-time alerts on new/updated items only."
          },
          "telegramChatId": {
            "title": "💬 Telegram Chat / Channel ID",
            "type": "string",
            "description": "Chat ID (from @userinfobot) or channel ID (starts with -100 for channels). Required when Telegram Bot Token is set."
          },
          "slackWebhookUrl": {
            "title": "💼 Slack Incoming Webhook URL",
            "type": "string",
            "description": "Slack incoming webhook URL (Slack App → Incoming Webhooks → Add New Webhook). Formats jobs as Slack blocks."
          },
          "discordWebhookUrl": {
            "title": "🎮 Discord Webhook URL",
            "type": "string",
            "description": "Discord channel webhook URL (Server Settings → Integrations → Webhooks → New Webhook). Sends rich embeds colour-coded by change type (green=NEW, amber=UPDATED)."
          },
          "whatsappAccessToken": {
            "title": "📲 WhatsApp Access Token",
            "type": "string",
            "description": "WhatsApp Cloud API permanent System User token from Meta Business. Pairs with WhatsApp Phone Number ID and recipient phone."
          },
          "whatsappPhoneNumberId": {
            "title": "📞 WhatsApp Phone Number ID",
            "type": "string",
            "description": "Numeric WhatsApp Business phone-number ID from Meta dashboard."
          },
          "whatsappTo": {
            "title": "📨 WhatsApp Recipient (E.164)",
            "type": "string",
            "description": "Recipient phone in E.164 format (e.g. \"15551234567\"). Recipient must have messaged the business number within the last 24h, otherwise Meta rejects free-form text."
          },
          "webhookUrl": {
            "title": "🔗 Generic Webhook URL",
            "type": "string",
            "description": "POSTs a JSON payload `{metadata, items}` to your endpoint. Universal hook for n8n / Make / Zapier / custom backends."
          },
          "webhookHeaders": {
            "title": "📑 Webhook Headers (JSON)",
            "type": "object",
            "description": "Optional headers (e.g. `{\"Authorization\": \"Bearer ...\"}`) sent with the webhook POST."
          },
          "notificationLimit": {
            "title": "🔢 Notification Limit",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Maximum number of jobs included per notification batch (1–20). Prevents spam on large result sets.",
            "default": 5
          },
          "notifyOnlyChanges": {
            "title": "🆕 Notify Only on Changes",
            "type": "boolean",
            "description": "When ON together with Incremental Mode, send notifications only for NEW and UPDATED jobs. Has no effect outside incremental mode.",
            "default": false
          },
          "includeRunMetadata": {
            "title": "📣 Include Run Summary in Notifications",
            "type": "boolean",
            "description": "Prepend a one-line summary (search label + total count) to each notification batch.",
            "default": true
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}