Platforms
Publish image and video pins to Pinterest boards, create boards, edit pin descriptions and read impressions, saves and clicks.
Pinterest works like a visual search engine. A pin keeps getting found for months, so the title, description, board and destination link matter more than the time you post. With Pozy you publish image and video pins with the same POST /v1/posts call you use everywhere else, using the platform id pinterest.
#What you can do
| Feature | Supported | Where |
|---|---|---|
| Image pins | Yes, 1 image per pin | Post types |
| Video pins | Yes, 1 video per pin, with a custom cover | Post types |
| Choose or create a board | Yes | Boards |
| Scheduling | Yes | Scheduling |
| Edit a published pin | Description only | Edit a pin |
| Analytics | Impressions, saves, clicks | Analytics |
| Inbox (DMs, comments) | No | Pinterest has no inbox API |
| Ads | Yes, separate connection | Pinterest Ads |
There are no text-only pins, carousels or multi-image pins through the API. Every pin carries exactly one image or one video.
#Connect
Pinterest connects with OAuth. Request a connect URL for a profile and send the user to authUrl:
curl "https://api.pozy.ai/v1/connect/pinterest?profileId=66a1f0c2a4b9d3e8f1a2b3c4&redirect_url=https://app.example.com/connected" \
-H "Authorization: Bearer $POZY_API_KEY"const res = await fetch("https://api.pozy.ai/v1/connect/pinterest?profileId=66a1f0c2a4b9d3e8f1a2b3c4&redirect_url=https:%2F%2Fapp.example.com%2Fconnected", {
headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
// Redirect the user's browser to data.authUrlimport os, requests
resp = requests.get(
"https://api.pozy.ai/v1/connect/pinterest",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
params={"profileId": "66a1f0c2a4b9d3e8f1a2b3c4", "redirect_url": "https://app.example.com/connected"},
)
print(resp.json()["authUrl"])After the Pinterest consent screen the user picks a default board. Pozy hosts that screen for you. To build your own picker, pass headless=true and use List Pinterest boards and Select Pinterest board. See Hosted connect and Headless connect.
You can change the default board later with Set default Pinterest board. No second OAuth is needed.
#Post types
content becomes the pin description. The board, title and destination link go in platformSpecificData on the Pinterest entry.
#Image pin
curl -X POST https://api.pozy.ai/v1/posts \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Small kitchen layouts that still fit an island",
"mediaItems": [{ "type": "image", "url": "https://pozy.ai/media/kitchen-2x3.jpg" }],
"platforms": [{
"platform": "pinterest",
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"platformSpecificData": {
"boardId": "1022106146582011234",
"title": "Small kitchen layouts with an island",
"link": "https://blog.example.com/small-kitchens"
}
}],
"publishNow": true
}'const res = await fetch("https://api.pozy.ai/v1/posts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
content: "Small kitchen layouts that still fit an island",
mediaItems: [{ type: "image", url: "https://pozy.ai/media/kitchen-2x3.jpg" }],
platforms: [{
platform: "pinterest",
accountId: "66b2e19d8c3f5a7e9d0b1c2d",
platformSpecificData: {
boardId: "1022106146582011234",
title: "Small kitchen layouts with an island",
link: "https://blog.example.com/small-kitchens",
},
}],
publishNow: true,
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.post.platforms[0].platformPostUrl);resp = requests.post(
"https://api.pozy.ai/v1/posts",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
json={
"content": "Small kitchen layouts that still fit an island",
"mediaItems": [{"type": "image", "url": "https://pozy.ai/media/kitchen-2x3.jpg"}],
"platforms": [{
"platform": "pinterest",
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"platformSpecificData": {
"boardId": "1022106146582011234",
"title": "Small kitchen layouts with an island",
"link": "https://blog.example.com/small-kitchens",
},
}],
"publishNow": True,
},
)
print(resp.json()["post"]["platforms"][0]["platformPostUrl"])boardId is optional in the schema, but a pin without it lands on whichever board Pinterest lists first. If the account has no boards at all, the pin fails and asks for platformSpecificData.boardId.
#Video pin
Swap the media for one video. Set a cover with coverImageUrl, or let Pozy grab a frame at coverImageKeyFrameTime seconds:
{
"platform": "pinterest",
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"platformSpecificData": {
"boardId": "1022106146582011234",
"title": "Five-minute breakfast wrap",
"link": "https://recipes.example.com/breakfast-wrap",
"coverImageUrl": "https://pozy.ai/media/wrap-cover.jpg"
}
}#Platform fields
| Field | Type | Notes |
|---|---|---|
boardId |
string | Board to pin to. Send it on every post. |
boardSectionId |
string | Section inside the board. Must belong to boardId, so send both. |
title |
string, up to 100 characters | Defaults to the first line of content. Searchable on Pinterest. |
link |
URL | Where a click on the pin goes. HTTPS, no URL shorteners. This is the field that drives traffic. |
coverImageUrl |
URL | Cover image for a video pin. |
coverImageKeyFrameTime |
integer (seconds) | Frame to use as the cover. Ignored when coverImageUrl is set. |
isAiGenerated |
boolean, default false |
Adds Pinterest's "AI modified" disclosure. Pinterest may still label a pin from its own detection. |
The full list of shared post fields is on Platform settings.
#Boards
List the boards on a connected account, or create one. A new board's id works as boardId straight away.
# List boards
curl https://api.pozy.ai/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/pinterest-boards \
-H "Authorization: Bearer $POZY_API_KEY"
# Create a board
curl -X POST https://api.pozy.ai/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/pinterest-boards \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Summer recipes", "description": "Quick dinners for hot days", "privacy": "PUBLIC" }'const listRes = await fetch("https://api.pozy.ai/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/pinterest-boards", {
headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
const list = await listRes.json();
if (!listRes.ok) throw new Error(list.error);
const createdRes = await fetch("https://api.pozy.ai/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/pinterest-boards", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "Summer recipes", description: "Quick dinners for hot days", privacy: "PUBLIC" }),
});
const created = await createdRes.json();
if (!createdRes.ok) throw new Error(created.error);
console.log(created.board.id);base = "https://api.pozy.ai/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/pinterest-boards"
headers = {"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"}
boards = requests.get(base, headers=headers).json()["boards"]
created = requests.post(base, headers=headers, json={
"name": "Summer recipes",
"description": "Quick dinners for hot days",
"privacy": "PUBLIC",
}).json()
print(created["board"]["id"])privacy is PUBLIC (the default), PROTECTED or SECRET. Pinterest rejects a second board with the same name on one account.
#Edit a published pin
Edit published post replaces the description of a live pin, up to 800 characters. The title, media, link and board cannot change after publishing, and the pin keeps its id.
curl -X POST https://api.pozy.ai/v1/posts/65f1c0a9e2b5af0012ab34cd/edit \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "platform": "pinterest", "content": "Updated description with the new recipe notes" }'Pinterest still keeps its pin-update API behind an allowlist. Until Pinterest opens it, edit requests come back with Pinterest's "beta feature not yet enabled" error. Nothing on your side changes that. If the post went to several Pinterest accounts, pass accountId to choose which copy to edit.
#Media requirements
| Images | Requirement |
|---|---|
| Per pin | 1 |
| Formats | JPEG, PNG, WebP, GIF (animated GIFs count as images) |
| Max size | 32 MB (under 10 MB loads faster) |
| Minimum | 100 x 100 px |
| Best ratio | 2:3, for example 1000 x 1500 px. 1:1 and long pins up to 1:2.1 also work |
| Videos | Requirement |
|---|---|
| Per pin | 1 |
| Formats | MP4, MOV |
| Max size | 2 GB |
| Duration | 4 seconds to 15 minutes |
| Aspect ratio | 2:3, 1:1 or 9:16 |
| Recommended | 1080p, 25 fps or more, around 10 Mbps, AAC audio at 128 kbps |
Media URLs must be public, return the file bytes with the right Content-Type, and not redirect to a web page. Sharing links from Google Drive, Dropbox, OneDrive or iCloud return a page, not a file, and fail. Upload through Media to get a URL that always works.
#Limits
| Limit | Value |
|---|---|
| Title | 100 characters |
| Description | 800 characters, on create and on edit |
| Media | 1 image or 1 video per pin |
| Burst posting | Space pins out. Bursts of 10 or more at once trip Pinterest's rate limit |
Not available through Pinterest's API: Idea Pins, Rich Pins (they need meta tags on your site), website claiming, shopping catalogs, carousels and multi-image pins.
#Analytics
Get post analytics with platform=pinterest returns, per pin:
| Metric | Field |
|---|---|
| Impressions | impressions |
| Saves | saves |
| Clicks | clicks |
curl "https://api.pozy.ai/v1/analytics?platform=pinterest&fromDate=2026-09-01&toDate=2026-09-30" \
-H "Authorization: Bearer $POZY_API_KEY"See Post analytics for paging and date ranges.
#Inbox
Pinterest has no DM, comment or review API, so Pinterest accounts do not appear in the Inbox.
#Errors you may see
| Error | Cause | Fix |
|---|---|---|
| "Pinterest requires a boardId" | No boardId and no board Pozy could fall back to |
Send platformSpecificData.boardId. List boards first. |
| "Unable to reach the URL" | Pinterest could not download the media | Open the URL in a private window. It must load the raw file with no login or redirect. |
| "Invalid URL or request data" | Pinterest could not process the media or request | Check the URL is HTTPS and returns media bytes. |
| "Pinterest rate limit reached" | Too many pins in a short window | Spread pins out or use a queue. |
A post you publish right away can be accepted by Pozy and still fail on Pinterest. Check post.status and platforms[].errorMessage in the response, not only the HTTP status. Errors covers the error format.
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/accounts/{accountId}/pinterest-boards |
List Pinterest boards |
POST /v1/accounts/{accountId}/pinterest-boards |
Create Pinterest board |
PUT /v1/accounts/{accountId}/pinterest-boards |
Set default Pinterest board |
GET /v1/connect/pinterest/select-board |
List Pinterest boards |
POST /v1/connect/pinterest/select-board |
Select Pinterest board |
POST /v1/posts |
Create post |
POST /v1/posts/{postId}/edit |
Edit published post |
GET /v1/analytics |
Get post analytics |
#Webhook events
| Event | When it fires |
|---|---|
post.published |
Post published. |
post.failed |
Post failed. |
post.platform.published |
Post platform published. |
post.platform.failed |
Post platform failed. |
post.platform.deleted |
Post platform deleted. |