Skip to main content
Before you start. Pinterest gates pin creation on production (api.pinterest.com) until your app passes Standard Access review — Trial Access apps must point at api-sandbox.pinterest.com. letmepost reads PINTEREST_API_BASE from env, so during the trial window you set it to the sandbox host and clear it back to default the moment your app goes Standard.

Quick reference

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

Extended: 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 to token.expiring to know when a re-auth window is coming.

Post types

Image pin

image-pin.json
The 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
Behind the scenes the publisher runs four steps for video:
  1. POST /v5/media — register an upload slot. Failures: pinterest.media.register_failed.
  2. Multipart POST to the presigned S3 endpoint. Failures: pinterest.video.upload_failed.
  3. Poll GET /v5/media/{id} every 2 s up to a 5-minute deadline. Failures: pinterest.video.transcode_failed, pinterest.video.transcode_timeout.
  4. POST /v5/pins with media_source: { source_type: "video_id", media_id, cover_image_url }.

Wisdom (platform-specific things that bite)

  • Video pins need a cover image URL. Pinterest will 400 createPin with a vague message if it’s missing. Preflight catches the absence before any upload starts.
  • Destination URL and image URL must be publicly reachable. Both go through a HEAD probe at preflight (pinterest.destination_url.reachable, pinterest.image_url.reachable). Signed S3 URLs that expire mid-flight will fail — use stable public URLs.
  • One media item per pin. Carousel pins (multi-image) are not in v1 — preflight rejects with pinterest.media.single_only.
  • Board id is required. Either pass pinterest.boardId per-post, or set a default board on the connected account; missing both fails preflight with pinterest.board.required.
  • Trial vs Standard access. Pinterest’s Trial Access apps must point at the sandbox host (api-sandbox.pinterest.com); production calls return 403 until your app clears review.
  • Image content-type is checked from the URL response headers, not from the file extension — a .jpg URL serving image/webp will trip pinterest.image.mime_allowed.
  • The publisher uses GET for the reachability probe (not HEAD) because several Pinterest-hosted CDNs reject HEAD or skip content-length on it.

Common errors

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_secret scope.

API reference