{
  "openapi": "3.0.1",
  "info": {
    "title": "Google Sheets Sync (BYOK)",
    "description": "Append, upsert or replace rows from an Actor dataset into Google Sheets using your own Google OAuth credentials.",
    "version": "0.1",
    "x-build-id": "wj2TS4Wbi2R70CqKh"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/assured_hippeastrum~google-sheets-sync/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-assured_hippeastrum-google-sheets-sync",
        "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/assured_hippeastrum~google-sheets-sync/runs": {
      "post": {
        "operationId": "runs-sync-assured_hippeastrum-google-sheets-sync",
        "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/assured_hippeastrum~google-sheets-sync/run-sync": {
      "post": {
        "operationId": "run-sync-assured_hippeastrum-google-sheets-sync",
        "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",
        "required": [
          "clientId",
          "clientSecret",
          "refreshToken"
        ],
        "properties": {
          "clientId": {
            "title": "Google client ID",
            "type": "string",
            "description": "OAuth client ID of a Desktop app from Google Cloud Console. Format: <number>-<hash>.apps.googleusercontent.com. See README for the 5-minute setup."
          },
          "clientSecret": {
            "title": "Google client secret",
            "type": "string",
            "description": "OAuth client secret of the same Desktop app. Starts with GOCSPX-. Marked as secret: encrypted by Apify and decrypted only inside the run."
          },
          "refreshToken": {
            "title": "Google refresh token",
            "type": "string",
            "description": "Long-lived refresh token for scope https://www.googleapis.com/auth/spreadsheets, obtained via https://developers.google.com/oauthplayground. Marked as secret. Note: while your OAuth app is in Testing status the token expires in 7 days; publish the app to make it permanent."
          },
          "mode": {
            "title": "Write mode",
            "enum": [
              "append",
              "upsert",
              "replace"
            ],
            "type": "string",
            "description": "append adds new rows at the bottom and never touches existing ones; upsert updates rows whose keyField matches and appends the rest; replace clears the target sheet and writes everything.",
            "default": "append"
          },
          "spreadsheetId": {
            "title": "Spreadsheet ID or URL",
            "type": "string",
            "description": "ID from https://docs.google.com/spreadsheets/d/<ID>/edit or the full URL. Leave empty to create a brand-new spreadsheet owned by your Google account; its URL is returned in the run report."
          },
          "sheetName": {
            "title": "Sheet (tab) name",
            "type": "string",
            "description": "Tab name inside the spreadsheet, for example Sheet1. Case-sensitive.",
            "default": "Sheet1"
          },
          "createSheetIfMissing": {
            "title": "Create the tab if it does not exist",
            "type": "boolean",
            "description": "When off (default) the run fails with a clear message listing existing tabs. When on, a missing tab is created automatically.",
            "default": false
          },
          "datasetId": {
            "title": "Dataset to sync",
            "type": "string",
            "description": "Dataset with the rows to write. Pick it with the resource picker: under LIMITED_PERMISSIONS the platform grants access only to the datasets you select this way. Leave the field empty to read the dataset of the current run instead (start the Actor with \"Run actor\" from a dataset page, or use an Actor Task)."
          },
          "maxItems": {
            "title": "Max rows to write",
            "minimum": 0,
            "type": "integer",
            "description": "Stop after this many dataset items. 0 means no limit.",
            "default": 0
          },
          "columnsOrder": {
            "title": "Column order",
            "type": "array",
            "description": "Explicit list of dataset fields to write, in this order. Fields not listed here are handled by unknownColumns. Leave empty to keep the natural order of keys as they appear in the first item.",
            "items": {
              "type": "string"
            }
          },
          "unknownColumns": {
            "title": "Fields not listed in column order",
            "enum": [
              "append",
              "drop"
            ],
            "type": "string",
            "description": "append keeps unlisted fields as extra columns at the end; drop writes only the listed ones.",
            "default": "append"
          },
          "writeHeader": {
            "title": "Header row",
            "enum": [
              "once",
              "always",
              "never"
            ],
            "type": "string",
            "description": "once writes the header only when the target sheet is empty (recommended); always writes it before the first batch of this run; never never writes it.",
            "default": "once"
          },
          "keyField": {
            "title": "Key field",
            "type": "string",
            "description": "Dataset field used as a unique key: required for upsert, optional for append (deduplication against rows already in the sheet). Items without this field are skipped and counted in the report."
          },
          "keyNormalization": {
            "title": "Key normalization",
            "enum": [
              "exact",
              "trim",
              "lowercase"
            ],
            "type": "string",
            "description": "How keys are compared: exact, trim (default, ignores surrounding spaces) or lowercase (trim + case-insensitive).",
            "default": "trim"
          },
          "valueInputOption": {
            "title": "Value input option",
            "enum": [
              "USER_ENTERED",
              "RAW"
            ],
            "type": "string",
            "description": "USER_ENTERED lets Google parse numbers, dates and formulas (dates stay dates); RAW writes everything as text.",
            "default": "USER_ENTERED"
          },
          "escapeFormulas": {
            "title": "Escape formulas",
            "type": "boolean",
            "description": "Prefix cells that start with = + - @ with an apostrophe so scraped data can never be executed as a formula by Google Sheets. Recommended on.",
            "default": true
          },
          "addMissingColumns": {
            "title": "Add missing columns (upsert)",
            "type": "boolean",
            "description": "In upsert mode, extend the sheet header with dataset fields that the sheet does not have yet. When off, such fields are dropped and reported.",
            "default": true
          },
          "chunkSize": {
            "title": "Rows per request",
            "enum": [
              "1000",
              "2000",
              "4000",
              "6000",
              "8000",
              "10000"
            ],
            "type": "string",
            "description": "Batch size — the main speed lever; rows/s measured on a 25k-row sheet. 4000 is the recommended balance; 6000-10000 pay off only on narrow rows and small sheets (the actor still shrinks a batch that would exceed maxPayloadMb); 1000-2000 is safest for wide rows and very large files. In API inputs pass the value as a string, e.g. \"4000\".",
            "default": "4000"
          },
          "maxPayloadMb": {
            "title": "Max request payload, MB",
            "minimum": 0.1,
            "maximum": 10,
            "type": "number",
            "description": "Soft cap on the size of one Sheets API write request. 2 MB is the speed optimum (Google's own recommendation): a single 10 MB request is accepted (HTTP 200) but processed about 50x slower per cell, so a bigger cap slows big writes down.",
            "default": 2
          },
          "requestsPerMinute": {
            "title": "Requests per minute (reads and writes counted separately)",
            "minimum": 1,
            "maximum": 60,
            "type": "integer",
            "description": "Throttle applied independently to read requests and to write requests. 60 is Google's per-user limit (and the fastest setting); lower it if other tools share the same Google account.",
            "default": 60
          },
          "maxRetries": {
            "title": "Max retries per request",
            "minimum": 0,
            "maximum": 20,
            "type": "integer",
            "description": "Retries for retryable Google errors (429, 5xx, network) with exponential backoff and jitter.",
            "default": 10
          },
          "autoSplit": {
            "title": "When the data does not fit",
            "enum": [
              "off",
              "sheets",
              "spreadsheets"
            ],
            "type": "string",
            "description": "off fails with the exact number of rows that still fit; sheets adds tabs to the same spreadsheet; spreadsheets adds tabs and then brand-new spreadsheets. Order of rows is always preserved.",
            "default": "off"
          },
          "maxCellsPerSpreadsheet": {
            "title": "Cell limit per spreadsheet",
            "minimum": 100000,
            "maximum": 20000000,
            "type": "integer",
            "description": "Cell budget for the spreadsheet. Google's documented limit is 20,000,000 cells (or 100 MB per file); spreadsheets created before the limit increase may still be capped at 5-10 million. If the sheet refuses the write, the actor detects the cell-limit error and applies autoSplit.",
            "default": 20000000
          },
          "maxCellsPerSheet": {
            "title": "Cell limit per sheet (tab)",
            "minimum": 100000,
            "maximum": 20000000,
            "type": "integer",
            "description": "Soft target used when auto-splitting: a new tab is started once a tab reaches this size. Keeps every tab fast to open and edit.",
            "default": 5000000
          },
          "safetyMargin": {
            "title": "Safety margin, cells",
            "minimum": 0,
            "type": "integer",
            "description": "Reserved headroom below the spreadsheet cell limit, in case someone edits the file while the actor runs.",
            "default": 100000
          },
          "dryRun": {
            "title": "Dry run",
            "type": "boolean",
            "description": "Validate credentials, read the dataset and compute the plan (rows, columns, splits, target ranges) without writing anything.",
            "default": false
          },
          "continueOnChunkError": {
            "title": "Continue after a failed batch",
            "type": "boolean",
            "description": "When on, a failed batch is reported and the run continues with the next one; when off the run fails immediately.",
            "default": true
          },
          "resume": {
            "title": "Resume a previous run",
            "type": "boolean",
            "description": "Continue from the last successfully written batch if the same dataset, spreadsheet, sheet and key field are used. Prevents duplicates on retries.",
            "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}