Skip to main content
RapidDev - Software Development Agency
bolt-ai-integrationsBolt Chat + API Route

How to Integrate Bolt.new with LinkedIn Ads

Connect Bolt.new to LinkedIn Marketing API by creating a LinkedIn developer app, requesting Marketing API product access, implementing the OAuth 2.0 authorization code flow via a deployed URL, and making API calls through a Next.js API route with your access token. Build dashboards showing campaign performance, spend, impressions, and B2B targeting analytics. LinkedIn's OAuth callback requires a deployed domain — it cannot use Bolt's WebContainer preview URL.

What you'll learn

  • How to create a LinkedIn developer app and request Marketing API product access
  • How to implement the OAuth 2.0 authorization code flow for LinkedIn in a deployed Bolt.new app
  • How to fetch campaign performance data (impressions, clicks, conversions, spend) via the LinkedIn Marketing API
  • How to build a B2B ads analytics dashboard with LinkedIn-specific targeting metrics
  • Why LinkedIn's OAuth callback cannot use Bolt's WebContainer preview URL and how to deploy first
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read45 minutesMarketingApril 2026RapidDev Engineering Team
TL;DR

Connect Bolt.new to LinkedIn Marketing API by creating a LinkedIn developer app, requesting Marketing API product access, implementing the OAuth 2.0 authorization code flow via a deployed URL, and making API calls through a Next.js API route with your access token. Build dashboards showing campaign performance, spend, impressions, and B2B targeting analytics. LinkedIn's OAuth callback requires a deployed domain — it cannot use Bolt's WebContainer preview URL.

Build a LinkedIn Ads Analytics Dashboard from Bolt.new

LinkedIn Ads is the dominant B2B advertising platform — the only place you can target by job title, company size, industry, and seniority simultaneously. For founders and marketers building B2B SaaS products, LinkedIn campaigns are often the highest-intent paid channel. The LinkedIn Marketing API lets you programmatically access your campaign data, build custom dashboards, automate reporting, and manage campaigns at scale — the kind of workflow that would otherwise require manually exporting data from Campaign Manager and pasting it into spreadsheets.

The LinkedIn Marketing API uses the same OAuth 2.0 authorization code flow as most Google and Meta APIs, but with one critical difference: LinkedIn's app review process is stricter. Getting Marketing API access requires creating a developer app, adding the 'Marketing Developer Platform' product, and waiting for LinkedIn to review and approve your application — a process that can take several days to weeks. The Marketing Developer Platform product access is required before any marketing-specific endpoints work. Without it, your app can authenticate users (Member login) but cannot access advertising data.

For Bolt.new developers, there is an important technical constraint: LinkedIn's OAuth callback URL must be a real HTTPS URL registered in your LinkedIn app settings. Bolt's WebContainer preview URL is ephemeral and cannot be registered as an OAuth redirect URI. This means you must deploy your app to Netlify or Vercel and register your deployed domain before you can complete the OAuth flow. This tutorial walks you through building the app in Bolt, deploying it, configuring the OAuth callback, and then connecting to the LinkedIn Marketing API for campaign analytics.

Integration method

Bolt Chat + API Route

LinkedIn Marketing API uses OAuth 2.0 authorization code flow — your app redirects users to LinkedIn to authorize access, LinkedIn redirects back to your app with an authorization code, and you exchange that code for access and refresh tokens. Because the OAuth redirect callback must be a registered URL, you cannot complete the OAuth flow in Bolt's WebContainer preview — deploy to Netlify or Vercel first and register your deployed domain in your LinkedIn app settings. All Marketing API calls (campaign data, analytics, creatives) go through Next.js API routes to keep access tokens secure.

Prerequisites

  • A LinkedIn account with admin access to an active LinkedIn Ads Campaign Manager account
  • A LinkedIn developer app created at developer.linkedin.com with the Marketing Developer Platform product requested and approved
  • A Bolt.new project using Next.js (required for server-side OAuth handling and API routes)
  • A deployed Netlify or Vercel URL to use as the OAuth redirect URI — LinkedIn cannot redirect to Bolt's WebContainer preview
  • Your LinkedIn app's Client ID and Client Secret from the LinkedIn Developer portal

Step-by-step guide

1

Create a LinkedIn Developer App and Request Marketing API Access

