Schedule post
const url = 'https://api-v1.tailwind.ai/v1/accounts/example/posts/example/schedule';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"sendAt":"2026-04-15T12:00:00Z","useNextOpenSlot":false,"boardId":"example","boardSectionId":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api-v1.tailwind.ai/v1/accounts/example/posts/example/schedule \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "sendAt": "2026-04-15T12:00:00Z", "useNextOpenSlot": false, "boardId": "example", "boardSectionId": "example" }'Schedule a draft post or reschedule a queued post, passing exactly one of sendAt or useNextOpenSlot. A draft exists only in Tailwind, not on Pinterest, until this call: scheduling is what puts it into Tailwind’s publishing flow. useNextOpenSlot places the Pin in the account’s next open smart schedule slot, honoring the account’s Pin Spacing rules for the Pin’s destination url — the same calculation the Pin Scheduler runs. An explicit sendAt sets only the Pin’s initial time and is not an exemption from Pin Spacing: a later Pin Spacing respace or schedule shuffle can still move the Pin, and the API has no way to lock it in place. The post must have title, description, and url set before it can be scheduled. Cannot reschedule posts that have already been sent or are uploading. A 422 means the account’s schedule has no open slot; a 503 without a reason means resolving one timed out. Neither writes anything, and any pin_schedule charge already taken is refunded. A 503 with reason pinterest_rate_limited is different: Pinterest rate-limited the boardSectionId check, which runs with sendAt too. Nothing was written or charged; retry in a few minutes. A draft saved with multiple interval Boards cannot be scheduled here and is refused with a 400; to publish one Pin across several Boards, create it with intervalBoards on POST /v1/accounts/{accountId}/posts instead. A 400 writes nothing, refunds any charge, and will fail the same way if retried unchanged.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Numeric Tailwind account ID returned by GET /v1/accounts
Post ID
Request Bodyrequired
Section titled “Request Bodyrequired”Provide exactly one of sendAt or useNextOpenSlot. A 422 means the account’s schedule has no open slot; a 503 without a reason means resolving one timed out. Neither writes anything, and any pin_schedule charge is refunded.
object
Explicit publish time (ISO 8601), in the future and within 10 years. Exactly one of sendAt or useNextOpenSlot is required. Sets only the initial time, not an exemption from Pin Spacing: a later respace or schedule shuffle can still move the Pin.
Schedule into the account’s next open smart schedule slot, honoring the account’s Pin Spacing rules for the Pin’s destination url. Exactly one of sendAt or useNextOpenSlot is required; must be true when provided.
Target board ID. Must be the numeric Pinterest board ID from GET /v1/accounts/{accountId}/boards — not a board name or URL. A leading “b_” (Tailwind CSV export format) is accepted and stripped. Required when scheduling a draft that doesn’t already have a board assigned.
Section to publish into, validated against the board this Pin ends up on. Send “” to publish to the board root. Supplying boardId WITHOUT this field clears any section the Pin already had, since a section is only valid on its own board. Use GET /v1/accounts/{accountId}/boards/{boardId}/sections to look up section IDs.
Provide exactly one of sendAt or useNextOpenSlot. A 422 means the account’s schedule has no open slot; a 503 without a reason means resolving one timed out. Neither writes anything, and any pin_schedule charge is refunded.
object
Explicit publish time (ISO 8601), in the future and within 10 years. Exactly one of sendAt or useNextOpenSlot is required. Sets only the initial time, not an exemption from Pin Spacing: a later respace or schedule shuffle can still move the Pin.
Target board ID. Must be the numeric Pinterest board ID from GET /v1/accounts/{accountId}/boards — not a board name or URL. A leading “b_” (Tailwind CSV export format) is accepted and stripped. Required when scheduling a draft that doesn’t already have a board assigned.
Section to publish into, validated against the board this Pin ends up on. Send “” to publish to the board root. Supplying boardId WITHOUT this field clears any section the Pin already had, since a section is only valid on its own board. Use GET /v1/accounts/{accountId}/boards/{boardId}/sections to look up section IDs.
Responses
Section titled “Responses”Post scheduled
object
object
object
Post ID
Post status. draft = saved in Tailwind only, not created on Pinterest; queued = scheduled; sent = published to Pinterest.
URL of the media file
Type of media
Further images of a carousel Pin, in order after the cover in mediaUrl. Absent on a single-image Pin. Per-slide title, description and link are reported when the Pin carries them, but cannot be set through this API yet.
object
URL of this image
Per-slide title, when the Pin has one
Per-slide description, when the Pin has one
Per-slide destination, when the Pin has one
Pin title
Pin description
Destination URL
Target board ID
Name of the Board in boardId, as Tailwind last saw it when listing the account’s Boards. Returned by the get and list reads only; absent when the Pin has no Board or the Board has not been listed yet, such as one created moments ago.
Section of boardId the Pin publishes into. Null when it publishes to the board root.
Alt text for accessibility
Scheduled send time (Unix timestamp)
Actual send time (Unix timestamp)
Creation time (Unix timestamp)
Pinterest pin ID (only present after publishing). This is the id GET /v1/accounts/{accountId}/pins/{pinId}/analytics takes.
Whether this is a simplified pin (as opposed to a standard pin)
Pinterest product-catalog pin IDs tagged on the pin (business accounts only).
ID of the AI generation that produced this post, when Tailwind’s AI generated it from a URL (matches the id returned by POST /v1/accounts/{accountId}/generations) or from a connected feed. Absent for posts created any other way. A draft with one is a generated draft waiting for review.
Why a failed Pin did not publish, as a stable code such as board_not_found, expired_token or user_rate_limit. Present only when status is failed and Tailwind recorded a reason. New codes are added over time, so treat an unrecognized code as a generic failure.
A user-facing explanation of failureReason and what to do next, the same copy the Tailwind dashboard shows for a failed Pin. Present whenever failureReason is; a code with no specific copy gets a generic explanation.
object
Unique request ID for debugging
Example
{ "data": { "post": { "status": "draft", "mediaType": "image" } }}Invalid request, or the post cannot be scheduled as it stands — for example a draft saved with multiple interval Boards. Nothing was scheduled; retrying unchanged fails the same way.
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Examplegenerated
{ "error": { "code": "example", "message": "example", "reason": "example", "resolve_url": "example" }, "meta": { "requestId": "example" }}Authentication required or invalid bearer credentials
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Example
{ "error": { "code": "UNAUTHORIZED", "message": "Invalid API key" }, "meta": { "requestId": "abc123" }}Billing denied — scheduling requires an available credit or trial allowance on the account, or would exceed the plan’s post limit for the billing period
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Example
{ "error": { "code": "PAYMENT_REQUIRED", "message": "Not enough credits to schedule this post.", "reason": "insufficient_credits" }, "meta": { "requestId": "abc123" }}Resource not found
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Example
{ "error": { "code": "NOT_FOUND", "message": "Account not found" }, "meta": { "requestId": "abc123" }}Nothing was scheduled. Either the account’s schedule is being updated by another request (retry shortly), or the post changed status while it was being scheduled (read it back with GET before retrying).
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Examplegenerated
{ "error": { "code": "example", "message": "example", "reason": "example", "resolve_url": "example" }, "meta": { "requestId": "example" }}UseNextOpenSlot only: the account’s smart schedule has no open slot to publish into.
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Examplegenerated
{ "error": { "code": "example", "message": "example", "reason": "example", "resolve_url": "example" }, "meta": { "requestId": "example" }}Rate limit exceeded
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Example
{ "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Daily rate limit of 10000 requests for this organization exceeded. Resets at midnight UTC." }, "meta": { "requestId": "abc123" }}Headers
Section titled “Headers”Seconds until the daily limit resets at midnight UTC.
Pinterest failed the request with an error of its own. A create may still have taken effect, so list Boards or sections before repeating one; other requests can be retried. If the same request keeps failing, Pinterest is refusing it rather than having an outage.
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Example
{ "error": { "code": "BAD_GATEWAY", "message": "Pinterest couldn't complete this request. Please try again.", "reason": "pinterest_request_failed" }, "meta": { "requestId": "abc123" }}Either useNextOpenSlot timed out resolving the next open slot (nothing was scheduled; retry, or pass an explicit sendAt instead), or, with reason pinterest_rate_limited, Pinterest rate-limited the boardSectionId check (nothing was written; retry in a few minutes).
object
object
Error code
Error message
Machine-readable reason. On PAYMENT_REQUIRED errors it is the denial reason: insufficient_credits, trial_exhausted, no_access, account_not_connected, legacy_post_limit_exceeded. Other errors may carry an operation-specific reason, such as pinterest_reconnect_required, pinterest_rate_limited, pinterest_timeout, pinterest_request_failed or list_boards_upstream_failed; each operation’s documented error responses show the values it returns. Branch on reason rather than parsing message.
Present on PAYMENT_REQUIRED errors: where the denial can be resolved. Reason-specific, because buying credits does not clear a trial, access or connection denial. Requests sent with X-Request-Source: mcp receive an informational plans page instead, so agent surfaces never present a purchase link.
object
Unique request ID for debugging
Examplegenerated
{ "error": { "code": "example", "message": "example", "reason": "example", "resolve_url": "example" }, "meta": { "requestId": "example" }}