yikart/AiToEarn · error · PinterestPlatformException
15070
15070
Error message
{{platform}} platform API request failed What it means
PinterestService's axios interceptor converts every failed Pinterest API request into a PinterestPlatformException with ResponseCode.ChannelPlatformApiFailed (15070). Network-level Axios failures (no response) and non-2xx responses from api.pinterest.com are both wrapped, with the Pinterest error body parsed for platform code/message. The exception records endpoint, method, HTTP status, category, retryability, and the raw platform payload.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/pinterest/pinterest.service.ts:45
PinterestPinMediaSourceType,
} from './pinterest.interface'
@Injectable()
export class PinterestService {
private readonly http: AxiosInstance
private readonly apiBaseUrl: string
constructor(private readonly cfg: PinterestConfig) {
this.apiBaseUrl = this.normalizeApiBaseUrl(cfg.baseUrl)
this.http = this.createHttpClient()
}
private createHttpClient(): AxiosInstance {
const http = axios.create()
http.interceptors.response.use(
response => response,
(error: AxiosError<PinterestErrorBody>) => {
throw PinterestPlatformException.fromAxiosError(error)
},
)
return http
}
private normalizeApiBaseUrl(baseUrl: string): string {
const trimmed = (baseUrl || 'https://api.pinterest.com').replace(/\/+$/, '')
return trimmed.endsWith('/v5') ? trimmed : `${trimmed}/v5`
}
generateAuthUrl(scopes: string[], state: string): string {
const params = new URLSearchParams({
client_id: this.cfg.clientId,
redirect_uri: this.cfg.redirectUri,
scope: scopes.join(','),
state,
response_type: 'code',
})View on GitHub (pinned to d3aa8bea5b)
Solutions
- Read the thrown PinterestPlatformException's cause (platformCode, platformMessage, httpStatus) for Pinterest's specific error detail.
- If httpStatus is 401, refresh the Pinterest access token or re-run the OAuth flow, then retry.
- If 403, verify the token scopes cover pin creation and that the target board belongs to the authenticated account.
- If 429 or a retryable network/5xx error, retry with exponential backoff honoring rate-limit headers.
- Validate pin payload fields (board_id, media source, link URL) against the Pinterest v5 schema and confirm base URL handling via normalizeApiBaseUrl is correct.
Example fix
// before: expired token -> 401 wrapped as 15070
const res = await this.http.post(`${this.apiBaseUrl}/v5/pins`, pinBody, { headers: { Authorization: `Bearer ${token}` } })
// after: refresh on 401 and retry
try {
const res = await this.http.post(`${this.apiBaseUrl}/v5/pins`, pinBody, { headers: { Authorization: `Bearer ${token}` } })
} catch (e) {
if (e instanceof PinterestPlatformException && e.cause?.httpStatus === 401) {
const fresh = await this.refreshAccessToken(channel)
const res = await this.http.post(`${this.apiBaseUrl}/v5/pins`, pinBody, { headers: { Authorization: `Bearer ${fresh}` } })
} else throw e
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: token freshness and board ownership check
if (!accessToken || tokenExpiresAt <= new Date()) await refreshPinterestToken(channel)
const boards = await pinterestService.listBoards(accessToken)
if (!boards.some(b => b.id === targetBoardId)) throw new Error(`Board ${targetBoardId} not accessible for this Pinterest account`) Type guard
function isPinterestPlatformException(e: unknown): e is PinterestPlatformException {
return e instanceof PinterestPlatformException
} Try / catch
try {
const result = await pinterestService.createPin(accessToken, pinPayload)
} catch (e) {
if (e instanceof PinterestPlatformException) {
if (e.cause?.httpStatus === 401) {
// refresh token and retry once
} else if (e.retryable) {
// exponential backoff (429 / 5xx / network)
} else {
// log cause.platformCode/platformMessage and notify the channel owner
}
} else throw e
} Prevention
- Refresh Pinterest OAuth tokens before expiry and handle user-initiated revocations by detecting 401 and flagging the channel for re-auth.
- Verify board ownership and token write scopes before attempting pin creation.
- Rate-limit bulk pin creation and honor Pinterest rate-limit headers to avoid 429s.
- Validate pin payloads against the Pinterest v5 API schema; version upgrades often change required fields.
- Confirm server egress to api.pinterest.com and correct base URL normalization in deployment configs.
When it happens
Trigger: Any request through this.http — OAuth token exchange, fetching user boards, creating pins/media uploads — that returns a non-2xx status (401 invalid token, 403 forbidden board/account, 429 rate limit, 400 invalid pin data) or fails before a response arrives (timeout, DNS, connection refused, TLS failure).
Common situations: Pinterest access token expired or user revoked authorization; app missing ads/pins write scopes; publishing to a board the user no longer owns; Pinterest v5 API breaking changes after version bumps; rate limiting during bulk pin creation; server egress blocked to api.pinterest.com.
Related errors
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/8685632fca549795.
Report an issue: GitHub.