{
  "openapi": "3.0.1",
  "info": {
    "title": "Google Sheets Import & Export (Append, Upsert, Replace)",
    "description": "Send any Apify dataset or JSON to Google Sheets (append, upsert by key, replace) or export a sheet to a dataset. Service-account auth with no OAuth popups, automatic header mapping, typed values, batching and quota-aware retries.",
    "version": "0.1",
    "x-build-id": "Qbkf4anUXKCpeCI57"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/pluginlint-tools~google-sheets-sync/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-pluginlint-tools-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/pluginlint-tools~google-sheets-sync/runs": {
      "post": {
        "operationId": "runs-sync-pluginlint-tools-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/pluginlint-tools~google-sheets-sync/run-sync": {
      "post": {
        "operationId": "run-sync-pluginlint-tools-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",
        "properties": {
          "mode": {
            "title": "What to do",
            "enum": [
              "append",
              "upsert",
              "replace",
              "export"
            ],
            "type": "string",
            "description": "<b>append</b> – add rows below existing data (optionally skip rows whose key already exists).<br><b>upsert</b> – update rows that match <i>Key columns</i>, append the rest.<br><b>replace</b> – clear the tab and write the data (old content is backed up to the key-value store).<br><b>export</b> – read the tab and save every row to this run's dataset.",
            "default": "append"
          },
          "spreadsheetId": {
            "title": "Google Sheet URL or ID",
            "type": "string",
            "description": "Paste the full URL from your browser (e.g. https://docs.google.com/spreadsheets/d/1AbCdEf.../edit#gid=0) or just the ID. If the URL contains #gid=..., that tab is used unless you set Sheet (tab) name."
          },
          "sheetName": {
            "title": "Sheet (tab) name",
            "type": "string",
            "description": "Name of the tab to write to / read from. Empty = the tab from the URL's gid, otherwise the first tab. For writes, a missing tab is created automatically."
          },
          "serviceAccountJson": {
            "title": "Service account JSON key (recommended)",
            "type": "string",
            "description": "Paste the whole JSON key file of a Google Cloud service account (Google Cloud Console → IAM & Admin → Service Accounts → Keys → Add key → JSON). Then share your sheet with the service account's e-mail (the <code>client_email</code> in the JSON) as Editor. Stored encrypted; never logged. No expiring tokens, works for scheduled runs."
          },
          "oauthClientId": {
            "title": "OAuth client ID (alternative)",
            "type": "string",
            "description": "Only if you prefer OAuth instead of a service account: client ID of your own Google OAuth client (type Desktop or Web)."
          },
          "oauthClientSecret": {
            "title": "OAuth client secret",
            "type": "string",
            "description": "Client secret of the same OAuth client."
          },
          "oauthRefreshToken": {
            "title": "OAuth refresh token",
            "type": "string",
            "description": "Refresh token with the https://www.googleapis.com/auth/spreadsheets scope (e.g. from the Google OAuth Playground using your own client). Note: if your OAuth consent screen is in 'Testing' mode, Google expires refresh tokens after 7 days."
          },
          "datasetId": {
            "title": "Dataset ID (source data)",
            "type": "string",
            "description": "ID of the Apify dataset to send to the sheet, e.g. the default dataset of your scraper run. When this actor is attached as an integration to another actor, the source run's dataset is used automatically."
          },
          "data": {
            "title": "Data (JSON)",
            "type": "array",
            "description": "Alternatively, paste an array of objects to write. Used instead of Dataset ID when not empty. Max ~9 MB (Apify input limit)."
          },
          "limit": {
            "title": "Limit",
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of items to take from the dataset (or rows to export). Empty = all."
          },
          "offset": {
            "title": "Offset",
            "minimum": 0,
            "type": "integer",
            "description": "Number of items to skip from the start of the dataset (or of the exported rows).",
            "default": 0
          },
          "fields": {
            "title": "Fields to include",
            "type": "array",
            "description": "Only these top-level fields are written (applied before flattening). Empty = all fields.",
            "items": {
              "type": "string"
            }
          },
          "omitFields": {
            "title": "Fields to omit",
            "type": "array",
            "description": "Top-level fields to leave out, e.g. large HTML fields.",
            "items": {
              "type": "string"
            }
          },
          "keyColumns": {
            "title": "Key columns (for upsert / dedupe)",
            "type": "array",
            "description": "Column names that identify a row, e.g. <code>url</code> or <code>sku</code>. Required for <b>upsert</b>. In <b>append</b> mode, rows whose key already exists in the sheet are skipped (dedupe). Duplicate keys inside the input are merged.",
            "items": {
              "type": "string"
            }
          },
          "autoMapHeaders": {
            "title": "Auto-map headers",
            "type": "boolean",
            "description": "Match data fields to existing sheet columns even when spelling differs in case, spaces, underscores, dots or slashes (\"Product Name\" ⇄ product_name). Existing columns are never reordered.",
            "default": true
          },
          "addNewColumns": {
            "title": "Add new columns",
            "type": "boolean",
            "description": "Add data fields that have no column yet as new columns on the right. If off, such fields are skipped (and listed in the log).",
            "default": true
          },
          "columnsOrder": {
            "title": "Order of new columns",
            "type": "array",
            "description": "Fields listed here come first (in this order) when columns are created. Existing sheet columns keep their position.",
            "items": {
              "type": "string"
            }
          },
          "nestedHandling": {
            "title": "Nested objects / arrays",
            "enum": [
              "flatten",
              "json"
            ],
            "type": "string",
            "description": "<b>flatten</b> – <code>{seller:{name}}</code> becomes column <code>seller/name</code>, arrays become <code>tags/0</code>, <code>tags/1</code> (same as Apify CSV export).<br><b>json</b> – keep one column per top-level field and store nested values as JSON text.",
            "default": "flatten"
          },
          "flattenSeparator": {
            "title": "Flatten separator",
            "type": "string",
            "description": "Separator for flattened column names.",
            "default": "/"
          },
          "valueInputOption": {
            "title": "Value handling",
            "enum": [
              "RAW",
              "USER_ENTERED"
            ],
            "type": "string",
            "description": "<b>RAW</b> (default) – exact types: numbers stay numbers, booleans stay TRUE/FALSE, text stays text (leading zeros like 00123 and '+1 555…' are preserved, '=' formulas are NOT executed, no locale surprises with '1,5').<br><b>USER_ENTERED</b> – Google parses values as if typed by a user (formulas run, '2024-01-31' becomes a date).",
            "default": "RAW"
          },
          "createSheetIfMissing": {
            "title": "Create tab if missing",
            "type": "boolean",
            "description": "Create the tab named in Sheet (tab) name if it doesn't exist.",
            "default": true
          },
          "createBackup": {
            "title": "Back up before replace",
            "type": "boolean",
            "description": "In replace mode, save the old tab content to this run's key-value store (record BACKUP-<tab>) before clearing it.",
            "default": true
          },
          "range": {
            "title": "Range to export (A1)",
            "type": "string",
            "description": "Optional A1 range inside the tab for export, e.g. <code>A1:F500</code>. First row of the range is used as the header. Empty = whole tab."
          },
          "valueRenderOption": {
            "title": "Exported value format",
            "enum": [
              "UNFORMATTED_VALUE",
              "FORMATTED_VALUE",
              "FORMULA"
            ],
            "type": "string",
            "description": "<b>UNFORMATTED_VALUE</b> – real numbers/booleans (12.5, true). <b>FORMATTED_VALUE</b> – exactly what you see in the sheet ('$12.50'). <b>FORMULA</b> – formulas as text.",
            "default": "UNFORMATTED_VALUE"
          },
          "unflattenOutput": {
            "title": "Unflatten exported columns",
            "type": "boolean",
            "description": "Turn columns like seller/name back into nested objects in the dataset.",
            "default": false
          },
          "skipEmptyRows": {
            "title": "Skip empty rows",
            "type": "boolean",
            "description": "Ignore completely empty rows when exporting.",
            "default": true
          },
          "batchSize": {
            "title": "Rows per request",
            "minimum": 1,
            "maximum": 50000,
            "type": "integer",
            "description": "Rows sent per Google API request (payloads are also capped at ~2 MB automatically).",
            "default": 5000
          },
          "delayBetweenBatchesMs": {
            "title": "Delay between batches (ms)",
            "minimum": 0,
            "type": "integer",
            "description": "Pause between write requests to stay under Google's 60 writes/minute/user quota. Rate-limit errors (429) are retried with exponential backoff anyway.",
            "default": 1000
          },
          "maxRetries": {
            "title": "Max retries per request",
            "minimum": 0,
            "maximum": 10,
            "type": "integer",
            "description": "Retries for quota (429) and transient (5xx, network) errors, with exponential backoff up to 64 s.",
            "default": 6
          },
          "dryRun": {
            "title": "Dry run (no Google account needed)",
            "type": "boolean",
            "description": "Run everything against an in-memory spreadsheet: shows exactly which header/rows would be written, without credentials and without any charge. Runs with no spreadsheet and no credentials are dry runs automatically.",
            "default": false
          },
          "dryRunExistingValues": {
            "title": "Dry run: existing sheet content",
            "type": "array",
            "description": "Optional rows (array of arrays, first row = header) to pre-fill the in-memory sheet with, to test upsert/append mapping."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}