{
  "openapi": "3.0.1",
  "info": {
    "title": "Notion Uploader",
    "description": "Upload data into a specified Notion database. It dynamically maps data from any Actor / Dataset to your Notion properties, ensuring your database stays up-to-date with the latest information.",
    "version": "2.0",
    "x-build-id": "EsJtmsyhLO0OtPjDt"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/filip_cicvarek~notion-uploader/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-filip_cicvarek-notion-uploader",
        "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/filip_cicvarek~notion-uploader/runs": {
      "post": {
        "operationId": "runs-sync-filip_cicvarek-notion-uploader",
        "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/filip_cicvarek~notion-uploader/run-sync": {
      "post": {
        "operationId": "run-sync-filip_cicvarek-notion-uploader",
        "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": {
          "notionConnector": {
            "title": "Notion connection (MCP connector)",
            "type": "string",
            "description": "Recommended. An Apify MCP connector authorized to your Notion workspace — create one in Console → Settings → Integrations → MCP connectors. The Actor then acts with your Notion permissions without ever seeing a token. Alternative: leave empty and provide a Notion API key below."
          },
          "notionApiKey": {
            "title": "Notion API key",
            "type": "string",
            "description": "Classic Notion internal-integration secret (starts with 'ntn_' — create at notion.so/profile/integrations). In Notion, connect the integration to the target database/page via the ••• → Connections menu, otherwise it sees nothing. Not needed when a connector is selected above — but adding it anyway enables duplicate lookups (upsert/skip) on Notion plans where the connector cannot run queries."
          },
          "datasetId": {
            "title": "Source dataset",
            "type": "string",
            "description": "The Apify dataset whose items get uploaded — pick one from your account or paste a dataset ID. Leave empty when this Actor runs as an integration on another Actor's success: the triggering run's dataset is used automatically."
          },
          "maxItems": {
            "title": "Max items to upload",
            "minimum": 0,
            "type": "integer",
            "description": "Upper limit of dataset items to process. 0 = no limit (the whole dataset).",
            "default": 0
          },
          "notionDatabaseId": {
            "title": "Notion database (ID or URL)",
            "type": "string",
            "description": "Destination 1 — existing database: paste its Notion URL, a bare ID, or a data-source ID (collection://...). Each dataset item becomes one row. Leave empty when using destination 2 or 3."
          },
          "notionDataSourceId": {
            "title": "Data source ID",
            "type": "string",
            "description": "For destination 1 only, and only when the database has multiple data sources (a Notion 2025+ feature — the run fails and lists the candidates in that case). Leave empty for normal databases."
          },
          "createDatabaseIfMissing": {
            "title": "Create a database for me",
            "type": "boolean",
            "description": "Destination 2 — new database: creates it with a schema inferred from your data (column names and types come from the items; leave 'Field mapping' empty to get all fields). Only applies when 'Notion database' above is empty. CAUTION on schedules: every run creates a NEW database unless you paste the created database (URL is in the log and SUMMARY) into 'Notion database' for the next run.",
            "default": false
          },
          "databaseParentPageId": {
            "title": "Parent page for the new database",
            "type": "string",
            "description": "Destination 2 only: the Notion page (URL or ID) under which the new database is created. With an MCP connector you can leave it empty (the database lands as a workspace-level private page); with an API key it is required."
          },
          "newDatabaseTitle": {
            "title": "New database title",
            "type": "string",
            "description": "Destination 2 only: title of the created database. Default: 'Apify upload'."
          },
          "notionPageId": {
            "title": "Notion page (ID or URL)",
            "type": "string",
            "description": "Destination 3 — page: items are rendered as markdown (see 'Page rendering') and written into this page instead of a database. Cannot be combined with 'Notion database'."
          },
          "pageWriteMode": {
            "title": "Page write mode",
            "enum": [
              "append",
              "replace",
              "new-page"
            ],
            "type": "string",
            "description": "Destination 3 only: append to the end of the page, replace the page's content, or create a new child page on every run.",
            "default": "append"
          },
          "pageRenderMode": {
            "title": "Page rendering",
            "enum": [
              "table",
              "bullets",
              "content-only"
            ],
            "type": "string",
            "description": "Destination 3 only: how items are rendered — a markdown table of the mapped fields, a bulleted digest, or only the raw text taken from 'Page content field' (set it below in Mapping).",
            "default": "table"
          },
          "newPageTitle": {
            "title": "New child page title",
            "type": "string",
            "description": "Destination 3 only, when 'Page write mode' is 'Create a new child page per run'. Default: 'Apify upload (N items)'."
          },
          "mappingPrompt": {
            "title": "AI mapping prompt",
            "type": "string",
            "description": "Optional plain-English mapping instructions, e.g. 'Put the listing headline into Name, monthly rent into Price, and use the sreality link as URL'. One cheap LLM call resolves it against your dataset fields and the Notion schema — needs the Anthropic API key from the AI features section. Explicit 'Field mapping' below still wins; automatic name-matching fills whatever remains."
          },
          "dataMapping": {
            "title": "Field mapping",
            "type": "object",
            "description": "Optional explicit mapping of Notion property names to dataset field names, e.g. {\"Name\": \"title\", \"URL\": \"url\", \"Score\": \"stats.score\"}. Dot paths reach nested fields. CAUTION with 'Create a database for me': a non-empty mapping means the new database gets ONLY these columns — leave empty to get all fields."
          },
          "createMissingProperties": {
            "title": "Create missing Notion properties",
            "type": "boolean",
            "description": "Destination 1 (existing database) only: create mapped properties that don't exist in it yet. Types are inferred from sample values (text, number, checkbox, URL, date, email, multi-select). New databases get their schema from the data automatically.",
            "default": false
          },
          "contentField": {
            "title": "Page content field",
            "type": "string",
            "description": "Optional dataset field whose text becomes the page body — of each created row (database destinations) or of the target page (page destination with 'Raw content' rendering). Markdown is preserved on the connector path; the API-key path renders headings, bullets and tables."
          },
          "dedupeMode": {
            "title": "Duplicate handling",
            "enum": [
              "create",
              "upsert",
              "skip-existing"
            ],
            "type": "string",
            "description": "What to do when an item already exists in the database, matched by the key property below. 'Upsert' updates the existing row, 'Skip existing' leaves it untouched, 'Create' never checks and always adds new rows. Lookups need either a Notion API key or a connector on a Notion Business+ plan — otherwise the run falls back to 'Create' with a warning and 'dedupeDegraded: true' in the SUMMARY.",
            "default": "create"
          },
          "keyProperty": {
            "title": "Notion key property",
            "type": "string",
            "description": "Required for Upsert / Skip existing: the Notion property that identifies a row, e.g. 'URL'. Works with title, text, number, URL, email, phone and select properties."
          },
          "keyField": {
            "title": "Dataset key field",
            "type": "string",
            "description": "Optional: the dataset field holding the identity value. Leave empty to use the field already mapped to the key property."
          },
          "transformPrompt": {
            "title": "AI value transformation",
            "type": "string",
            "description": "Optional instruction that rewrites EXISTING field values before upload, e.g. 'append USD to all price values' or 'translate the description to English'. Mechanical changes compile to per-field templates and run locally (one LLM call total); only fields needing judgment get one call per item. The rule plan is saved to the TRANSFORM_PLAN record. Column types adapt automatically in create-database mode; in an existing database, transformed values must still fit the column type. Needs the Anthropic API key."
          },
          "enrichmentPrompt": {
            "title": "AI enrichment prompt",
            "type": "string",
            "description": "Optional per-item LLM instruction that GENERATES A NEW VALUE per item, e.g. 'Summarize this listing in one sentence: {{title}}, {{description}}'. {{field}} placeholders are filled from each item and the full item JSON is appended for context. The output lands in the property below. To modify existing values instead, use 'AI value transformation' above. Needs the Anthropic API key."
          },
          "enrichmentProperty": {
            "title": "Enrichment target property",
            "type": "string",
            "description": "Only with an enrichment prompt: the Notion text property that receives the AI output. Created automatically when missing.",
            "default": "AI summary"
          },
          "anthropicApiKey": {
            "title": "Anthropic API key",
            "type": "string",
            "description": "Needed only for the AI mapping prompt and AI enrichment — get one at console.anthropic.com."
          },
          "llmModel": {
            "title": "LLM model",
            "enum": [
              "claude-haiku-4-5",
              "claude-sonnet-5"
            ],
            "type": "string",
            "description": "Anthropic model used by the AI features.",
            "default": "claude-haiku-4-5"
          },
          "dryRun": {
            "title": "Dry run",
            "type": "boolean",
            "description": "Rehearse without writing: resolves the mapping (including the AI prompt), validates against the Notion schema, checks duplicates, and records what WOULD happen (RESOLVED_MAPPING and WOULD_WRITE records, would-create/would-update statuses in the report). No pages are written and no per-item enrichment calls are made. Great first run.",
            "default": false
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}