Go to developer.linkedin.com and click 'Create app'. You will need to associate the app with a LinkedIn Company Page — if you do not have one, create a company page first (it takes about 2 minutes at linkedin.com/company/setup). Fill in the app name, LinkedIn page, app logo, and agree to the terms. After creating the app, go to the 'Products' tab. You will see a list of LinkedIn API products. Find 'Marketing Developer Platform' and click 'Request access'. LinkedIn will review your application — this is the step where developers often wait. The review process can take from a few hours to several weeks depending on your use case description. While waiting, you can set up the rest of the app. Also request 'Sign In with LinkedIn using OpenID Connect' if you want user authentication. On the 'Auth' tab, add your redirect URLs. You must add both a development URL (you will use a deployed staging URL since Bolt preview cannot receive OAuth callbacks) and your production URL. LinkedIn requires HTTPS for all redirect URIs. Add your Netlify URL now — you will get it after your first deployment. LinkedIn's OAuth 2.0 scopes for Marketing API include: r_ads (read ad accounts), r_ads_reporting (read analytics), rw_ads (read/write for managing campaigns), and r_organization_social. Request only the scopes your app needs — unnecessary permissions slow down the review process.

Bolt.new Prompt

Set up the LinkedIn Marketing API integration for my Next.js Bolt.new app. Create a .env file with placeholders: LINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRET, LINKEDIN_REDIRECT_URI, NEXTAUTH_SECRET, NEXTAUTH_URL. Create lib/linkedin.ts with: (1) a buildAuthUrl() function that generates the LinkedIn OAuth authorization URL with scopes r_ads and r_ads_reporting, including a random state parameter for CSRF protection; (2) an exchangeCodeForTokens(code) function that POSTs to https://www.linkedin.com/oauth/v2/accessToken to exchange the auth code for access and refresh tokens; (3) a refreshAccessToken(refreshToken) function.

Paste this in Bolt.new chat

lib/linkedin.ts
1// lib/linkedin.ts
2const LINKEDIN_AUTH_URL = 'https://www.linkedin.com/oauth/v2/authorization';
3const LINKEDIN_TOKEN_URL = 'https://www.linkedin.com/oauth/v2/accessToken';
4
5export function buildAuthUrl(state: string): string {
6 const params = new URLSearchParams({
7 response_type: 'code',
8 client_id: process.env.LINKEDIN_CLIENT_ID!,
9 redirect_uri: process.env.LINKEDIN_REDIRECT_URI!,
10 state,
11 scope: 'r_ads r_ads_reporting',
12 });
13 return `${LINKEDIN_AUTH_URL}?${params.toString()}`;
14}
15
16export async function exchangeCodeForTokens(code: string) {
17 const response = await fetch(LINKEDIN_TOKEN_URL, {
18 method: 'POST',
19 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
20 body: new URLSearchParams({
21 grant_type: 'authorization_code',
22 code,
23 redirect_uri: process.env.LINKEDIN_REDIRECT_URI!,
24 client_id: process.env.LINKEDIN_CLIENT_ID!,
25 client_secret: process.env.LINKEDIN_CLIENT_SECRET!,
26 }),
27 });
28 if (!response.ok) throw new Error(`Token exchange failed: ${await response.text()}`);
29 return response.json() as Promise<{
30 access_token: string;
31 expires_in: number;
32 refresh_token: string;
33 refresh_token_expires_in: number;
34 }>;
35}
36
37export async function callLinkedInAPI(endpoint: string, accessToken: string) {
38 const response = await fetch(`https://api.linkedin.com/v2${endpoint}`, {
39 headers: {
40 'Authorization': `Bearer ${accessToken}`,
41 'LinkedIn-Version': '202401',
42 'X-Restli-Protocol-Version': '2.0.0',
43 },
44 });
45 if (!response.ok) throw new Error(`LinkedIn API error: ${response.status} ${await response.text()}`);
46 return response.json();
47}

Pro tip: LinkedIn's Marketing API scopes are additive — r_ads gives read access to ad accounts and campaigns, r_ads_reporting adds analytics data. If you only need reporting (not campaign management), request just r_ads and r_ads_reporting in your app review to improve approval chances.

Expected result: The LinkedIn app is created, Marketing Developer Platform access is requested, and the auth utility functions are in place. You have the Client ID and Client Secret from the LinkedIn Developer portal.

