Cut clips from any video URL. Manually or with one API call.
Duration:
GIF limited to 30s (current: )
Use these timestamps with POST /v1/clip to clip only the segments you want.
Get $5 free to test when you sign up
Works with any programming language. Here are a few examples.
# Clip a video with one API call
import requests, time
headers = {"Authorization": "Bearer sk_live_..."}
clip = requests.post(
"https://api.fastclip.dev/v1/clip",
headers=headers,
json={
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"start": 30,
"end": 90,
"format": "mp4",
"quality": "1080p"
}
).json()
# Poll until ready
while True:
r = requests.get(f"https://api.fastclip.dev/v1/clip/{clip['job_id']}", headers=headers).json()
if r["status"] == "complete":
print(r["download_url"])
break
time.sleep(2)
// Clip a video with one API call
const response = await fetch(
"https://api.fastclip.dev/v1/clip", {
method: "POST",
headers: {
"Authorization": "Bearer sk_live_...",
"Content-Type": "application/json"
},
body: JSON.stringify({
url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
start: 30, end: 90,
format: "mp4", quality: "1080p"
})
}
);
const clip = await response.json();
// Poll until ready
while (true) {
const r = await fetch(
`https://api.fastclip.dev/v1/clip/${clip.job_id}`,
{ headers: { "Authorization": "Bearer sk_live_..." } }
).then(r => r.json());
if (r.status === "complete") { console.log(r.download_url); break; }
await new Promise(r => setTimeout(r, 2000));
}
# Clip a video with one API call
curl -X POST https://api.fastclip.dev/v1/clip \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"start": 30, "end": 90,
"format": "mp4", "quality": "1080p"
}'
// Clip a video with one API call
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"start": 30,
"end": 90,
"format": "mp4",
"quality": "1080p",
})
req, _ := http.NewRequest("POST",
"https://api.fastclip.dev/v1/clip",
bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer sk_live_...")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
fmt.Println(resp.Status)
}
# Clip a video with one API call
require "net/http"
require "json"
require "uri"
uri = URI("https://api.fastclip.dev/v1/clip")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer sk_live_..."
request["Content-Type"] = "application/json"
request.body = {
url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
start: 30, end: 90,
format: "mp4", quality: "1080p"
}.to_json
response = http.request(request)
clip = JSON.parse(response.body)
job_id = clip["job_id"]
# Poll until ready
loop do
sleep 2
poll = Net::HTTP::Get.new(URI("https://api.fastclip.dev/v1/clip/#{job_id}"))
poll["Authorization"] = "Bearer sk_live_..."
r = JSON.parse(http.request(poll).body)
if r["status"] == "complete"
puts r["download_url"]
break
end
end
// Clip a video with one API call
$response = file_get_contents(
"https://api.fastclip.dev/v1/clip",
false,
stream_context_create([
"http" => [
"method" => "POST",
"header" => implode("\r\n", [
"Authorization: Bearer sk_live_...",
"Content-Type: application/json"
]),
"content" => json_encode([
"url" => "https://youtube.com/watch?v=dQw4w9WgXcQ",
"start" => 30,
"end" => 90,
"format" => "mp4",
"quality" => "1080p"
])
]
])
);
$clip = json_decode($response, true);
// Poll until ready
$ctx = stream_context_create(["http" => [
"header" => "Authorization: Bearer sk_live_..."
]]);
do {
sleep(2);
$r = json_decode(file_get_contents(
"https://api.fastclip.dev/v1/clip/" . $clip["job_id"],
false, $ctx
), true);
} while ($r["status"] !== "complete");
echo $r["download_url"];
Top up your balance programmatically with a saved card. Enable in Settings → API Reload.
# Check balance, list cards, then reload
import requests
headers = {"Authorization": "Bearer sk_live_..."}
# 1. Check current balance
bal = requests.get("https://api.fastclip.dev/v1/balance", headers=headers).json()
print(f"Balance: ${bal['balance']:.2f}")
# 2. List saved cards
cards = requests.get("https://api.fastclip.dev/v1/cards", headers=headers).json()
for c in cards["cards"]:
print(f" {c['brand']} ****{c['last4']}")
# 3. Reload $25 with saved card
reload = requests.post("https://api.fastclip.dev/v1/reload",
headers=headers,
json={"amount": 2500} # cents
).json()
print(f"New balance: ${reload['balance']:.2f}")
# → New balance: $29.90
// Check balance, list cards, then reload
const headers = {
"Authorization": "Bearer sk_live_...",
"Content-Type": "application/json"
};
// 1. Check current balance
const bal = await fetch("https://api.fastclip.dev/v1/balance", { headers })
.then(r => r.json());
console.log(`Balance: $${bal.balance.toFixed(2)}`);
// 2. List saved cards
const cards = await fetch("https://api.fastclip.dev/v1/cards", { headers })
.then(r => r.json());
cards.cards.forEach(c => console.log(` ${c.brand} ****${c.last4}`));
// 3. Reload $25 with saved card
const reload = await fetch("https://api.fastclip.dev/v1/reload", {
method: "POST", headers,
body: JSON.stringify({ amount: 2500 }) // cents
}).then(r => r.json());
console.log(`New balance: $${reload.balance.toFixed(2)}`);
// → New balance: $29.90
# 1. Check current balance
curl https://api.fastclip.dev/v1/balance \
-H "Authorization: Bearer sk_live_..."
# 2. List saved cards
curl https://api.fastclip.dev/v1/cards \
-H "Authorization: Bearer sk_live_..."
# 3. Reload $25 with saved card
curl -X POST https://api.fastclip.dev/v1/reload \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"amount": 2500}'
# → {"success":true,"balance":29.90,...}
// Check balance, list cards, then reload
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func apiGet(url, auth string) map[string]any {
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", auth)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var out map[string]any
json.NewDecoder(resp.Body).Decode(&out)
return out
}
func main() {
auth := "Bearer sk_live_..."
// 1. Check balance
bal := apiGet("https://api.fastclip.dev/v1/balance", auth)
fmt.Printf("Balance: $%.2f\n", bal["balance"])
// 2. List saved cards
cards := apiGet("https://api.fastclip.dev/v1/cards", auth)
for _, c := range cards["cards"].([]any) {
card := c.(map[string]any)
fmt.Printf(" %s ****%s\n", card["brand"], card["last4"])
}
// 3. Reload $25
body, _ := json.Marshal(map[string]any{"amount": 2500})
req, _ := http.NewRequest("POST",
"https://api.fastclip.dev/v1/reload",
bytes.NewBuffer(body))
req.Header.Set("Authorization", auth)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
// → {"success":true,"balance":29.90,...}
}
# Check balance, list cards, then reload
require "net/http"
require "json"
http = Net::HTTP.new("api.fastclip.dev", 443)
http.use_ssl = true
auth = "Bearer sk_live_..."
# 1. Check balance
req = Net::HTTP::Get.new("/v1/balance")
req["Authorization"] = auth
bal = JSON.parse(http.request(req).body)
puts "Balance: $#{'%.2f' % bal['balance']}"
# 2. List saved cards
req = Net::HTTP::Get.new("/v1/cards")
req["Authorization"] = auth
cards = JSON.parse(http.request(req).body)
cards["cards"].each { |c| puts " #{c['brand']} ****#{c['last4']}" }
# 3. Reload $25
req = Net::HTTP::Post.new("/v1/reload")
req["Authorization"] = auth
req["Content-Type"] = "application/json"
req.body = { amount: 2500 }.to_json
reload = JSON.parse(http.request(req).body)
puts "New balance: $#{'%.2f' % reload['balance']}"
# → New balance: $29.90
// Check balance, list cards, then reload
$auth = "Authorization: Bearer sk_live_...";
// 1. Check balance
$bal = json_decode(file_get_contents(
"https://api.fastclip.dev/v1/balance", false,
stream_context_create(["http" => ["header" => $auth]])
), true);
echo "Balance: $" . number_format($bal["balance"], 2) . "\n";
// 2. List saved cards
$cards = json_decode(file_get_contents(
"https://api.fastclip.dev/v1/cards", false,
stream_context_create(["http" => ["header" => $auth]])
), true);
foreach ($cards["cards"] as $c) {
echo " {$c['brand']} ****{$c['last4']}\n";
}
// 3. Reload $25 with saved card
$r = json_decode(file_get_contents(
"https://api.fastclip.dev/v1/reload", false,
stream_context_create(["http" => [
"method" => "POST",
"header" => implode("\r\n", [
$auth,
"Content-Type: application/json"
]),
"content" => json_encode(["amount" => 2500])
]])
), true);
echo "New balance: $" . number_format($r["balance"], 2);
// → New balance: $29.90
Don't know the timestamps? Just describe what you want and our AI finds and clips the right moments.
Tell us what you're looking for in plain English. "The part about machine learning" or "when the host laughs."
Our AI processes the video's content, using transcripts for YouTube or audio analysis for other sites, to find matching moments.
Multiple matching segments? You get multiple clips. Each additional segment is just $0.10 extra. Download them all instantly.
Example Request
POST /v1/clip/auto
{
"url": "https://youtube.com/watch?v=...",
"query": "the part about neural networks",
"format": "mp4",
"quality": "1080p"
}
Analyze Only: from $0.10
Just want the timestamps? The /v1/clip/analyze endpoint returns matching segments with confidence scores and transcript excerpts when available. No output clip is rendered, and no format or quality is needed.
POST /v1/clip/analyze
{
"url": "https://youtube.com/watch?v=...",
"query": "all mentions of machine learning"
}
// Response:
{
"segments": [{
"start": 45, "end": 112,
"excerpt": "...where machine learning really changed the game...",
"confidence": 0.92
}],
"cost": 0.10
}
Pair with POST /v1/clip to clip only the segments you want.
Coming soon
Deposit funds ($5 minimum), clip videos.
Base URL
https://api.fastclip.dev/v1
Request
{
"url": "https://youtube.com/watch?v=..."
}
Response
{
"title": "Video Title",
"duration": 3600.5,
"thumbnail": "https://...",
"preview_url": null,
"preview_embed_url": "https://...",
"max_height": 1080
}
No auth required. Use to validate URLs, check duration (for cost estimates), and confirm platform support before clipping.
Request
{
"url": "https://youtube.com/watch?v=...",
"start": 120,
"end": 180,
"format": "mp4",
"quality": "1080p"
}
Response
{
"job_id": "a1b2c3d4e5f6g7h8",
"status": "pending"
}
Request
{
"url": "https://youtube.com/watch?v=...",
"query": "the part about neural networks",
"format": "mp4",
"quality": "720p"
}
Response
{
"job_id": "x1y2z3a4b5c6d7e8",
"status": "pending",
"reserved": 0.20
}
Request
{
"url": "https://youtube.com/watch?v=...",
"query": "all mentions of machine learning"
}
Response
{
"segments": [{
"start": 45,
"end": 112,
"excerpt": "...where machine learning really changed the game...",
"confidence": 0.92
}],
"cost": 0.10
}
From $0.10 (scales with video length). No output clip is rendered. Excerpts contain transcript text when available (and may be empty on some sources). Pair with POST /v1/clip to clip only the segments you want.
Response (complete)
{
"job_id": "a1b2c3d4e5f6g7h8",
"status": "complete",
"progress": 100,
"status_message": "Done!",
"download_url": "https://r2.../abc123.mp4",
"file_name": "clip_2-00-3-00.mp4",
"cost": 0.10
}
Status values include pending → analyzing (auto only) → downloading → processing/processing segment N/M → uploading → complete. On failure: failed with error field. Auto-clips return a clips array with per-segment download URLs.
Clip Management
Response
{
"clips": [{
"id": "a1b2c3d4e5f6g7h8",
"name": "Intro Section",
"format": "mp4",
"quality": "1080p",
"duration": 60,
"file_size": 1048576,
"pinned": true,
"expires_at": null,
"hours_left": null,
"download_url": "https://r2.../a1b2c3.mp4",
"share_url": "/c/a1b2c3d4e5f6g7h8",
"aspect_ratio": "16:9",
"source_title": "My Source Video",
"created": "2026-03-30T12:00:00Z"
}],
"page": 1,
"per_page": 20,
"total_items": 47,
"total_pages": 3
}
Paginated, most recent first. Query params: ?page=1&per_page=20
Request
{
"name": "Final Intro Cut"
}
Response
{
"id": "a1b2c3d4e5f6g7h8",
"name": "Final Intro Cut"
}
Response
{
"id": "a1b2c3d4e5f6g7h8",
"pinned": true
}
Pinned clips count against your storage quota. Returns error if quota exceeded.
Response
{
"id": "a1b2c3d4e5f6g7h8",
"pinned": false,
"expires_at": "2026-03-31T12:00:00+00:00"
}
Response
{
"id": "a1b2c3d4e5f6g7h8",
"deleted": true,
"storage_freed": 40509 // bytes
}
This permanently deletes the clip from storage. This action cannot be undone.
Account
Response
{
"balance": 4.90
}
Response
{
"cards": [{
"id": "card_1a2b3c",
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2027
}]
}
Listing cards does not require API Reload to be enabled. Cards can only be added/removed via the dashboard UI.
Request
{
"amount": 2500, // cents ($25)
"reload_password": "..." // if set
}
Response
{
"success": true,
"payment_intent_id": "pi_3T...",
"amount": 2500,
"balance": 29.90
}
$5–$500 per reload. Rate limit: 10/hour. Requires API Reload enabled in Settings. If email confirmation is on, returns pending status and sends an approval email.
Authorization: Bearer sk_live_...
Generate API keys from your account dashboard. Max 10 keys per account. Exception: /v1/clip/info requires no auth.
API-key requests: 60 req/min per key. Clip jobs: 20/hour per user. Reloads: 10/hour. Unauthenticated endpoints are IP-limited.
X-RateLimit-Remaining: 8
X-RateLimit-Reset: 1711814400
Retry-After: 42 // on 429 only
A plain-text reference covering every endpoint, pricing rule, format, limit, and policy. Optimised for LLMs to read and reason about.
https://fastclip.dev/llm
Everything else you need to know when integrating.
All errors return JSON with a detail field:
{ "detail": "Insufficient balance" }
400 Bad request
404 Not found
401 Invalid API key
409 Storage quota full
402 Low balance
422 Unsupported URL
429 Rate limited (check Retry-After)
✓ youtube.com
… More coming soon
Others return 422
Auto-downgrades if source is lower. high=1080p, medium=720p
New clips expire in 24 hours by default
Pin to keep permanently (counts against storage)
Unpin starts a new 24hr countdown
Expired clips return 404. Download URLs are presigned & regenerated on each request.
Auto-clip: +$0.10 per extra segment. Cost reserved upfront, unused amount refunded.
1 GB free per account. Only pinned clips count.
Check: GET /v1/storage
Buy: POST /v1/storage/purchase { "gb": 5 }
Each clip gets a public URL. No auth needed to view.
Page: /c/{clip_id}
API: GET /v1/share/{clip_id}
Returns name, format, duration, stream & download URLs. Expires with clip.
Don't have an account?
Already have an account?
We've sent a verification link to:
Click it to activate your account and receive your $5.00 free credit.
Didn't get the email?
Your account is now active and you've received a $5.00 welcome credit.
Log in to start clipping.
Enter your email and we'll send a reset link.
If an account exists for that email, a reset link has been sent.
Check your inbox and spam folder.
All deposits are non-refundable. Funds remain in your account until used. Balance is forfeited if account is deleted.
Minimum deposit is $5.00
Processing payment…
New balance: $
New key created. Copy it now, you won't see it again:
Created
Revoke this key? API calls using it will stop working.
A confirmation link will be sent to your email. Password won't change until you click it.
Enable API Reload
Allow reloading balance via API with saved cards
Email Confirmation
Require email approval before each reload
No password or email confirmation set. Anyone with your API key can reload your saved cards without any additional verification.
Max amount per single API reload. Rate limit: 10 reloads/hour.
This action is permanent and cannot be undone.
Your remaining balance of $ will be forfeited. Deposited funds are non-refundable.
We typically respond within 24 hours.
Responses will be sent to .
We'll get back to you at within 24 hours.
Choose which emails you'd like to receive.
Security emails (password resets, account deletion) cannot be disabled.
Your email preferences have been updated.
Download links expire after 24 hours unless pinned to storage.
Pinned clips use storage. Buy more storage anytime — one-time, no recurring fees.
One-time purchase. Storage is added permanently to your account.
$0.99 per GB. Minimum 1 GB.
One-time purchase from your account balance
Permanent storage add-on
This storage is added to your account permanently. No recurring fees. Storage purchases are non-refundable and tied to your account.
This storage is yours permanently. No recurring fees.