Platforms
Create image, carousel and video Pins on your Pinterest boards with the Pinterest API v5.
Overview
The pinterest platform creates Pins with the Pinterest API v5. You can create:
- Image Pins (1 image)
- Carousel Pins (2–5 images)
- Video Pins (1 video, with a cover image or a cover frame)
Every Pin is saved to a board (options.boardId is required). The post content becomes the Pin description; options.title sets the Pin title and options.link the destination link.
Connect the account
In Integrations, choose Pinterest and approve access.
App setup (self-hosted)
- At developers.pinterest.com, open My apps → Connect app (you need a Pinterest business account).
- Add the redirect URI
https://social-publish-kappa.vercel.app/api/integrations/pinterest/callback(override withPINTEREST_REDIRECT_URI). - Set
PINTEREST_APP_IDandPINTEREST_APP_SECRET.
Scopes requested: boards:read, boards:write, pins:read, pins:write, user_accounts:read. Tokens are refreshed automatically.
New Pinterest apps get Trial access, which can't create Pins on production. Until Pinterest grants Standard access, set PINTEREST_API_BASE=https://api-sandbox.pinterest.com. Sandbox boards and Pins are separate from your real ones, visible only to you, and video Pins are not supported there.
Post types & media rules
| Rule | Limit |
|---|---|
| Media | Required: 1 image, 2–5 images (carousel), or exactly 1 video |
| Video | 1 video and no images; up to 1 GB |
| Video cover | coverImageUrl or coverKeyFrameSeconds is required for video Pins |
Description (content) | 800 characters |
| Title | 100 characters |
| Alt text | 500 characters (options.altText, or the first image's altText) |
| Destination link | Up to 2,048 characters |
| Board | boardId is required (numeric board ID) |
Images are fetched by Pinterest from their URLs, so they must be publicly reachable. Carousel items share the Pin's title, description and link.
Options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
boardId | string (per account) | Yes | Board. Every Pin must be saved to one of your boards. | |
title | string | No | Pin title. Optional, max 100 characters. The post text becomes the Pin description (max 800). | |
link | string (URL) | No | Destination link. Where the Pin leads when clicked. | |
altText | string | No | Alt text. Describes the image for screen readers (max 500). Defaults to the image's own alt text. | |
coverImageUrl | string (URL) | No | Video cover image URL. Video Pins only. Required unless a cover key frame is set. | |
coverKeyFrameSeconds | number | No | Video cover frame (seconds). Video Pins only. Use the frame at this many seconds as the cover instead of a cover image URL. | |
boardId is a per-account value. The easiest way to get it is to pick the board in the dashboard Playground and copy the generated request; the board list there comes from your Pinterest account (up to 250 boards). |
Examples
Image Pin
curl -X POST https://social-publish-api.onrender.com/v1/posts \
-H "x-access-key: $RELAYCAST_API_KEY" \
-H "content-type: application/json" \
-d '{
"content": "A 20-minute weeknight pasta with roasted tomatoes.",
"media": [{ "url": "https://cdn.example.com/pasta.jpg", "type": "image" }],
"targets": [{
"accountId": "4f5e6d7c-8b9a-4c0d-8e1f-2a3b4c5d6e7f",
"options": {
"boardId": "1084523960912345678",
"title": "Roasted tomato pasta",
"link": "https://example.com/recipes/roasted-tomato-pasta",
"altText": "Bowl of pasta with roasted cherry tomatoes and basil"
}
}],
"publishNow": true
}'const res = await fetch("https://social-publish-api.onrender.com/v1/posts", {
method: "POST",
headers: {
"x-access-key": process.env.RELAYCAST_API_KEY!,
"content-type": "application/json",
},
body: JSON.stringify({
content: "A 20-minute weeknight pasta with roasted tomatoes.",
media: [{ url: "https://cdn.example.com/pasta.jpg", type: "image" }],
targets: [
{
accountId: "4f5e6d7c-8b9a-4c0d-8e1f-2a3b4c5d6e7f",
options: {
boardId: "1084523960912345678",
title: "Roasted tomato pasta",
link: "https://example.com/recipes/roasted-tomato-pasta",
altText: "Bowl of pasta with roasted cherry tomatoes and basil",
},
},
],
publishNow: true,
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://social-publish-api.onrender.com/v1/posts",
headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
json={
"content": "A 20-minute weeknight pasta with roasted tomatoes.",
"media": [{"url": "https://cdn.example.com/pasta.jpg", "type": "image"}],
"targets": [{
"accountId": "4f5e6d7c-8b9a-4c0d-8e1f-2a3b4c5d6e7f",
"options": {
"boardId": "1084523960912345678",
"title": "Roasted tomato pasta",
"link": "https://example.com/recipes/roasted-tomato-pasta",
"altText": "Bowl of pasta with roasted cherry tomatoes and basil",
},
}],
"publishNow": True,
},
)
data = res.json()["data"]Video Pin with a cover frame
{
"content": "How to fold a fitted sheet in 30 seconds",
"media": [{ "url": "https://cdn.example.com/fold.mp4", "type": "video" }],
"targets": [{
"accountId": "4f5e6d7c-8b9a-4c0d-8e1f-2a3b4c5d6e7f",
"options": { "boardId": "1084523960912345678", "title": "Fold a fitted sheet", "coverKeyFrameSeconds": 3 }
}],
"scheduledFor": "2026-11-09T14:00:00Z"
}Analytics & comments
Analytics show impressions, saves, clicks (Pin clicks + outbound clicks), reactions and comments. Pinterest only reports analytics for the last 90 days, and none in the sandbox.
Comments and messaging are not supported for Pinterest.
Limitations & common errors
| Error | Cause |
|---|---|
Choose a board to pin to | boardId is missing or not numeric. |
Pinterest Pins need an image or a video | No media. |
A Pinterest video Pin takes exactly one video and no images | Video combined with other media. |
Pinterest carousels allow 2-5 images | More than 5 images. |
Video Pins need a cover image URL or a cover key frame time | Set coverImageUrl or coverKeyFrameSeconds. |
Video Pins cannot be created in the Pinterest API sandbox | Video with PINTEREST_API_BASE pointing at the sandbox. |
Pinterest descriptions allow 800 characters | content is too long. |
| Target fails with a trial-access message | The app only has Trial access; use the sandbox or request Standard access. |
Account becomes reconnect_required | The refresh token expired or was revoked. |
This page is also available as Markdown.