Quick reference
| Limit / capability | Value |
|---|---|
| Description (text) | mapped to Pinterest description; no documented grapheme cap (Pinterest enforces a soft 800-char display limit) |
| Title | optional, free-form |
| Media items per pin | 1 (image or video; no carousel in v1) |
| Image formats | jpeg, png, webp |
| Image size | 20,000,000 bytes (20 MB) |
| Video formats | mp4, mov, m4v |
| Video size | 2,000,000,000 bytes (~2 GB) |
| Board | required (per-post pinterest.boardId or account default) |
| Destination URL | optional click-through; defaults to the image URL |
| Cover image URL | required for video pins (Pinterest mandates a still-frame URL) |
| Post types supported | image pin, video pin |
| Scheduling | Yes (via scheduledAt) |
| Reply / first comment | Not supported in v1 |
| Inbox / DM | Not supported in v1 |
| Analytics | Not supported in v1 |
Connect an account
POST /v1/accounts/connect/pinterest. OAuth 2.0. After the callback the provider calls GET /v5/user_account to pin platformAccountId to the real Pinterest user id.
Scopes
pins:read_secret (off by default) for callers that publish to secret boards.
Token lifecycle
30-day access tokens, refreshable. The provider refreshes ~24 h before expiry; subscribe totoken.expiring to know when a re-auth window is coming.
Post types
Image pin
image-pin.json
options extension is optional. If you set a default board on the account, options.boardId can be omitted; if you don’t supply destinationUrl we fall back to the image’s letmepost URL.
Video pin
coverImageUrl is required — Pinterest mandates a still-frame URL for the pre-play poster. Preflight rejects video pins without it (pinterest.video.cover_required) so you don’t lose the upload to a vague upstream 400.
video-pin.json
POST /v5/media— register an upload slot. Failures:pinterest.media.register_failed.- Multipart POST to the presigned S3 endpoint. Failures:
pinterest.video.upload_failed. - Poll
GET /v5/media/{id}every 2 s up to a 5-minute deadline. Failures:pinterest.video.transcode_failed,pinterest.video.transcode_timeout. POST /v5/pinswithmedia_source: { source_type: "video_id", media_id, cover_image_url }.
Wisdom (platform-specific things that bite)
Common errors
| Error rule | What it means | How to fix |
|---|---|---|
pinterest.board.required | No boardId per-post and no account default | Pass pinterest.boardId or set a default board on the account. |
pinterest.media.required | No media on the pin | Attach media: [{ kind: "image" / "video", … }]. |
pinterest.media.single_only | More than one media item | Send a single media item; carousel pins aren’t in v1. |
pinterest.video.cover_required | Video pin without coverImageUrl | Pass pinterest.coverImageUrl pointing at a public still frame. |
pinterest.image.mime_allowed | Image URL served an unsupported mime | Serve jpeg/png/webp from the URL. |
pinterest.image.size_max | Image > 20 MB | Compress under 20,000,000 bytes. |
pinterest.image_url.reachable | Pinterest couldn’t fetch the image URL | Verify it’s publicly reachable and returns 2xx. |
pinterest.cover_image_url.reachable | Cover image URL unreachable | Verify the cover URL is publicly reachable + serves an image mime. |
pinterest.video.transcode_failed | Pinterest’s transcoder rejected the video | Re-encode the source (H.264 + AAC in an MP4 container is the safe path). |
pinterest.video.transcode_timeout | Transcode poll exceeded 5 minutes | Retry; large videos occasionally exceed the SLA. |
What you can’t do (yet)
- Carousel pins (multi-image).
- Idea pins.
- Tagging products on a pin.
- Reading pin engagement (saves, impressions).
- Comments on pins.
- Posting to secret boards without the extended
pins:read_secretscope.
API reference
POST /v1/posts— primary publish.POST /v1/media— upload images/videos formediaIdreferences.POST /v1/accounts/connect/pinterest— start a Pinterest OAuth flow.

