Publish pins
Create a pin with POST /v1/pins. This page covers every field on the request, the media options, and the state a pin moves through after you submit it.
Prerequisites
- An API key in the
X-API-Keyheader. See Authentication. - A connected Pinterest account (
account_id) and a board on it (board_id). - Media: either a public
image_url, or an uploadedasset_id. See Upload media.
Pin fields
Every request is a PinCreate object.
Required
| Field | Type | Notes |
|---|---|---|
account_id |
UUID | The connected Pinterest account to publish with. |
board_id |
string | The Pinterest board id. |
title |
string | Max 100 characters. |
idempotency_key |
string | Max 255 characters. Required, never auto-generated. Reusing a key returns the existing pin instead of creating a duplicate. |
one of image_url / asset_id |
string | Exactly one is required (see Media options). |
Optional
| Field | Type | Notes |
|---|---|---|
description |
string | Max 800 characters. |
related_terms |
string[] | Related terms for Pinterest. Also accepts a comma-separated string. |
alt_text |
string | Max 500 characters. Accessibility text. |
dominant_color |
string | 6-digit hex, optional leading # (for example #6E7874); normalized to upper-case. |
link_url |
string | Destination URL, max 2048 characters. |
cover_image_url |
string | Public cover image URL. Video pins only. |
cover_image_asset_id |
UUID | Uploaded image asset used as a video cover. Video pins only. |
Media options
Provide the pin’s media in exactly one way:
- Public image URL — set
image_url. Works on every plan. - Uploaded asset — set
asset_idfrom an uploaded image or video. Paid plans only; see Upload media.
Notes:
- Provide exactly one of
image_url/asset_id. Both missing or both present each return422. - A video pin is created by referencing an uploaded video
asset_id. There is novideo_urlfield. - Cover images (
cover_image_url/cover_image_asset_id) apply only to video pins, and you may set at most one of the two.
Heads up: Pinterest can change your title. When your pin has a
link_url, Pinterest re-scrapes that destination page and may override your pin title with the page’s Open Graph / meta tags. If your published title doesn’t match what you sent, this is almost always why. Control it by setting goodog:title(andog:description) meta tags on the destination page. This is the most common “my title changed” surprise.
Publish a pin
curl
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 first PinBridge pin",
"description": "A short, useful description.",
"link_url": "https://example.com/product",
"image_url": "https://example.com/pin.png",
"idempotency_key": "publish-demo-001"
}'
Response (201, trimmed):
{
"id": "8a3f6c12-4d5e-4b7a-9c01-2e6f8d4b7a93",
"status": "queued",
"media_type": "image",
"title": "My first PinBridge pin",
"board_id": "987654321098765432",
"idempotency_key": "publish-demo-001",
"pinterest_pin_id": null,
"error_code": null
}
The pin is accepted as queued and published by a background worker. Poll its status or use a webhook to learn the outcome.
Python SDK
from pinbridge_sdk import PinbridgeClient
from pinbridge_sdk.models import PinCreate
with PinbridgeClient(api_key="$PINBRIDGE_API_KEY") as client:
pin = client.pins.create(
PinCreate(
account_id="6f1c2e4a-3b7d-4c9e-8a21-5d0f9b3e7c41",
board_id="987654321098765432",
title="My first PinBridge pin",
image_url="https://example.com/pin.png", # or asset_id="e3a7c5f9-1b4d-4c8e-a2f6-7d9b3e5a1c80"
link_url="https://example.com/product",
idempotency_key="publish-demo-001",
)
)
print(pin.id, pin.status)
idempotency_key is a required field on PinCreate. To publish a video pin, drop image_url and pass asset_id for an uploaded video.
n8n
Use the PinBridge node with Resource: Pin, Operation: Publish. Choose the Media Source (Uploaded Asset or Public Image URL) and fill in Title, Board, and the account Connection. The Idempotency Key field defaults to ={{$execution.id + "-" + $itemIndex}}, which gives each item a stable, unique key.
Pin states
A pin moves through these statuses:
queued→publishing→publishedon success (setspinterest_pin_idandpublished_at).failedon a non-retryable error (setserror_codeanderror_message).- Retryable errors move the pin to
deferredand auto-retry, up to 8 deferrals, before finally becomingfailed.
Common failure error_code values include rate_limited, token_expired, token_revoked, scope_missing, board_access_denied, transient_upstream, media_url_unreachable, invalid_payload, and publish_timeout. See Rate limits and quotas for how retries and quota interact.
To reprocess failures: POST /v1/pins/{pin_id}/retry (only failed pins; otherwise 409), or the bulk endpoints POST /v1/pins/bulk-retry and POST /v1/pins/bulk-delete.
Verify it worked
- Fetch the pin with
GET /v1/pins/{pin_id}(SDK:client.pins.get(pin_id)) and checkstatus. - When
statusispublished,pinterest_pin_idholds the id of the live Pinterest pin. - For push notifications instead of polling, subscribe to
pin.publishedandpin.failedwebhooks.
Common errors
| Status | Cause |
|---|---|
| 422 | Either image_url or asset_id must be provided / Provide either image_url or asset_id, not both. |
| 422 | Missing a required field such as account_id, or title over 100 chars. |
| 403 | feature_unavailable — used an asset_id on the Free plan. Use a public image_url or upgrade. |
| 400 | cover_image_url is only supported for video pins. |
Next steps
- Upload media — host images and videos and publish by
asset_id. - Schedule pins — publish the same payload at a future time.
- Webhooks — get
pin.published/pin.failedevents. - Rate limits and quotas — publishing quotas and retry behavior.
