Home / Docs / Upload media

Upload media (images and videos)

Host your pin media on PinBridge, then publish pins that reference it by asset_id. This is the alternative to pointing a pin at a public image_url, and it’s the only way to publish a video pin.

Prerequisites

  • A paid plan. Uploads are a paid feature: the Playground (Free) plan cannot upload assets (you’ll get a 403). On Free, publish with a public image_url instead (see Publish pins).
  • An API key, sent in the X-API-Key header. See Authentication.
  • Your files must be one of the supported formats below.

When to upload vs. use a public URL

You have two ways to give a pin its media:

  • Public image_url — PinBridge fetches the image from a URL you host. Works on every plan, images only.
  • Uploaded asset_id — you upload the file to PinBridge first, then reference the returned asset. Required for video pins, and useful when you don’t have a public URL. Paid plans only.

Assets have no expiry. They persist until you delete them.

Supported formats

Media Content types
Image image/gif, image/jpeg, image/png, image/webp
Video video/mp4, video/quicktime (.mov)

Any other content type is rejected with 400 Unsupported image content type (or ... video content type).

Size limits

Per-file limits are set by your plan:

Plan Image per file Video per file
Playground (Free) Uploads blocked Uploads blocked
Starter 10 MiB 250 MiB
Growth 50 MiB 500 MiB
Agency 100 MiB 1 GiB
Enterprise 100 MiB 1 GiB

Files over the limit return 400 file_too_large.

Your organization also has a total disk quota across all uploaded assets:

Plan Storage quota
Playground (Free) 0 (uploads blocked)
Starter 2 GiB
Growth 7 GiB
Agency 20 GiB
Enterprise 20 GiB

When an upload would exceed the org quota, it returns 402 storage_quota_exceeded. Delete unused assets or upgrade to free space.

Upload an image

POST /v1/assets/images is a multipart/form-data request with a single file field.

curl

curl -X POST https://api.pinbridge.io/v1/assets/images \
  -H "X-API-Key: $PINBRIDGE_API_KEY" \
  -F "file=@/path/to/pin.png;type=image/png"

Response (201, trimmed):

{
  "id": "e3a7c5f9-1b4d-4c8e-a2f6-7d9b3e5a1c80",
  "asset_type": "image",
  "original_filename": "pin.png",
  "content_type": "image/png",
  "file_size_bytes": 148213,
  "file_size_display": "144.7 KiB",
  "referenced_by_pin_count": 0,
  "public_url": "https://api.pinbridge.io/v1/assets/e3a7c5f9-1b4d-4c8e-a2f6-7d9b3e5a1c80/content"
}

Keep the id. That’s the asset_id you’ll pass when publishing.

Python SDK

from pinbridge_sdk import PinbridgeClient

with PinbridgeClient(api_key="$PINBRIDGE_API_KEY") as client:
    asset = client.assets.upload_image("/path/to/pin.png")
    print(asset.id, asset.asset_type, asset.public_url)

upload_image also accepts raw bytes or a file object; pass filename= / content_type= if you do. The SDK does not read environment variables, so pass api_key= explicitly.

n8n

Use the PinBridge node with Resource: Asset, Operation: Upload Image. The file comes from the item’s binary data: set Binary Property to the property that holds the file (default data). Chain it after a node that produces binary data (for example an HTTP Request or Read Binary File node).

Upload a video

Same shape, at POST /v1/assets/videos.

curl -X POST https://api.pinbridge.io/v1/assets/videos \
  -H "X-API-Key: $PINBRIDGE_API_KEY" \
  -F "file=@/path/to/clip.mp4;type=video/mp4"

The response is the same AssetResponse shape, with "asset_type": "video". In n8n, use Operation: Upload Video; in the SDK, client.assets.upload_video(...).

Publish a pin from an asset

Reference the asset by asset_id when you create the pin. Provide exactly one of image_url or asset_id, never both.

curl -X POST https://api.pinbridge.io/v1/pins \
  -H "X-API-Key: $PINBRIDGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "6f1c2e4a-3b7d-4c9e-8a21-5d0f9b3e7c41",
    "board_id": "987654321098765432",
    "title": "My pin",
    "asset_id": "e3a7c5f9-1b4d-4c8e-a2f6-7d9b3e5a1c80",
    "idempotency_key": "upload-demo-001"
  }'

The pin’s media type is derived from the asset: an image asset produces an image pin, a video asset produces a video pin. There is no separate video_url field. For the full list of pin fields, see Publish pins.

Video cover images

The cover image for a video pin is a field on the pin, not on the asset. On PinCreate (and ScheduleCreate), set one of:

  • cover_image_url — a public image URL, or
  • cover_image_asset_id — an uploaded image asset’s id.

Rules:

  • Cover fields are only accepted for video pins. Setting a cover on an image pin returns 400 cover_image_url is only supported for video pins.
  • cover_image_asset_id must reference an image asset (not a video), else 400.
  • Provide at most one of the two cover fields, else 422.

Verify it worked

  • The upload response returns 201 with the asset id and public_url.
  • Fetch the asset later with GET /v1/assets/{asset_id} (SDK: client.assets.get(asset_id)).
  • After you publish, referenced_by_pin_count reflects how many pins use the asset.

Common errors

Status Code / message Cause
403 feature_unavailable Uploads are not available on the Free plan. Use a public image_url, or upgrade.
400 Unsupported image content type / ... video content type File type is not in the supported list.
400 file_too_large File exceeds your plan’s per-file limit.
400 Uploaded file is empty The file part had no bytes.
402 storage_quota_exceeded Org disk quota is full. Delete assets or upgrade.

Next steps

Last updated September 13, 2026Was this page helpful? Tell us →