Publishing to Pinterest via API: A technical guide
Understanding OAuth, boards, pin creation, video uploads, and API endpoints for Pinterest content publishing.
Before you start: App access
Before your app can create pins on Pinterest, you need to set up API access:
- Create a Pinterest app at developers.pinterest.com and obtain your
app_idandapp_secret - Request access — New apps start in trial mode with access limited to the app owner’s account. Submit your app for review to publish on behalf of other users.
Required permissions
To create pins and access analytics, your app needs these OAuth scopes:
user_accounts:read— Access basic account informationpins:read— Read pin data and analyticspins:write— Create and manage pinsboards:read— List and read board databoards:write— Create and manage boards
Request all required scopes during the OAuth authorization flow.
Authentication
Pinterest uses standard OAuth 2.0. Exchange an authorization code for tokens by POSTing to https://api.pinterest.com/oauth/token with HTTP Basic Auth (app_id:app_secret):
POST /oauth/tokenContent-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=<AUTH_CODE>&redirect_uri=<REDIRECT_URI>Returns:
{ "access_token": "pina_...", "token_type": "bearer", "expires_in": 2592000, "refresh_token": "pinr_...", "refresh_token_expires_in": 5184000, "scope": "user_accounts:read pins:read pins:write boards:read boards:write"}Refresh tokens expire after 60 days but can be refreshed indefinitely using grant_type=refresh_token.
Listing boards
Pins must be published to a board. List the user’s boards with a GET to https://api.pinterest.com/v5/boards:
GET /v5/boards?page_size=25Authorization: Bearer <ACCESS_TOKEN>Returns paginated results with id, name, privacy, and pin_count for each board. Use the bookmark parameter for pagination.
Creating an image pin
POST to https://api.pinterest.com/v5/pins:
{ "board_id": "1234567890", "title": "Pin title", "description": "Pin description", "link": "https://example.com/page", "media_source": { "source_type": "image_url", "url": "https://example.com/image.jpg" }}The media_source object supports several source types:
image_url— Provide a publicly accessible image URLimage_base64— Provide base64-encoded image data withcontent_type(image/jpegorimage/png)pin_url— Repin from an existing pin URL
Title is limited to 100 characters, description to 800 characters.
Creating a carousel pin
Carousels contain 2–5 images in a single pin. Use the multiple_image_urls source type:
{ "board_id": "1234567890", "title": "Carousel pin", "description": "Multiple images in one pin", "media_source": { "source_type": "multiple_image_urls", "items": [ { "url": "https://example.com/image1.jpg" }, { "url": "https://example.com/image2.jpg" }, { "url": "https://example.com/image3.jpg" } ] }}Unlike Instagram carousels, Pinterest carousels are created in a single request — no separate container steps.
Publishing videos
Video pins require a multi-step upload flow:
Step 1: Register the media upload
POST to https://api.pinterest.com/v5/media:
{ "media_type": "video"}Returns an upload_url and upload_parameters:
{ "media_id": "12345", "media_type": "video", "upload_url": "https://pinterest-media-upload.s3-accelerate.amazonaws.com/", "upload_parameters": { "Content-Type": "multipart/form-data", "key": "uploads/...", "policy": "eyJ...", "x-amz-algorithm": "AWS4-HMAC-SHA256", "x-amz-credential": "...", "x-amz-date": "...", "x-amz-security-token": "...", "x-amz-signature": "..." }}Step 2: Upload the video file
POST the video as multipart/form-data to the upload_url, including all upload_parameters as form fields alongside the file. This uploads directly to S3.
Step 3: Poll for processing status
GET https://api.pinterest.com/v5/media/{media_id} until status is succeeded:
{ "media_id": "12345", "media_type": "video", "status": "succeeded"}Possible status values:
registered— Upload registered, file not yet uploadedprocessing— File uploaded, being processedsucceeded— Ready to use in pin creationfailed— Processing failed
Step 4: Create the video pin
POST to https://api.pinterest.com/v5/pins with the video_id source type:
{ "board_id": "1234567890", "title": "Video pin", "description": "Video description", "media_source": { "source_type": "video_id", "media_id": "12345" }}Pin analytics
GET https://api.pinterest.com/v5/pins/{pin_id}/analytics with required query parameters:
GET /v5/pins/{pin_id}/analytics?start_date=2026-01-01&end_date=2026-01-31&metric_types=IMPRESSION,PIN_CLICK,SAVEAvailable metrics include IMPRESSION, OUTBOUND_CLICK, PIN_CLICK, SAVE, SAVE_RATE, TOTAL_COMMENTS, and TOTAL_REACTIONS. Video pins also support VIDEO_MRC_VIEW and watch time metrics.
Analytics data is available for up to 90 days back from today.
Rate limits
Pinterest enforces rate limits per app and per user across three categories:
org_read— Board listing, media status checksorg_write— Pin creation, media registrationorg_analytics— Pin analytics
Exceeding limits returns HTTP 429. Specific numeric limits are not published in the API documentation.
The same pin, through Postproxy
Here’s how it’s done with Postproxy. One simple request with only what matters:
curl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "3 tips that changed how we approach customer onboarding" }, "profiles": ["pinterest"], "media": ["https://example.com/image.jpg"] }'One request. Postproxy handles the board selection, media upload, processing status polling, and pin creation.
What Postproxy handles
Postproxy maintains approved access and handles the complexity:
- OAuth token exchange and continuous refresh
- Board listing and selection
- Direct image pins and multi-step video uploads
- Carousel pin creation from multiple images
- Upload status polling for video processing
- Rate limit monitoring and request pacing
Your system sends content. Postproxy handles the Pinterest-specific implementation.
Connect your Pinterest account and start publishing through the Postproxy API.