Skip to content

POST /v1/uploads/from-url

Useful when you have an ephemeral link that needs a permanent home: an image-generation API result, a screenshot service URL, a search-result thumbnail, anything you would otherwise download then re-upload. dropkit fetches the source, streams it into R2, and returns the CDN URL in one round trip.

Request

POST https://api.dropkit.app/v1/uploads/from-url
Authorization: Bearer sk_live_...
Content-Type: application/json
{
"url": "https://example.com/photo.jpg",
"name": "hero.jpg",
"visibility": "public",
"metadata": { "source": "openai-image" }
}
fieldrequiredwhat it is
urlyesAbsolute https URL. Must resolve to a public address. http, localhost, and private IPs are rejected.
namenoOverride the stored filename. Defaults to the last path segment of the URL (decoded). Falls back to upload.<ext> if neither is usable.
visibilitynopublic (default) or private. Private files require a signed URL to read.
metadatanoOptional string -> string map stored with the file.

Response

{
"id": "ggdhhwrfarqp",
"url": "https://cdn.dropkit.app/ggdhhwrfarqp/hero.jpg",
"name": "hero.jpg",
"size": 283910,
"type": "image/jpeg",
"visibility": "public"
}

Status 201. The URL is immediately live. Same response shape as POST /v1/upload.

Auth

Real project key only. Browser (pk_live_*) and server (sk_live_*) keys both work; the bundled demo key (pk_demo_*) is rejected to prevent the public demo from being used as a free egress mirror.

Browser keys must satisfy the project’s origin allowlist as usual.

Size enforcement

dropkit issues a HEAD first to learn Content-Length and Content-Type. If the source declares a size, it is checked against the plan’s per-file cap (100 MB Free, 5 GiB paid) up front. If the size is unknown or the source lies, the GET stream is capped at the plan limit and aborted on overflow.

Per-plan storage caps and metered overage apply the same as for direct uploads.

SDK

import { uploadFromUrl } from '@dropkit/sdk';
const { data, error } = await uploadFromUrl(
'https://example.com/photo.jpg',
{ key: 'sk_live_...' },
);
if (error) throw new Error(error.message);
console.log(data.url);

Or with a client:

const client = dropkit({ key: process.env.DROPKIT_KEY });
const { data } = await client.uploadFromUrl('https://example.com/photo.jpg');

CLI

dropkit upload detects when the argument is an http(s):// URL and routes through this endpoint:

Terminal window
dropkit upload https://example.com/photo.jpg

Requires a real key (saved via dropkit login, set via DROPKIT_KEY, or passed as --key). The demo fallback only applies to local file paths.

MCP

Agents call the dropkit_upload_url tool. See the MCP docs.

Errors

HTTPcodemeaning
400bad_urlurl missing or not a valid absolute URL
400bad_url_schemeurl is not https
400host_blockedHostname is localhost or a private/loopback/link-local IP
400bad_visibilityvisibility is not public or private
400empty_bodySource URL returned 0 bytes
401missing_auth / invalid_keyAuth header missing or unrecognized
402billing_past_due / quota_exceededOwner is past-due, or the file would exceed the storage cap
403demo_not_allowedDemo key cannot use URL ingest
403origin_not_allowedBrowser key origin not on the allowlist
413file_too_largeSource declared or streamed beyond the plan’s per-file cap
502fetch_failedThe remote URL did not return 2xx, or could not be reached
502ingest_failedStream into storage failed mid-flight