# Pinterest API: Posting Reference

Pinterest is supported via the Pinterest Business API. OmniSocials publishes Pins to a specific board, which must be provided on every post.

**Channel ID:** `pinterest`

## Supported content types

| Type | Supported | Notes |
|------|-----------|-------|
| Feed post (Pin) | ✅ | Image or video pin to a specific board |
| Carousel pin | ✅ | 2–5 images in one swipeable pin (see [Carousel pins](#carousel-pins)) |
| Story | - | Not supported |
| Reel | - | Not supported |

## Minimal example

```bash
curl -X POST https://api.omnisocials.com/v1/posts/create \
  -H "Authorization: Bearer $OMNISOCIALS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": { "default": "Spring color palette inspiration" },
    "accounts": ["your-pinterest-account-id"],
    "media_urls": ["https://example.com/palette.jpg"],
    "pinterest": {
      "board_id": "1234567890",
      "title": "Spring palette"
    }
  }'
```

## Platform-specific options

| Field | Type | Description |
|-------|------|-------------|
| `pinterest.board_id` | string | **Required.** The ID of the board to pin to. Get board IDs from `GET /accounts/:id`. Pinterest accounts include a `boards` array with `{ id, name }` entries. |
| `pinterest.title` | string | Pin title. Highly recommended for discoverability. Max 100 characters. |
| `pinterest.link` | string | Destination URL the pin links to when clicked. |
| `pinterest.video_cover` | string | Cover image URL for video pins (JPEG/PNG). If omitted, Pinterest uses a video keyframe at 1 second. |
| `pinterest.alt_text` | string | Accessibility alt text for the pin image (max 500 characters). Improves discoverability and supports screen readers. |

Posts without `board_id` are rejected at validation.

**Per-media alt fallback.** If `pinterest.alt_text` is not set, a per-media `alt` on the entry itself is used instead — e.g. `"media_urls": [{ "url": "https://example.com/pin.jpg", "alt": "Flat-lay of spring outfit ideas" }]`. Handy when you cross-post the same media (with one shared alt description) to Pinterest alongside Mastodon, Bluesky, and X. `pinterest.alt_text` always wins when both are present.

## Media requirements

| Media | Requirement |
|-------|-------------|
| Image | JPEG, PNG, or WebP. Max 32 MB. Minimum 600 × 600. |
| Video | MP4 or MOV, 4 seconds to 15 minutes, max 2 GB |

Pinterest recommends a 2:3 aspect ratio (e.g. 1000 × 1500) for best visibility in the feed.

## Video pins

Video pins use a cover image. Pass either:

- An image URL in `pinterest.video_cover`, or
- Omit `video_cover` and Pinterest will use a keyframe at 1 second of the video as the cover (automatic fallback)

## Carousel pins

Attach **2–5 images** to a single Pinterest post and OmniSocials publishes them as one swipeable Pinterest carousel pin (Pinterest's v5 `multiple_image_urls` source type), not separate pins. The pin-level `title`, `description`, `link`, and `alt_text` apply to the whole pin — Pinterest's standard carousel format doesn't expose per-slide metadata.

```bash
curl -X POST https://api.omnisocials.com/v1/posts/create \
  -H "Authorization: Bearer $OMNISOCIALS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": { "pinterest": "Spring lookbook — swipe through the set" },
    "accounts": ["your-pinterest-account-id"],
    "media_urls": {
      "pinterest": [
        "https://example.com/slide-1.jpg",
        "https://example.com/slide-2.jpg",
        "https://example.com/slide-3.jpg",
        "https://example.com/slide-4.jpg"
      ]
    },
    "pinterest": {
      "board_id": "1234567890",
      "title": "Spring lookbook",
      "link": "https://example.com/spring",
      "alt_text": "Four-slide carousel of spring looks"
    }
  }'
```

### Carousel constraints

- **2 to 5 images per pin.** 1 image publishes as a normal image pin; 6+ images return `400 validation_error`.
- **Same aspect ratio across all slides.** Pinterest's carousel endpoints reject mixed-ratio sets. OmniSocials probes slide dimensions when you schedule or publish-now and returns a synchronous `400 validation_error` listing the slides that don't match slide 1 — you'll never get a deferred publish failure at cron time. Recommended ratios: **1:1** (square) or **2:3** (vertical).
- **Images only.** Pinterest's `multiple_image_urls` discriminator doesn't accept videos. A post with one video plus images publishes as a single-video pin and the images are dropped.
- **Pinterest Business account in an ads-enabled region.** Personal accounts can't create carousel pins and Pinterest rejects the API call regardless of payload.

Example aspect-ratio error response:

```json
{
  "error": {
    "code": "validation_error",
    "message": "Pinterest carousel pins need every image at the same aspect ratio. Slides 2, 3 don't match slide 1 — re-crop or remove them before publishing.",
    "mismatched_slides": [2, 3]
  }
}
```

The `mismatched_slides` array is 1-indexed and lists every slide whose ratio diverges from slide 1's by more than 1%. Re-crop the listed slides to match slide 1 and re-submit.

The same check runs on `POST /posts/create` (with `schedule_at` or `publish_now`), on `POST /posts/{id}/publish`, and on `PATCH /posts/{id}` when the update flips the post to `scheduled` status. **Drafts are exempt**, so you can iterate on media before committing to publish.

## Limitations

- Pins must target a specific board. Posting to the user's profile is not supported.
- Rich pins (product, article, recipe) are not currently exposed through the API
- Pinterest requires HTTPS URLs for `link`. HTTP links are rejected.
- Carousel pins require a Pinterest Business account in an ads-enabled region (Pinterest restriction, not an OmniSocials one).
