List top-performing Pins
const url = 'https://api-v1.tailwind.ai/v1/accounts/example/top-pins?sortBy=ENGAGEMENT&contentType=ALL';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api-v1.tailwind.ai/v1/accounts/example/top-pins?sortBy=ENGAGEMENT&contentType=ALL' \ --header 'Authorization: Bearer <token>'The account’s best-performing Pins over a date window, ranked by one metric and returned in Pinterest’s ranked order. Metrics and ranking combine paid (promoted) and organic activity unless contentType says otherwise, so by default ad spend can crowd organic Pins out of the list and a promoted Pin can rank far higher than its organic-only per-Pin analytics suggest. contentType ORGANIC ranks on unpromoted activity alone, PAID on promoted only; the filter applied is echoed back as contentType.
Ranks by ENGAGEMENT unless sortBy says otherwise, and echoes the metric used back as sortBy. Engagement is the default rather than impressions because it counts what people did with a Pin rather than how often Pinterest showed it.
Each entry carries the Pinterest pinId, which is what GET /v1/accounts/{accountId}/pins/{pinId}/analytics takes — this endpoint is the usual way to find Pins worth reading in detail.
Omit startDate and endDate for the last 30 days (today and the 29 days before it, UTC). Supply both to choose a window; supplying only one is a 400. The window actually used is echoed back as startDate/endDate inside data, so a caller never has to infer the period a number covers. Pinterest’s own limits apply: startDate no more than 90 days before today, endDate no more than 90 days after startDate.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Numeric Tailwind account ID returned by GET /v1/accounts
Query Parameters
Section titled “Query Parameters”Metric to rank by. Defaults to ENGAGEMENT. Only these five are accepted — Pinterest’s documented sort vocabulary.
Which activity to count: ORGANIC for unpromoted activity only, PAID for promoted (ad) activity only, ALL for both blended. Defaults to ALL.
First day of the reporting window, as a UTC calendar date (YYYY-MM-DD). Must be supplied together with endDate; omit both for the last 30 days. Pinterest does not report further back than 90 days.
Last day of the reporting window, inclusive, as a UTC calendar date (YYYY-MM-DD). Must be supplied together with startDate. Cannot be more than 90 days after startDate.
Responses
Section titled “Responses”Top-performing Pins over the resolved window, ranked by the resolved metric
object
object
One of the account’s best-performing Pins. A deliberately narrow projection of Pinterest’s Pin payload — tracking parameters, per-metric status flags, promotion state and internal identifiers are not passed through.
object
The Pinterest Pin id. This is the id GET /v1/accounts/{accountId}/pins/{pinId}/analytics takes — not a Tailwind postId.
Where the Pin links to
The Pin’s own page on Pinterest
The Pinterest board the Pin is saved to — the same id GET /v1/accounts/{accountId}/boards returns. Group by it to compare performance across boards.
Pinterest’s creative format for the Pin, verbatim — for example REGULAR, VIDEO, CAROUSEL, IDEA or COLLAGE. Pinterest adds values over time, so treat it as an open set. Null when Pinterest did not report one.
Pinterest metrics, camelCased (impression, save, saveRate, pinClick, outboundClick, engagement, engagementRate, …). A metric Pinterest does not report for this subject is ABSENT; a metric it reports as not-yet-computed is present and NULL. The two mean different things — absent will never arrive, null may.
object
True when some Pins Pinterest ranked are missing from pins because Pinterest limited the lookups of their details. Retrying shortly should return the full list. Pins Pinterest reports as deleted or no longer visible are left out without setting it, since a retry would not bring them back.
The Pinterest Pin ids missing from pins for that reason, in ranking order. Empty when isPartial is false. Where they ranked among pins is not known.
object
Unique request ID for debugging
Example
{ "data": { "sortBy": "ENGAGEMENT", "contentType": "ALL" }}Invalid request
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_REQUEST", "message": "Invalid request body" }, "meta": { "requestId": "abc123" }}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" }}Pinterest refused to report analytics for this subject. PERMANENT, and distinct from the collaborator-board 403 on the board endpoints: for a Pin, Pinterest has forbidden analytics on it and it will never start reporting; for an account, analytics require a Pinterest business account. Retrying will return the same answer.
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": "FORBIDDEN", "message": "Pinterest does not permit analytics for this Pin. This is permanent for this Pin — it will not start reporting later, so do not retry.", "reason": "pinterest_analytics_forbidden" }, "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" }}The account’s Pinterest connection is no longer usable. Your API key is fine — this is not an authentication failure on Tailwind’s side, which is why it is not a 401. The account holder needs to reconnect Pinterest in Tailwind before this operation can succeed.
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": "UNPROCESSABLE_ENTITY", "message": "Reconnect your Pinterest account to manage Boards.", "reason": "pinterest_reconnect_required" }, "meta": { "requestId": "abc123" }}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 read with an error on its side. Whether it is permanent is unknown, so this stays a 500, but retrying right away will not help; try again later.
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": "INTERNAL_ERROR", "message": "Pinterest failed to return analytics for this Pin. The error is on Pinterest's side, so retrying right away will not help. Try again later.", "reason": "pinterest_upstream_error" }, "meta": { "requestId": "abc123" }}Pinterest rate-limited the request. Pinterest refused it before acting, so nothing was changed. Distinct from a 429, which means the organization’s shared daily request limit — retry this request in a few minutes rather than backing off across the API.
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": "SERVICE_UNAVAILABLE", "message": "Pinterest is limiting requests for this account right now. Nothing was changed. Retry in a few minutes.", "reason": "pinterest_rate_limited" }, "meta": { "requestId": "abc123" }}Headers
Section titled “Headers”Seconds until Pinterest’s limit for this account resets. Sent by the analytics and Pin inventory operations when Pinterest reports it; absent otherwise.
