Schedule pins
Publish a pin at a future time with POST /v1/schedules. A schedule carries the same media and pin details you’d send to Publish pins, plus a run_at timestamp. A background task materializes the pin when the time arrives.
Prerequisites
- An API key in the
X-API-Keyheader. See Authentication. - A connected Pinterest account (
account_id) and aboard_id. - Media: a public
image_urlor an uploadedasset_id. See Upload media.
Fields a schedule supports
A ScheduleCreate accepts:
| Field | Required | Notes |
|---|---|---|
account_id |
yes | Connected Pinterest account (UUID). |
run_at |
yes | Future ISO 8601 timestamp with a timezone offset (see below). |
board_id |
yes | Pinterest board id. |
title |
yes | Max 100 characters. |
description |
no | Max 800 characters. |
alt_text |
no | Accessibility text, max 500 characters. The pin keeps it when the schedule runs. |
link_url |
no | Destination URL, max 2048 characters. |
one of image_url / asset_id |
yes | Exactly one, same rule as publishing. |
cover_image_url / cover_image_asset_id |
no | Video pins only; at most one. |
Schedule fields vs. publish fields
One PinCreate field is not part of ScheduleCreate: dominant_color. If you need it, publish directly with Publish pins instead of scheduling. alt_text works on both.
run_at rules
- Must include an explicit timezone offset (for example
2026-12-25T09:00:00-05:00or...Z). A naive timestamp is rejected with422. It’s normalized to UTC on the server. - Must be in the future, else
400 run_at must be in the future.
Create a schedule
curl
curl -X POST https://api.pinbridge.io/v1/schedules \
-H "X-API-Key: $PINBRIDGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"account_id": "6f1c2e4a-3b7d-4c9e-8a21-5d0f9b3e7c41",
"board_id": "987654321098765432",
"title": "Holiday promo pin",
"image_url": "https://example.com/pin.png",
"link_url": "https://example.com/promo",
"alt_text": "Gift boxes wrapped in red paper under a decorated tree",
"run_at": "2026-12-25T09:00:00-05:00"
}'
Response (201, trimmed):
{
"id": "c4e2a9b1-7d3f-4e6a-8b50-1f9d2c7e3a64",
"pinterest_account_id": "6f1c2e4a-3b7d-4c9e-8a21-5d0f9b3e7c41",
"run_at": "2026-12-25T14:00:00Z",
"status": "scheduled",
"pin_id": null,
"last_error": null
}
Python SDK
from datetime import datetime, timezone
from pinbridge_sdk import PinbridgeClient
from pinbridge_sdk.models import ScheduleCreate
with PinbridgeClient(api_key="$PINBRIDGE_API_KEY") as client:
schedule = client.schedules.create(
ScheduleCreate(
account_id="6f1c2e4a-3b7d-4c9e-8a21-5d0f9b3e7c41",
board_id="987654321098765432",
title="Holiday promo pin",
image_url="https://example.com/pin.png",
run_at=datetime(2026, 12, 25, 14, 0, tzinfo=timezone.utc),
)
)
print(schedule.id, schedule.status)
run_at must be timezone-aware.
n8n
Use the PinBridge node with Resource: Schedule, Operation: Create. Set Run At (a dateTime), the Connection, Board, Title, and Media Source. From node version 1.3.1 the schedule form also has Alt Text. Dominant Color is publish-only, matching the API.
Schedule statuses
A schedule’s status is one of:
scheduled → queued → running → done on success. Retryable errors go to deferred; a hard failure is failed; a canceled schedule is canceled. Once the pin is created you can follow it with pin_id and the pin’s own publish states.
Manage schedules
List and fetch
curl "https://api.pinbridge.io/v1/schedules?limit=50&offset=0" \
-H "X-API-Key: $PINBRIDGE_API_KEY"
curl "https://api.pinbridge.io/v1/schedules/c4e2a9b1-7d3f-4e6a-8b50-1f9d2c7e3a64" \
-H "X-API-Key: $PINBRIDGE_API_KEY"
Cancel, retry, delete
# Cancel a pending schedule
curl -X POST https://api.pinbridge.io/v1/schedules/c4e2a9b1-7d3f-4e6a-8b50-1f9d2c7e3a64/cancel \
-H "X-API-Key: $PINBRIDGE_API_KEY"
# Retry a failed schedule
curl -X POST https://api.pinbridge.io/v1/schedules/c4e2a9b1-7d3f-4e6a-8b50-1f9d2c7e3a64/retry \
-H "X-API-Key: $PINBRIDGE_API_KEY"
# Delete a schedule (returns 204 No Content)
curl -X DELETE https://api.pinbridge.io/v1/schedules/c4e2a9b1-7d3f-4e6a-8b50-1f9d2c7e3a64 \
-H "X-API-Key: $PINBRIDGE_API_KEY"
Cancel, retry, and delete are status-dependent: you’ll get a 400 such as Cannot cancel schedule with status <status>, Cannot retry schedule with status <status>, or Cannot delete schedule with status <status>; cancel it first. when the current status doesn’t allow the action.
In the SDK: client.schedules.cancel(id), client.schedules.retry(id), client.schedules.delete(id).
Bulk actions
Each bulk endpoint takes { "ids": [...] } with up to 500 ids.
curl -X POST https://api.pinbridge.io/v1/schedules/bulk-cancel \
-H "X-API-Key: $PINBRIDGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ids": ["c4e2a9b1-7d3f-4e6a-8b50-1f9d2c7e3a64", "9f5b3d1e-2a7c-4b8d-a4e6-6c0f1b9d5e27"]}'
Response (200, trimmed):
{
"succeeded_count": 1,
"skipped_count": 1,
"failed_count": 0,
"results": [
{"id": "c4e2a9b1-7d3f-4e6a-8b50-1f9d2c7e3a64", "status": "succeeded"},
{"id": "9f5b3d1e-2a7c-4b8d-a4e6-6c0f1b9d5e27", "status": "skipped", "error_code": "ineligible_status"}
]
}
The same shape applies to POST /v1/schedules/bulk-retry and POST /v1/schedules/bulk-delete (SDK: client.schedules.bulk_cancel(ids), bulk_retry(ids), bulk_delete(ids)).
Verify it worked
- The create response returns
201withstatus: scheduledand therun_atnormalized to UTC. - Fetch with
GET /v1/schedules/{schedule_id}and watchstatusadvance. - Once
pin_idis set, follow the pin withGET /v1/pins/{pin_id}or a webhook.
Common errors
| Status | Cause |
|---|---|
| 422 | run_at missing a timezone offset, or a missing required field. |
| 400 | run_at must be in the future. |
| 400 | Cannot cancel / retry / delete schedule with status <status>. |
| 403 | feature_unavailable — used an asset_id on the Free plan. |
Next steps
- Publish pins — publish immediately, and the full field reference.
- Upload media — host media and schedule an asset-backed pin.
- Webhooks — get notified when a scheduled pin publishes or fails.
- Rate limits and quotas — how scheduled publishes count against quota.
