{
  "openapi": "3.0.1",
  "info": {
    "title": "TuneIn Scraper: Radio Stations, Podcasts & Stream URLs",
    "description": "Scrape the TuneIn directory by keyword, category, genre, location or pasted link. Returns stations and podcasts with artwork, genre, bitrate, call sign, frequency, location, language, website, contact, playable stream URLs and episode lists. Incremental mode tracks changes.",
    "version": "1.0",
    "x-build-id": "a8bd1BkGNxRla9lSw"
  },
  "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'.",
            "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.",
            "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 and podcast addresses, tun.in share links, and bare directory ids such as s34682, p1008289 or c57943. In this mode the full profile is always read, so a pasted link never returns an empty shell.",
            "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
          },
          "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
          },
          "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."
          },
          "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
          },
          "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
            }
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}