How to Create Pins with the Pinterest API v5: Scopes, Media Uploads, and the Trial-Mode Trap
Short answer: creating a Pin through the Pinterest API is one POST request. Getting to the point where that request works for anyone other than you is the part the docs gloss over.
The call itself, POST /v5/pins, is small and sane compared to what Instagram or LinkedIn make you deal with. The trap is earlier in the process: your app starts in Trial mode, and Trial mode will only let you publish to the Pinterest account that owns the app. If you are building this for yourself, that is fine and you can stop reading the auth section. If you are building it for other people, you need to know that before you architect anything around it.
This is the practical walkthrough: access modes, scopes, the image pin call, the two-step video upload, the constraints that will reject your request, rate limits, and where scheduling actually lives.
API access and Trial vs Production mode
Every new Pinterest app starts in Trial mode. In Trial mode you can call the full API, including /v5/pins, but only against the Pinterest account you used to create the app. That is enough to build and test your integration end to end. It is not enough to ship a product that posts on behalf of other users.
To move past that, you submit for standard or advanced access through Pinterest's app review, describing what your app does and how it uses each scope. Until that review clears, treat any "connect your Pinterest account" flow in your product as something you can build and demo, but not launch publicly.
If you are only automating your own brand's Pinterest account, Trial mode is genuinely enough. Skip the review and start posting.
Scopes and tokens
Pinterest uses OAuth 2.0. For creating Pins you need two scopes:
pins:write
boards:read
pins:write lets you create and update Pins. boards:read lets you look up the board_id you need for every Pin you create, since Pinterest has no concept of posting to a feed the way X or Threads do. Everything on Pinterest lives on a board.
Token lifetimes are worth writing down somewhere you will actually see them again: access tokens last 30 days, and the refresh token is valid for a year. That means you need a refresh job running roughly monthly, not once a year, or your integration goes quiet without an obvious error until someone notices posts stopped going out.
POST https://api.pinterest.com/v5/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token={your_refresh_token}
Creating an image pin (media_source options)
Once you have a token and a board_id, creating an image Pin is one call:
POST https://api.pinterest.com/v5/pins
Authorization: Bearer {access_token}
Content-Type: application/json
{
"board_id": "934567891234567890",
"title": "Weeknight sheet-pan salmon",
"description": "One pan, twenty minutes, no dishes.",
"link": "https://example.com/recipe",
"media_source": {
"source_type": "image_url",
"url": "https://example.com/images/salmon.jpg"
}
}
media_source.source_type can also be image_base64 if you want to send raw bytes instead of hosting the image somewhere fetchable first. Use the URL form when you can. It is simpler to debug and does not bloat your request payload.
Notice there is no separate "publish" step here, unlike Instagram's container-then-publish dance. One request, one Pin.
See how TimeToPost can help you implement these strategies.
Video pins: the two-step /v5/media upload
Video is where Pinterest stops being a one-call API. You cannot hand a video URL directly to /v5/pins. You have to register the media first, upload the file to the URL Pinterest gives you back, then reference the resulting media_id in the Pin creation call.
Step one, register the upload:
POST https://api.pinterest.com/v5/media
Authorization: Bearer {access_token}
Content-Type: application/json
{
"media_type": "video"
}
That returns an upload_url, upload_parameters, and a media_id. You then POST the actual video file as multipart form data to the upload_url using the parameters Pinterest gave you, exactly as returned, not reformatted.
Step two, once the upload completes and status flips to registered, create the Pin referencing it:
POST https://api.pinterest.com/v5/pins
Authorization: Bearer {access_token}
Content-Type: application/json
{
"board_id": "934567891234567890",
"title": "Behind the scenes: how we shoot product photos",
"media_source": {
"source_type": "video_id",
"cover_image_url": "https://example.com/images/cover.jpg",
"media_id": "the-media-id-from-step-one"
}
}
You can poll the media status endpoint if you want to confirm processing finished before you attempt the Pin call. Skipping that check and firing the Pin request immediately after upload is a common source of intermittent failures, since processing is not instant.
Image and video constraints
Pinterest is forgiving on format but has real ceilings worth knowing before you build your upload pipeline:
- Images: up to 32MB. Pinterest recommends a 2:3 aspect ratio, with 1000x1500 as the sweet spot. Square and other ratios upload fine but get cropped in some surfaces, so 2:3 is the safe default if you only have one asset to prepare.
- Video: MP4 or MOV, up to roughly 2GB, with a duration window reportedly between 4 seconds and 15 minutes. Treat the upper duration bound as a guideline rather than a hard guarantee and test with your actual files before assuming the ceiling.
If your source content comes from Instagram or TikTok, note that neither platform's native 9:16 export matches Pinterest's preferred 2:3. You will get better save rates cropping specifically for Pinterest rather than reusing a vertical video file as-is.
Rate limits and 429 handling
Pinterest's v5 API returns rate limit information in response headers, which is more transparent than most platforms bother with. Reported limits sit around 1,000 read requests and 100 write requests per minute per app, though Pinterest has adjusted these figures before, so check the x-ratelimit-limit and x-ratelimit-remaining headers on your own responses rather than hardcoding a number in your code.
When you do get rate limited, you will see a 429 with a Retry-After header. The correct response is to back off for that duration and retry, not to immediately resend. If you are batching Pin creation across many boards or accounts, queue the requests and pace them rather than firing them all at once, since a burst of writes is exactly what trips the write-rate ceiling.
Scheduling pins
Pinterest's own scheduling tool, built into the Pinterest business dashboard, lets you queue Pins ahead of time, but that is a product feature, not an API endpoint. The /v5/pins call itself is synchronous. It publishes immediately. There is no scheduled_at field to pass.
If you want to schedule Pins programmatically, meaning queue content now and have it fire at a specific future time without a human clicking publish, you need something sitting on top of the API doing the timing for you: a cron job, a queue worker, or a scheduler product. That is genuinely the whole reason a tool like TimeToPost exists on top of raw platform APIs. TimeToPost publishes natively to X today, holding your connection and calling the platform's API at the right moment from your calendar, and a Pinterest connector is built alongside Instagram, TikTok, Facebook, and Threads but not yet open to customers, so it is coming soon rather than something you can plug in right now. If your build already handles Instagram's much heavier App Review and Business Verification gauntlet, our Instagram API guide is worth comparing against, since Pinterest's Trial-mode restriction is a lighter version of the same idea.
If Pinterest is one piece of a broader queue, our Pinterest native scheduler limits post covers what the platform's own scheduling tool caps you at, and our best time to post on Pinterest data plus the best-time-to-post calculator are worth checking before you lock in a send schedule, since Pinterest's engagement rhythm runs slower and longer-tail than a feed platform like Instagram or X.
FAQ
Do I need Business Verification like Instagram requires? No. Pinterest's review process is app-level, not business-verification-level. You submit your use case for standard or advanced access, and until that clears, your app is limited to Trial mode, meaning it can only post to the account that created it.
Can I post a carousel or multiple images in one Pin?
The /v5/pins endpoint creates a single Pin per call. Pinterest supports multi-image "Idea Pins" through a related but separate flow with its own constraints, which is worth treating as a different feature rather than an extension of the standard image Pin call.
What happens if I try to post to a board that is not mine? The call fails. Your token only has write access to boards owned by, or explicitly shared with, the authenticated account. You cannot post to an arbitrary public board.
Is there a sandbox or test board I should use while developing? Pinterest does not provide a dedicated sandbox environment. Create a private board on your own Trial-mode account and treat that as your test surface before pointing requests at a real board.
Why did my video Pin fail even though the upload succeeded?
Usually because the Pin creation call fired before Pinterest finished processing the uploaded video. Poll the media status before referencing the media_id in your Pin request, especially for longer files.
If you would rather skip the token refresh cron jobs and the manual pacing math, that is the gap TimeToPost is built to fill, with Pinterest publishing coming soon.