YouTube Download API Tutorial with Python, Node.js and PHP

Build a YouTube download API integration with Python, Node.js, or PHP. Send authenticated requests, poll progress, handle errors, and retrieve completed video files.

First request

GET

Use the shared API host unless the dashboard shows an account-specific hostname.

curl --location "https://p.savenow.to/ajax/download.php?format=mp3&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DK1Pu75yJUOE&apikey=YOUR_API_KEY&add_info=1"

Create a download API job

Send a URL-encoded YouTube URL, an output format, and apikey=YOUR_API_KEY to the shared download endpoint. A successful request returns success=true and an id for the new job.

Poll progress

Pass the returned id to /ajax/progress.php. Progress below 1000 is pending regardless of success. At 1000, the job is ready only with success=1 or true and a non-empty download_url; otherwise stop and surface text or message.

Handle ready and error outcomes

Use the URL only when progress=1000, success=1 or true, and download_url is non-empty. A terminal response without a usable URL is a failure; stop polling and surface text or message. Treat non-2xx responses as request errors.

Authentication

Download creation requires the dashboard key in the apikey query parameter. Progress polling does not require the key; it uses only the id returned by the creation request.

Pricing and account handoff

Production downloads consume API key wallet balance according to output format and applicable duration rules. Review pricing before production traffic, then create or manage the key from the account dashboard.

Review API pricing

Feature details

Response fields

Download creation

success confirms whether the job was accepted, id identifies it, content contains a base64-encoded UI snippet, and info is present only when add_info=1.

In progress

Progress below 1000 is pending even when success=0; text can describe the current status.

Ready

Only success=1 or true, progress=1000, and a non-empty download_url identify a completed job and its direct file URL.

Common errors

HTTP 400

Check for a missing url, unknown format, missing or invalid request values, or a duration that requires explicitly enabled extended-duration handling.

HTTP 500

Treat this as a server error, retain the returned error message for diagnostics, and retry according to your application policy.

Failed progress

At progress 1000, treat the job as failed unless success is 1 or true and download_url is non-empty. Stop polling and show text or message, or a generic failure message if neither is present.

Parameters

format Required Requested audio or video output format. Use the dedicated MP3 and MP4 guides for format-specific choices.
url Required URL-encoded YouTube video URL to download.
apikey Required Personal API key copied from the account dashboard.
add_info Optional Set to 1 to include the info object with title and thumbnail metadata in the creation response.
id Progress Job identifier returned by download creation and passed to /ajax/progress.php.
download_url Ready Usable direct file URL returned by progress only when progress=1000 and success is 1 or true.

Request examples

Python requests

python
import requests

response = requests.get(
    "https://p.savenow.to/ajax/download.php",
    params={
        "url": "https://www.youtube.com/watch?v=VIDEO_ID",
        "format": "mp3",
        "apikey": "YOUR_API_KEY",
    },
    timeout=30,
)
response.raise_for_status()
job = response.json()
print(job["id"])

Node.js fetch

javascript
const params = new URLSearchParams({
    url: 'https://www.youtube.com/watch?v=VIDEO_ID',
    format: 'mp3',
    apikey: 'YOUR_API_KEY',
});
const response = await fetch(`https://p.savenow.to/ajax/download.php?${params}`);
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const job = await response.json();
console.log(job.id);

PHP cURL

php
<?php
$query = http_build_query([
    'url' => 'https://www.youtube.com/watch?v=VIDEO_ID',
    'format' => 'mp3',
    'apikey' => 'YOUR_API_KEY',
]);
$handle = curl_init('https://p.savenow.to/ajax/download.php?' . $query);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($handle);
if ($body === false) {
    throw new RuntimeException(curl_error($handle));
}
curl_close($handle);
$job = json_decode($body, true, flags: JSON_THROW_ON_ERROR);
echo $job['id'];

Poll download progress

bash
curl --location "https://p.savenow.to/ajax/progress.php?id=DOWNLOAD_ID"

Important details

Use the canonical reference

The OpenAPI docs remain the source of truth for parameters, schemas, and endpoint behavior as the API evolves.

Open API docs

Keep keys server-side

Replace YOUR_API_KEY at runtime from protected server configuration. Do not publish a production key in browser code or a repository.

Get an API key

Choose a focused workflow

Continue to the format-specific guides when the implementation needs MP3 bitrate, MP4 quality, subtitles, or transcripts.

Open the MP3 guide

Related guides

Continue building

OpenAPI docs

Download YAML or JSON specs and inspect downloader, progress, and subtitle endpoints.

Read docs

Embed resources

Keep button, card, widget, and REST paths reachable for existing users and migrations.

View resources

Common questions

Where do examples run?

Use p.savenow.to for public API examples unless your dashboard shows a custom account hostname.

How do I add credit?

Open the dashboard, create a top-up payment, or redeem a coupon. Balance changes are shown in the account history.

Are old endpoints still supported?

Yes. The .php compatibility endpoints remain active for existing integrations and embedded clients.