Reelspan creates Pins with the Pinterest API v5. You send the media once with a board; Reelspan uploads it, waits for Pinterest to process a video, and creates the Pin with its title, description and link.
What you can post
| Post | How | Notes |
|---|---|---|
| Video Pin | POST /v1/posts/video |
Needs a cover: an image or a frame of the video |
| Image Pin | POST /v1/posts/photos with one photo |
|
| Carousel Pin | POST /v1/posts/photos with 2 to 5 photos |
Pinterest has no text-only Pins. Reelspan handles for you:
- The video upload: Reelspan registers the video with Pinterest, uploads it, and waits until Pinterest has processed it (up to 10 minutes) before making the Pin.
- The cover: a video Pin needs one. Reelspan uses your cover image if you send one, otherwise a frame of the video (1 second in, unless you pick another).
- Boards and sections: list the account's boards and their sections, or create them, through the API.
Connect the account
Pinterest connects with a Pinterest sign-in: in the dashboard go to Accounts → Pinterest, or send a white-label connect link. Any Pinterest account works.
Pick a board
Every Pin goes to a board, so a Pinterest post needs pinterest_board_id. List the boards to find the id:
curl "https://api.reelspan.com/v1/pinterest/boards?profile=my-brand" \
-H "Authorization: Bearer $REELSPAN_API_KEY"const { boards } = await reelspan.request('GET', '/v1/pinterest/boards', { query: { profile: 'my-brand' } });boards = reelspan.request("GET", "/v1/pinterest/boards", query={"profile": "my-brand"})["boards"]{
"success": true,
"boards": [
{ "id": "1029876543210987654", "name": "Spring recipes" },
{ "id": "1029876543210987655", "name": "Kitchen ideas" }
],
"pinterest_account_used": "mybrand"
}The list is read live from Pinterest, so boards made in the Pinterest app show up. If Pinterest doesn't answer, you get the list saved when the account was connected.
To make a new board, send its name (up to 50 characters), and optionally a description (up to 500 characters) and privacy: PUBLIC (the default) or PROTECTED. A protected board is hidden from others but can still be posted to; secret boards can't be posted to, so SECRET isn't one of the choices.
curl -X POST https://api.reelspan.com/v1/pinterest/boards \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile": "my-brand", "name": "Weeknight dinners"}'const { board } = await reelspan.pinterest.createBoard('my-brand', 'Weeknight dinners');board = reelspan.pinterest.create_board("my-brand", "Weeknight dinners")["board"]With a description and privacy (the SDKs' createBoard / create_board take a name only, so use request):
await reelspan.request('POST', '/v1/pinterest/boards', {
json: { profile: 'my-brand', name: 'Drafts', description: 'Pins waiting for review', privacy: 'PROTECTED' },
});reelspan.request("POST", "/v1/pinterest/boards", json_body={"profile": "my-brand", "name": "Drafts", "description": "Pins waiting for review", "privacy": "PROTECTED"})Board sections
A board can be split into sections; send a section's id as pinterest_board_section_id to put the Pin there. List a board's sections, read live from Pinterest:
curl "https://api.reelspan.com/v1/pinterest/boards/1029876543210987654/sections?profile=my-brand" \
-H "Authorization: Bearer $REELSPAN_API_KEY"const { sections } = await reelspan.request('GET', '/v1/pinterest/boards/1029876543210987654/sections', { query: { profile: 'my-brand' } });sections = reelspan.request("GET", "/v1/pinterest/boards/1029876543210987654/sections", query={"profile": "my-brand"})["sections"]{ "success": true, "board_id": "1029876543210987654", "sections": [{ "id": "5012345678901234567", "name": "Pasta" }] }Create one with a POST to the same path and a name (up to 180 characters); the answer is 201 with the new section. Creating a section needs the publish scope.
curl -X POST https://api.reelspan.com/v1/pinterest/boards/1029876543210987654/sections \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile": "my-brand", "name": "Soups"}'Example
A video Pin with a link and a cover picked 3 seconds in:
curl -X POST https://api.reelspan.com/v1/posts/video \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=pinterest" \
-F "pinterest_board_id=1029876543210987654" \
-F "pinterest_title=15-minute lemon pasta" \
-F "pinterest_description=A weeknight pasta with lemon, garlic and parmesan. Full recipe on the blog." \
-F "pinterest_link=https://example.com/lemon-pasta" \
-F "pinterest_cover_image_key_frame_time=3" \
-F "[email protected]"import { Reelspan } from 'reelspan';
import { readFile } from 'node:fs/promises';
const reelspan = new Reelspan();
const post = await reelspan.posts.video({
user: 'my-brand',
platforms: ['pinterest'],
video: { data: await readFile('launch.mp4'), name: 'launch.mp4', type: 'video/mp4' },
extra: {
pinterest_board_id: '1029876543210987654',
pinterest_title: '15-minute lemon pasta',
pinterest_description: 'A weeknight pasta with lemon, garlic and parmesan. Full recipe on the blog.',
pinterest_link: 'https://example.com/lemon-pasta',
pinterest_cover_image_key_frame_time: 3,
},
});from reelspan import Reelspan
reelspan = Reelspan()
post = reelspan.posts.video(
"my-brand", ["pinterest"], "launch.mp4",
extra={
"pinterest_board_id": "1029876543210987654",
"pinterest_title": "15-minute lemon pasta",
"pinterest_description": "A weeknight pasta with lemon, garlic and parmesan. Full recipe on the blog.",
"pinterest_link": "https://example.com/lemon-pasta",
"pinterest_cover_image_key_frame_time": 3,
},
)Fields
| Field | Type | Values | What it does |
|---|---|---|---|
pinterest_board_id |
string | a board id | Required. The board the Pin goes to. |
pinterest_board_section_id |
string | a section id | A section of that board. |
pinterest_title |
string | up to 100 characters | The Pin's title. Falls back to title. |
pinterest_description |
string | up to 800 characters | The Pin's description (the API takes 800; the Pinterest app shows about 500 before "more"). Falls back to description (not to title). |
pinterest_link |
string | URL | Where the Pin leads when tapped. |
pinterest_cover_image_url |
string | public image URL | Video Pins: the cover image. You can also send a cover file, cover_url or cover_media_id. |
pinterest_cover_image_key_frame_time |
number | seconds, default 1 |
Video Pins without a cover image: the frame used as the cover. |
pinterest_carousel_index |
number | 0-based, default 0 |
Carousel Pins: passed to Pinterest as the carousel's index. |
pinterest_alt_text |
string | up to 500 characters | Alt text for the Pin (the first image's, on a carousel). Falls back to alt_text. |
Limits
- Title: 100 characters. Description: 800 characters (longer is cut).
- Carousel: 2 to 5 photos, all in the same shape; with more, the first 5 are used and the result says so.
- Photos: JPEG or PNG, up to 20 MB each.
- Video size: your plan's upload limit (see Plans and limits).
- Shapes: 2:3 and 9:16 work best.
Save a Pin to a board
POST /v1/posts/save saves (repins) an existing Pin, yours or anyone's, to one of the account's boards, optionally into a section:
curl -X POST https://api.reelspan.com/v1/posts/save \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"user": "my-brand", "post_id": "987654321098765432", "pinterest_board_id": "1029876543210987654", "pinterest_board_section_id": "5012345678901234567"}'await reelspan.request('POST', '/v1/posts/save', {
json: { user: 'my-brand', post_id: '987654321098765432', pinterest_board_id: '1029876543210987654' },
});reelspan.request("POST", "/v1/posts/save", json_body={"user": "my-brand", "post_id": "987654321098765432", "pinterest_board_id": "1029876543210987654"}){
"success": true,
"post_id": "1122334455667788990",
"url": "https://www.pinterest.com/pin/1122334455667788990/",
"board_id": "1029876543210987654",
"board_section_id": "5012345678901234567",
"parent_pin_id": "987654321098765432"
}post_id in the answer is the new saved Pin; parent_pin_id is the one you saved.
After posting
- Delete a Pin with Unpublish.
- Edit a Pin with Edit a post:
title(up to 100 characters),descriptionortext(up to 800), and infieldsthepinterest_link,pinterest_alt_text(up to 500),pinterest_board_idandpinterest_board_section_id(to move it). The image or video can't change.
Good to know
- Trial access. While Reelspan's Pinterest app is on Pinterest's Trial access, Pins are made in Pinterest's sandbox and only you can see them; the result says so in
warnings. - Pinterest's filters. Pinterest blocks Pins whose words touch topics it treats as spam or unsafe (hacking, passwords, crypto, giveaways) or that link to a blocked site. That fails with
pinterest_blocked_content; retrying the same text won't help. - Result extras:
board_id, andmedia_idfor video Pins. - First comment: Pinterest's API has no comments, so
first_commentisn't posted; the result saysfirst_comment: "unsupported". - Analytics: followers, following, Pin count and monthly views for the account. There are no per-Pin numbers.
Errors
error_code |
What happened | What to do |
|---|---|---|
pinterest_blocked_content |
Pinterest's spam and safety filter blocked the Pin | Change the title, description or link, then retry. |
pinterest_upload_failed |
The video upload to Pinterest failed | Reelspan retries server errors; otherwise post again. |
pinterest_processing_failed |
Pinterest couldn't process the video | Check the file and post again. |
pinterest_processing_timeout |
Pinterest took more than 10 minutes | Reelspan retries it. |
pinterest_error |
Pinterest refused the request, for example an unknown board | Read error for Pinterest's message. |
reauth_required |
The sign-in expired, or the connection predates a permission Reelspan now needs | Reconnect Pinterest. |
media_required |
The post had no photo or video | Send media: Pinterest has no text Pins. |
A request that names Pinterest without a board is refused with 400 before anything is uploaded.