2

Deploy to Netlify First, Then Configure OAuth Redirect URI

This step is the most critical difference between LinkedIn Ads integration and simpler API integrations. LinkedIn's OAuth 2.0 authorization code flow requires a redirect URI — when the user authorizes your app on LinkedIn's website, LinkedIn redirects them back to your app at the URL you specify. This URL must be pre-registered in your LinkedIn developer app settings and must use HTTPS. Bolt's WebContainer preview URL is ephemeral (it changes between sessions) and is not publicly accessible from LinkedIn's servers — it cannot be used as an OAuth redirect URI. You must deploy your app to get a stable HTTPS URL before the OAuth flow can work. In Bolt, go to Settings → Applications and connect Netlify (or Vercel) via OAuth. Click Publish. After deployment, copy your Netlify URL (e.g., https://your-app-name.netlify.app). Go back to developer.linkedin.com → your app → Auth tab → Redirect URLs, and add https://your-app-name.netlify.app/api/auth/linkedin/callback. Update your LINKEDIN_REDIRECT_URI environment variable in Netlify's Site Configuration → Environment Variables and redeploy. For local development, you can use a tool like ngrok to create a temporary HTTPS tunnel to your local server and register that as a development redirect URI — but this is optional. Note: Bolt's WebContainer during development cannot receive incoming OAuth callbacks. This is a fundamental WebContainer limitation — the browser-based runtime has no public URL. Build and test the non-OAuth parts of your app in the preview, and test the full OAuth flow on your deployed Netlify URL.

Bolt.new Prompt

Create the OAuth callback route for LinkedIn. Create app/api/auth/linkedin/callback/route.ts that: (1) reads the 'code' and 'state' query parameters, (2) validates the state against what was stored in a cookie to prevent CSRF attacks, (3) calls exchangeCodeForTokens(code) from lib/linkedin.ts, (4) stores the access_token and refresh_token in an encrypted HTTP-only cookie using the NEXTAUTH_SECRET, (5) redirects to /dashboard. Also create app/api/auth/linkedin/login/route.ts that generates a random state, stores it in a cookie, and redirects to the LinkedIn auth URL built by buildAuthUrl().

Paste this in Bolt.new chat

app/api/auth/linkedin/callback/route.ts
1// app/api/auth/linkedin/callback/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { exchangeCodeForTokens } from '@/lib/linkedin';
4import { cookies } from 'next/headers';
5
6export async function GET(request: NextRequest) {
7 const { searchParams } = new URL(request.url);
8 const code = searchParams.get('code');
9 const state = searchParams.get('state');
10 const error = searchParams.get('error');
11
12 if (error) {
13 return NextResponse.redirect(new URL('/login?error=linkedin_denied', request.url));
14 }
15
16 // Validate CSRF state
17 const cookieStore = await cookies();
18 const savedState = cookieStore.get('linkedin_oauth_state')?.value;
19 if (!state || state !== savedState) {
20 return NextResponse.redirect(new URL('/login?error=invalid_state', request.url));
21 }
22
23 if (!code) {
24 return NextResponse.redirect(new URL('/login?error=no_code', request.url));
25 }
26
27 const tokens = await exchangeCodeForTokens(code);
28
29 const response = NextResponse.redirect(new URL('/dashboard', request.url));
30 // Store tokens in HTTP-only cookies (production: encrypt with NEXTAUTH_SECRET)
31 response.cookies.set('linkedin_access_token', tokens.access_token, {
32 httpOnly: true,
33 secure: true,
34 maxAge: tokens.expires_in,
35 path: '/',
36 });
37 response.cookies.set('linkedin_refresh_token', tokens.refresh_token, {
38 httpOnly: true,
39 secure: true,
40 maxAge: tokens.refresh_token_expires_in,
41 path: '/',
42 });
43 // Clear the state cookie
44 response.cookies.delete('linkedin_oauth_state');
45
46 return response;
47}

Pro tip: Store LinkedIn tokens in HTTP-only cookies, not localStorage or sessionStorage. HTTP-only cookies cannot be read by JavaScript in the browser, protecting the access_token from XSS attacks. Use the 'secure' flag so the cookie is only sent over HTTPS on your deployed Netlify domain.

Expected result: After deploying to Netlify and registering the callback URL, users can complete the LinkedIn OAuth flow. The access_token is stored in an HTTP-only cookie after successful authorization.

3

Fetch Campaign Performance Data from Marketing API

With an access token obtained from the OAuth flow, you can now query LinkedIn's Marketing API for campaign analytics. The key endpoints are: /adAccountsV2 (list ad accounts the user has access to), /adCampaignsV2 (list campaigns within an account), and /adAnalyticsV2 (fetch performance metrics). The analytics endpoint is the most powerful — it supports filtering by campaign, date range, and demographic dimensions, and returns metrics like impressions, clicks, spend (in micro-currency units — divide by 1,000,000 for USD), conversions, and conversion value. LinkedIn's API uses the 'finder' pattern for analytics: you POST a query specifying pivots (dateRange, campaign), timeGranularity (DAILY, MONTHLY, ALL), and metrics (impressions, clicks, externalWebsiteConversions, costInLocalCurrency). The response is a collection of data points. LinkedIn's spend values are returned in micro-currency (e.g., 5000000 means $5.00 USD) — always divide by 1,000,000 when displaying. Similarly, LinkedIn uses URN-formatted identifiers (e.g., 'urn:li:sponsoredCampaign:12345678') — extract the numeric ID for display. All Marketing API calls must include the 'LinkedIn-Version' header set to the API version date (e.g., '202401') and the 'X-Restli-Protocol-Version: 2.0.0' header. During development in Bolt's WebContainer, you cannot test this end-to-end because the OAuth flow requires your deployed URL. You can, however, build and style the dashboard UI components in the Bolt preview using mock data, then connect the real API after deployment.

Bolt.new Prompt

Create a Next.js API route at app/api/linkedin/analytics/route.ts. It reads the linkedin_access_token from cookies. It fetches campaign analytics from the LinkedIn Marketing API: GET /adAnalyticsV2 with query params for accounts (the user's ad account URN), dateRange.start.day/month/year, dateRange.end.day/month/year, timeGranularity=MONTHLY, and fields=impressions,clicks,externalWebsiteConversions,costInLocalCurrency. Return formatted results with spend converted from micro-currency (divide by 1000000) to a dollar amount. Create a /dashboard page that calls this API route and displays the results as: 4 KPI cards (total impressions, total clicks, total spend in USD, total conversions) and a line chart using Recharts showing daily spend over the selected period.

Paste this in Bolt.new chat

app/api/linkedin/analytics/route.ts
1// app/api/linkedin/analytics/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { cookies } from 'next/headers';
4
5export async function GET(request: NextRequest) {
6 const cookieStore = await cookies();
7 const accessToken = cookieStore.get('linkedin_access_token')?.value;
8
9 if (!accessToken) {
10 return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
11 }
12
13 const { searchParams } = new URL(request.url);
14 const accountId = searchParams.get('accountId');
15 const daysBack = parseInt(searchParams.get('days') || '30');
16
17 const endDate = new Date();
18 const startDate = new Date();
19 startDate.setDate(startDate.getDate() - daysBack);
20
21 const params = new URLSearchParams({
22 q: 'analytics',
23 pivot: 'CAMPAIGN',
24 dateRange: JSON.stringify({
25 start: { day: startDate.getDate(), month: startDate.getMonth() + 1, year: startDate.getFullYear() },
26 end: { day: endDate.getDate(), month: endDate.getMonth() + 1, year: endDate.getFullYear() },
27 }),
28 timeGranularity: 'MONTHLY',
29 accounts: `List(urn:li:sponsoredAccount:${accountId})`,
30 fields: 'impressions,clicks,externalWebsiteConversions,costInLocalCurrency,dateRange',
31 });
32
33 const response = await fetch(`https://api.linkedin.com/v2/adAnalyticsV2?${params}`, {
34 headers: {
35 'Authorization': `Bearer ${accessToken}`,
36 'LinkedIn-Version': '202401',
37 'X-Restli-Protocol-Version': '2.0.0',
38 },
39 });
40
41 if (!response.ok) {
42 return NextResponse.json({ error: await response.text() }, { status: response.status });
43 }
44
45 const raw = await response.json();
46 // LinkedIn spend is in micro-currency — divide by 1,000,000 for USD
47 const data = (raw.elements || []).map((el: Record<string, unknown>) => ({
48 ...el,
49 spendUSD: Number(el.costInLocalCurrency) / 1_000_000,
50 ctr: el.impressions ? ((Number(el.clicks) / Number(el.impressions)) * 100).toFixed(2) : '0.00',
51 }));
52
53 return NextResponse.json({ data });
54}

Pro tip: LinkedIn's micro-currency format (1000000 = $1.00 USD) applies to costInLocalCurrency and all spend-related fields. Always divide by 1,000,000 before displaying spend to users. Also note that LinkedIn CTR tends to be lower than other platforms (0.3-0.5% is typical) — do not assume something is broken if CTR looks low.

Expected result: The analytics API route returns campaign metrics including impressions, clicks, spend in USD, and conversions. The dashboard page displays KPI cards and a trend chart with real LinkedIn Ads data.

Common use cases

LinkedIn Ads Performance Dashboard

Build a real-time dashboard showing your LinkedIn campaign performance — impressions, clicks, click-through rate, conversions, cost per conversion, and total spend — broken down by campaign or ad. Fetch this data from the LinkedIn Marketing API and display it in charts and tables tailored for B2B metrics reporting.

Bolt.new Prompt

Build a LinkedIn Ads analytics dashboard. Create a Next.js API route at app/api/linkedin/campaigns/route.ts that fetches campaign analytics from the LinkedIn Marketing API using an OAuth access token stored in session. Display metrics in cards at the top: total impressions, total clicks, total spend (formatted as currency), and average CTR. Below, show a table of campaigns with columns for campaign name, status, impressions, clicks, CTR, conversions, and spend. Add a date range filter (last 7 days, 30 days, 90 days).

Copy this prompt to try it in Bolt.new

B2B Audience Targeting Analyzer

Analyze which audience segments are performing best in your LinkedIn campaigns — which job titles, companies, industries, or seniority levels drive the most conversions at the lowest cost. Fetch demographic breakdown data from the LinkedIn Marketing API and visualize it as ranked charts.

Bolt.new Prompt

Build a LinkedIn audience analyzer page. Create an API route that fetches demographic breakdown analytics from the LinkedIn Marketing API for a given campaign. Show a bar chart of performance by job function (with impressions and conversions per segment), a ranked list of top-performing company industries, and a table comparing seniority levels by cost-per-conversion. Use Recharts for the visualizations. This helps identify which B2B audience segments are most valuable.

Copy this prompt to try it in Bolt.new

Multi-Account Ad Spend Tracker

For agencies or businesses managing multiple LinkedIn Ads accounts, build a consolidated spend tracker that shows total daily and monthly spend across all linked accounts, budget utilization percentage, and spend pacing. Pull data from the Marketing API for each account and aggregate it in a single view.

Bolt.new Prompt

Build a LinkedIn Ads spend tracker for multiple ad accounts. After LinkedIn OAuth authentication, fetch all ad accounts the user has access to via the /adAccountsV2 endpoint. For each account, fetch the current month's total spend using the analytics endpoint. Display a summary card per account showing: account name, account ID, monthly budget, current month spend, and spend pacing (percentage of monthly budget used as of today). Show a total across all accounts at the top.

Copy this prompt to try it in Bolt.new

Troubleshooting

OAuth redirect fails with 'redirect_uri_mismatch' error on LinkedIn's authorization page

Cause: The redirect_uri in your authorization URL does not exactly match the URL registered in your LinkedIn developer app's Auth settings. LinkedIn requires an exact string match including trailing slashes.

Solution: In developer.linkedin.com → your app → Auth tab → Redirect URLs, verify the registered URL matches exactly what your LINKEDIN_REDIRECT_URI environment variable contains. Even a trailing slash difference causes this error. Also ensure you are using your deployed Netlify URL — Bolt's WebContainer preview URL cannot be registered.

typescript
1// Ensure the redirect_uri in buildAuthUrl() exactly matches what LinkedIn has registered
2// Example: https://your-app.netlify.app/api/auth/linkedin/callback
3// NOT: https://your-app.netlify.app/api/auth/linkedin/callback/ (trailing slash differs)

LinkedIn Marketing API returns 403 Forbidden with 'Access denied' when calling /adAccountsV2

Cause: The Marketing Developer Platform product has not been approved yet, or the OAuth scopes requested (r_ads, r_ads_reporting) were not included when the user authorized the app.

Solution: Check your LinkedIn developer app's Products tab — Marketing Developer Platform must show 'Added' status, not 'Pending review'. If it is still pending, wait for approval. If already approved, ensure the OAuth authorization URL includes scope=r_ads r_ads_reporting as URL-encoded scope parameters. Have the user re-authorize to get a new token with the correct scopes.

LinkedIn spend values appear as large numbers like 5000000 instead of $5.00

Cause: LinkedIn Marketing API returns cost values in micro-currency units — 1,000,000 units equals 1 unit of the account currency (e.g., $1.00 USD).

Solution: Divide all costInLocalCurrency, totalBudget, and spend-related fields by 1,000,000 when displaying to users.

typescript
1// Convert micro-currency to currency
2const spendUSD = Number(element.costInLocalCurrency) / 1_000_000;
3const formatted = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(spendUSD);

LinkedIn OAuth flow works on deployed Netlify but returns 'invalid_redirect_uri' during local development in Bolt's preview

Cause: Bolt's WebContainer preview URL is not a stable HTTPS URL and cannot be registered as an OAuth redirect URI. LinkedIn requires a pre-registered HTTPS URL for all redirects.

Solution: This is a known WebContainer limitation — incoming OAuth redirects cannot be received during development. Test the LinkedIn OAuth flow using your deployed Netlify URL. For the dashboard UI components, use mock data during development in Bolt's preview, then connect the real API after deployment.

Best practices

  • Deploy to Netlify or Vercel before testing the LinkedIn OAuth flow — Bolt's WebContainer preview cannot receive OAuth redirect callbacks from LinkedIn
  • Store access tokens in HTTP-only cookies, not localStorage — HTTP-only cookies are inaccessible to JavaScript and protected from XSS attacks
  • Request only the OAuth scopes you need (r_ads for account data, r_ads_reporting for analytics) — unnecessary scope requests slow down LinkedIn's app review process
  • Always divide LinkedIn spend values by 1,000,000 — costInLocalCurrency and all budget fields use micro-currency units
  • Implement token refresh logic using the refresh_token before the access_token expires (LinkedIn access tokens last 60 days, refresh tokens last 365 days)
  • Add a CSRF state parameter to the OAuth authorization URL and validate it in the callback to prevent state forgery attacks
  • Cache campaign list data with a short TTL (5-15 minutes) — LinkedIn's Marketing API has rate limits and campaign metadata does not change frequently

Alternatives

Frequently asked questions

Can I test LinkedIn OAuth in Bolt's WebContainer preview?

No. LinkedIn's OAuth flow redirects the user to LinkedIn's website and then back to your app's callback URL. Bolt's WebContainer during development does not have a public URL that LinkedIn can redirect to. You must deploy your app to Netlify or Vercel, register your deployed URL in the LinkedIn developer portal, and test the OAuth flow on the deployed app.

How long does it take to get LinkedIn Marketing API access approved?

LinkedIn's review of the Marketing Developer Platform product access takes anywhere from a few hours to several weeks. The review is faster if you provide a detailed description of your use case and already have a deployed application with the app logo and LinkedIn company page properly set up. Personal developer accounts without company associations tend to face longer review times.

What scopes do I need for reading LinkedIn Ads campaign performance data?

To read campaign performance analytics, you need r_ads (read access to ad accounts and campaign structures) and r_ads_reporting (read access to campaign analytics and reporting data). If you also need to create or modify campaigns, add rw_ads. Request only the scopes you need — broader scope requests can slow down LinkedIn's review process.

Why are LinkedIn spend values showing as very large numbers?

LinkedIn's Marketing API returns cost values in micro-currency — 1,000,000 units equals 1 currency unit (e.g., $1.00 USD or €1.00 EUR). Always divide costInLocalCurrency and all budget-related fields by 1,000,000 before displaying them. This is a common gotcha for developers new to LinkedIn's Marketing API.

How do I handle LinkedIn token expiry in my Bolt.new app?

LinkedIn access tokens expire after 60 days, and refresh tokens expire after 365 days. Implement a token refresh flow: before making Marketing API calls, check the cookie's expiry or make the call and catch 401 errors. If expired, use the refresh_token to call /oauth/v2/accessToken with grant_type=refresh_token to get a new access_token without requiring the user to re-authorize.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.