{
  "openapi": "3.0.1",
  "info": {
    "title": "TuneIn Scraper - Radio Stations, Podcasts & Stream URLs",
    "description": "Scrape TuneIn by keyword, category, genre, location or URL. Extract stations and podcasts with artwork, genre, bitrate, frequency, location, language, contact details, playable stream URLs and episodes. Incremental mode tracks changes over time.",
    "version": "1.0",
    "x-build-id": "FXrWhVObMRipkv09G"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~tunein-radio-podcast-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-tunein-radio-podcast-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/abotapi~tunein-radio-podcast-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-tunein-radio-podcast-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/abotapi~tunein-radio-podcast-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-tunein-radio-podcast-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",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "browse",
              "url"
            ],
            "type": "string",
            "description": "Choose 'search' to look results up by keyword, 'browse' to walk the directory's own categories, genres and locations, or 'url' to scrape pasted links and directory ids.",
            "default": "search"
          },
          "queries": {
            "title": "Search keywords",
            "type": "array",
            "description": "Only used when mode = search, ignored in the other modes. One or more keywords, for example 'jazz', 'BBC Radio 4', 'true crime' or a call sign such as 'KEXP'. Left empty in search mode, the run searches the example keyword 'jazz' so it never ends empty.",
            "items": {
              "type": "string"
            }
          },
          "browseCategories": {
            "title": "Categories",
            "uniqueItems": true,
            "type": "array",
            "description": "Only used when mode = browse, ignored in the other modes. Local radio is the directory's own locale popular chart and is the one category that responds to Locale coordinates below. Selecting several returns results from all of them. Left empty with no ids, a browse run uses Local radio.",
            "items": {
              "type": "string",
              "enum": [
                "local",
                "music",
                "talk",
                "sports",
                "podcast",
                "language",
                "location"
              ],
              "enumTitles": [
                "Local radio (popular near a place)",
                "Music",
                "Talk",
                "Sports",
                "Podcasts",
                "By language",
                "By location"
              ]
            }
          },
          "browseIds": {
            "title": "Genre, category or region ids",
            "type": "array",
            "description": "Optional, browse mode only. Directory ids for a specific genre, category or region, for example g11 (Jazz), c57943 (Top 40 and Pop) or r101216 (Asia). Every result this actor returns carries its own guideId, and the ids shown in the By location and category listings can be pasted straight back in here.",
            "items": {
              "type": "string"
            }
          },
          "localeLatLon": {
            "title": "Locale coordinates for Local radio",
            "type": "string",
            "description": "Optional, browse mode only, and applied to the Local radio category alone because the other categories are worldwide. Latitude and longitude separated by a comma, for example 51.5074,-0.1278 for London or 40.7128,-74.0060 for New York. Leave empty to use the location of the connection the run goes out on."
          },
          "urls": {
            "title": "Links or ids",
            "type": "array",
            "description": "Only used when mode = url, ignored in the other modes. Mix freely: tunein.com station, podcast and embed-player addresses, search pages (with or without a type filter), category and genre pages, the radio and podcast hub pages, and bare directory ids such as s34682, p1008289 or c57943. Left untouched, this field scrapes one example of each address shape. Left empty, the run reads one example station link instead of returning nothing. The editor's suggested list also shows podcast and episode address shapes, a podcast id on its own and a region page. In this mode the full profile is always read, so a pasted link never returns an empty shell.",
            "default": [
              "https://tunein.com/station/?stationId=34682",
              "https://tunein.com/radio/Jazz24-88-s34682/",
              "https://tunein.com/podcasts/Talk-p1008289/",
              "https://tunein.com/search/?query=jazz",
              "https://tunein.com/search/?query=jazz&filter=p",
              "https://tunein.com/radio/Jazz-c57943/",
              "https://tunein.com/radio/Jazz-g11/",
              "https://tunein.com/radio/Jazz-g11/?page=2",
              "https://tunein.com/podcasts/",
              "https://tunein.com/radio/music/",
              "https://tunein.com/radio/local/",
              "https://tunein.com/embed/player/s34682/"
            ],
            "items": {
              "type": "string"
            }
          },
          "itemTypes": {
            "title": "Result types",
            "uniqueItems": true,
            "type": "array",
            "description": "Optional. Keep only these kinds of result. Leave empty for all three. Stations are live radio, podcasts are shows with an episode archive, and episodes are the individual instalments of a podcast.",
            "items": {
              "type": "string",
              "enum": [
                "station",
                "podcast",
                "episode"
              ],
              "enumTitles": [
                "Radio stations",
                "Podcasts and shows",
                "Podcast episodes"
              ]
            }
          },
          "minBitrateKbps": {
            "title": "Minimum stream bitrate (kbps)",
            "minimum": 0,
            "maximum": 512,
            "type": "integer",
            "description": "Optional. Keep only stations streaming at or above this bitrate, for example 128 for CD-like quality. Applies to stations only: podcasts and episodes publish no bitrate and are never dropped by this filter. Use 0 for no bitrate requirement.",
            "default": 0
          },
          "maxBitrateKbps": {
            "title": "Maximum stream bitrate (kbps)",
            "minimum": 0,
            "maximum": 512,
            "type": "integer",
            "description": "Optional. Keep only stations streaming at or below this bitrate, for example 64 for low-bandwidth listening. Applies to stations only: podcasts and episodes publish no bitrate and are never dropped by this filter. Combine with the minimum to select a band. Use 0 for no upper limit.",
            "default": 0
          },
          "minReliabilityPercent": {
            "title": "Minimum reliability score",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Optional. Keep only stations whose uptime score is at or above this percentage. The directory scores every station on how often its stream actually answers, so 90 and above is a working station. Applies to stations only. Use 0 for no reliability requirement.",
            "default": 0
          },
          "streamFormats": {
            "title": "Stream formats",
            "type": "array",
            "description": "Optional. Keep only stations offering at least one of these audio formats, written as the directory writes them, for example mp3 or aac. Applies to stations only. Leave empty for any format.",
            "items": {
              "type": "string"
            }
          },
          "genreIds": {
            "title": "Genre ids",
            "type": "array",
            "description": "Optional. Keep only results the directory files under one of these genre ids, for example g11 for Jazz. Every result returns its own genreId, so one run's output tells you which ids to filter on next. An episode listing publishes no genre, so with Fetch full profiles off this filter excludes episodes; switch profiles on and episodes carry their own genre and are filtered on it like everything else.",
            "items": {
              "type": "string"
            }
          },
          "fetchDetails": {
            "title": "Fetch full profiles",
            "type": "boolean",
            "description": "Read each result's published profile: description, slogan, call sign, dial frequency and band, location and coordinates, language, timezone, the broadcaster's own website, its published contact details, and whether the stream is currently available. One extra request per result. Ignored in URL mode, where the profile is always read because a pasted link has nothing else to read, and is not charged there.",
            "default": false
          },
          "fetchStreams": {
            "title": "Fetch playable stream URLs",
            "type": "boolean",
            "description": "Add each station's playable stream addresses with their bitrate, codec and reliability. One extra request per station. Only stations have a stream, so podcasts and episodes are never asked for one and are never charged for it.",
            "default": false
          },
          "fetchEpisodes": {
            "title": "Fetch podcast episodes",
            "type": "boolean",
            "description": "Add each podcast's published episode list with titles, publication labels, running times and per episode links. One extra request per podcast. Only podcasts have an episode list, so stations and episodes are never asked for one and are never charged for it.",
            "default": false
          },
          "maxEpisodesPerPodcast": {
            "title": "Max episodes per podcast",
            "minimum": 0,
            "type": "integer",
            "description": "Cap on how many episodes are returned inside each podcast record, newest first. Use 0 for every episode the directory publishes for that podcast.",
            "default": 20
          },
          "maxItems": {
            "title": "Max results",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum number of results to return across the whole run. This is the run's cap, and the only setting that limits how much the run returns or costs. Use 0 for unlimited.",
            "default": 20
          },
          "maxPages": {
            "title": "Max result pages per category or link",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum number of listing pages read per browsed category or pasted category link. 0 means no limit, which is the default: the walk then stops only at Max results or at the last page the directory publishes. Does not apply to keyword search, which the directory answers in a single page.",
            "default": 0
          },
          "maxBrowseDepth": {
            "title": "Sub-category depth",
            "minimum": 0,
            "maximum": 4,
            "type": "integer",
            "description": "How many levels of sub-categories the walk may open when a category page holds only sub-categories and no results of its own, which is how most top level categories are published. 0 keeps to the exact addresses you named and returns nothing for those categories. This is a scope choice, not a cost cap: Max results above is what limits the size of the run.",
            "default": 2
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Apify Proxy is recommended. The standard pool is the default and is sufficient for this site. The connection's own location decides which stations the Local radio category returns when you leave Locale coordinates empty.",
            "default": {
              "useApifyProxy": true
            }
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue a large directory pull without returning or charging for results already collected there. Use this after an interrupted run. For recurring daily monitoring of the same scope, use Incremental mode below instead."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily or recurring monitoring. The first run returns every matching result as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED results. What is playing right now and the rolling reliability score drift constantly, so they never count as a change on their own; a station going off air is reported through isAvailable instead. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately for each scope, filter and lookup setup; use State key to name or deliberately share a monitoring campaign.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the mode, scope, filters and lookup settings, so different scopes never mix state with each other. With your own State key, the mode needs a keyword, category, id or link to scan: with none the run stops with an input message and collects nothing. A run that falls back to the example never saves or expires state."
          },
          "emitUnchanged": {
            "title": "Emit unchanged results (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return results that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you want the full snapshot every run.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired results (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return results that were listed in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked scope, so never when Max results capped it or when Resume was used. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Optional. Field names that must NOT make a result count as UPDATED, for example \"bitrateKbps\" or \"streams.url\" (dotted paths reach nested fields). Ignored fields stay in the output and the saved baseline; they are only left out of the comparison and of changedFields. What is playing right now and the rolling reliability score are always ignored. Leave empty to compare every other field.",
            "items": {
              "type": "string"
            }
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write or digest. Leave empty to skip; never changes the dataset output.",
            "items": {
              "type": "string"
            }
          },
          "notionParentPageUrl": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL or id of the Notion page under which result pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max results to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on results written to each connector per run. Does not affect the dataset.",
            "default": 50
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}