To integrate Bing Ads (Microsoft Advertising) with V0 by Vercel, use the Microsoft Advertising REST API through a Next.js API route. V0 generates the dashboard UI; your server-side route authenticates with OAuth 2.0 and fetches campaign performance data. Display search advertising metrics like impressions, clicks, spend, and ROAS in a V0-generated analytics dashboard.
Build a Microsoft Advertising Campaign Dashboard with V0 and the Bing Ads REST API
Microsoft Advertising (Bing Ads) serves ads across Bing, Yahoo, DuckDuckGo, and Microsoft's partner network — a significant audience that complements Google Ads campaigns. For V0 developers building marketing dashboards, the Microsoft Advertising REST API provides access to all campaign performance data: impressions, clicks, conversions, cost, ROAS, and Quality Score across campaigns, ad groups, ads, and keywords.
The integration follows V0's standard external-API pattern: V0 generates the analytics dashboard UI with charts, metric cards, and data tables. A Next.js API route handles Microsoft Advertising authentication and data fetching on the server. The OAuth credentials and developer token stay in Vercel environment variables and never reach the browser — the frontend only receives the processed performance data returned by your API route.
The Microsoft Advertising API is a SOAP/REST hybrid, but its REST endpoints are the recommended path for new integrations. Authentication uses Microsoft's standard OAuth 2.0 flow with the Azure Active Directory tenant. One important consideration: Microsoft Advertising requires a developer token from the Microsoft Advertising developer portal — this is separate from your OAuth credentials and must be included in every API request. The API has two modes: sandbox for testing and production for live data, each with different base URLs.
Integration method
Microsoft Advertising connects to V0-generated Next.js apps through server-side API routes that authenticate with OAuth 2.0 and call the Microsoft Advertising REST API. Campaign performance data is fetched server-side using your developer token and OAuth access token, then returned to the V0-generated dashboard components. Access tokens expire and require refresh token rotation.
Prerequisites
- A V0 account at v0.dev with a Next.js project created
- A Microsoft Advertising (Bing Ads) account with active campaigns at ads.microsoft.com
- A Microsoft Advertising developer token from the Microsoft Advertising developer portal
- An Azure Active Directory app registration with OAuth 2.0 client credentials for the Advertising API
- A Vercel account connected to your V0 project for deployment
Step-by-step guide
Get a Microsoft Advertising Developer Token and Set Up OAuth
Get a Microsoft Advertising Developer Token and Set Up OAuth
Microsoft Advertising requires two separate credentials: a developer token (for API access) and OAuth 2.0 credentials (for account authentication). You need both to make API calls. To get a developer token: log into ads.microsoft.com, go to the top-right menu → Tools → API Center → Apply for a developer token. Production developer tokens require a Microsoft Advertising account with active campaigns and billing. For testing, use the sandbox environment which has its own developer token. The developer token is a fixed string like 'BBD37VB98' — copy it and store it as BING_ADS_DEV_TOKEN in Vercel. For OAuth setup: go to portal.azure.com → Azure Active Directory → App registrations → New registration. Name your app (e.g., 'My V0 Ads Dashboard'), select 'Accounts in any organizational directory and personal Microsoft accounts', and set the redirect URI to https://your-app.vercel.app/api/bing-ads/callback. After creation, note the Application (client) ID as BING_ADS_CLIENT_ID. Go to Certificates & Secrets → New client secret → add expiry → copy the secret value as BING_ADS_CLIENT_SECRET. For the initial OAuth flow, you need to get a refresh token for your Microsoft Advertising account. Use the OAuth 2.0 authorization code flow: direct the user to https://login.microsoftonline.com/common/oauth2/v2.0/authorize with your client ID, redirect URI, and scope (https://ads.microsoft.com/msads.manage offline_access). After authorization, Microsoft redirects with a code that you exchange for access and refresh tokens. Store the refresh token in your database or Vercel environment for server-side use. Access tokens expire after 1 hour; refresh tokens last 90 days. Important V0 limitation: V0 can generate the OAuth callback handler code and the API route structure, but it cannot complete the OAuth authorization flow or generate real access tokens. You need to run the OAuth flow manually once to get a refresh token before your dashboard can fetch live data.
Create a Microsoft Advertising connection setup page with a 'Connect Microsoft Advertising Account' button that redirects to /api/bing-ads/auth. Show connection status with a green badge if BING_ADS_REFRESH_TOKEN is set (check via /api/bing-ads/status), or an orange 'Not Connected' badge with instructions to complete OAuth setup. Include a settings form with optional Customer ID and Account ID fields.
Paste this in V0 chat
1// app/api/bing-ads/auth/route.ts — OAuth initiation2import { NextResponse } from 'next/server';34export async function GET() {5 const clientId = process.env.BING_ADS_CLIENT_ID;6 const redirectUri = process.env.BING_ADS_REDIRECT_URI;78 if (!clientId || !redirectUri) {9 return NextResponse.json(10 { error: 'BING_ADS_CLIENT_ID and BING_ADS_REDIRECT_URI must be configured' },11 { status: 500 }12 );13 }1415 const scope = 'https://ads.microsoft.com/msads.manage offline_access';16 const authUrl = new URL('https://login.microsoftonline.com/common/oauth2/v2.0/authorize');17 authUrl.searchParams.set('client_id', clientId);18 authUrl.searchParams.set('redirect_uri', redirectUri);19 authUrl.searchParams.set('response_type', 'code');20 authUrl.searchParams.set('scope', scope);21 authUrl.searchParams.set('response_mode', 'query');2223 return NextResponse.redirect(authUrl.toString());24}Pro tip: After completing the OAuth flow, store the refresh token as BING_ADS_REFRESH_TOKEN in Vercel environment variables. For multi-user apps where different users connect their own Bing Ads accounts, store tokens in your database associated with each user session.
Expected result: You have BING_ADS_DEV_TOKEN, BING_ADS_CLIENT_ID, BING_ADS_CLIENT_SECRET, and BING_ADS_REFRESH_TOKEN in Vercel environment variables. The OAuth callback route exchanges codes for tokens.
Create the Token Refresh Helper and Base API Client
Create the Token Refresh Helper and Base API Client
Microsoft Advertising access tokens expire after 1 hour. Build a helper function that uses the stored refresh token to get a fresh access token before each API call. This is the core infrastructure all other Bing Ads API routes will use. Create a lib/bing-ads.ts utility file with the token refresh logic and a base API fetch function. The token refresh endpoint is https://login.microsoftonline.com/common/oauth2/v2.0/token. Successful refresh returns a new access_token and optionally a new refresh_token. Some implementations cache the access token in memory (module-level variable with expiry tracking) to avoid refreshing on every API call — access tokens are valid for 3600 seconds. The Microsoft Advertising REST API base URL for production is https://campaign.api.bingads.microsoft.com/api/advertiser/campaignmanagement/v13/. All requests require three headers: Authorization: Bearer {access_token}, DeveloperToken: {developer_token}, and CustomerId: {customer_id}. The customer ID is the top-level account identifier visible in the Microsoft Advertising UI URL. The reporting API (for performance metrics) uses a different approach: you submit a report request, wait for it to complete, and download the results. For simpler campaign list and status data, the Campaign Management API returns data directly. For dashboards requiring immediate data, use the Campaign Management API for real-time campaign data and the Bulk API for historical performance reports. For V0-generated dashboards, the Campaign Management API's GetCampaignsByAccountId endpoint gives you real-time campaign status and budget data. For historical performance metrics (impressions, clicks, spend), use the Reporting API with a date range.
1// lib/bing-ads.ts2interface TokenResponse {3 access_token: string;4 token_type: string;5 expires_in: number;6 refresh_token?: string;7}89let cachedToken: { token: string; expiresAt: number } | null = null;1011export async function getBingAdsAccessToken(): Promise<string> {12 // Return cached token if still valid (with 60s buffer)13 if (cachedToken && Date.now() < cachedToken.expiresAt - 60000) {14 return cachedToken.token;15 }1617 const refreshToken = process.env.BING_ADS_REFRESH_TOKEN;18 const clientId = process.env.BING_ADS_CLIENT_ID;19 const clientSecret = process.env.BING_ADS_CLIENT_SECRET;2021 if (!refreshToken || !clientId || !clientSecret) {22 throw new Error('Missing Bing Ads OAuth credentials in environment variables');23 }2425 const response = await fetch(26 'https://login.microsoftonline.com/common/oauth2/v2.0/token',27 {28 method: 'POST',29 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },30 body: new URLSearchParams({31 client_id: clientId,32 client_secret: clientSecret,33 refresh_token: refreshToken,34 grant_type: 'refresh_token',35 scope: 'https://ads.microsoft.com/msads.manage offline_access',36 }),37 }38 );3940 if (!response.ok) {41 const error = await response.text();42 throw new Error(`Token refresh failed: ${error}`);43 }4445 const data: TokenResponse = await response.json();46 cachedToken = {47 token: data.access_token,48 expiresAt: Date.now() + data.expires_in * 1000,49 };5051 return data.access_token;52}5354export function getBingAdsHeaders(accessToken: string): Record<string, string> {55 return {56 Authorization: `Bearer ${accessToken}`,57 DeveloperToken: process.env.BING_ADS_DEV_TOKEN!,58 CustomerId: process.env.BING_ADS_CUSTOMER_ID!,59 'Content-Type': 'application/json',60 };61}Pro tip: Cache the access token in a module-level variable with expiry tracking to avoid a token refresh on every single API request. Serverless function warm instances will reuse the cached token across multiple requests.
Expected result: The token refresh utility correctly exchanges the refresh token for a fresh access token. The cached token is reused until it expires. All subsequent API routes import and use getBingAdsAccessToken().
Create the Campaigns Performance API Route
Create the Campaigns Performance API Route
Build the main campaign data API route that fetches campaign list and performance metrics from Microsoft Advertising. This route is what V0-generated dashboard components call to display advertising data. Create app/api/bing-ads/campaigns/route.ts. The route uses the token refresh helper to get an access token, then calls the Microsoft Advertising Campaign Management API to list campaigns and their status, budget, and spend data. The AccountId parameter is your Microsoft Advertising account ID — find it in the Microsoft Advertising UI at Tools → Accounts & Billing → Account details, or in the URL as your account number. For performance metrics (impressions, clicks, CTR, conversions, ROAS), you use the Microsoft Advertising Reporting API. The reporting flow involves: (1) submitting a report request with date range, metrics, and segmentation, (2) polling for report completion status, (3) downloading the completed report CSV. This asynchronous flow takes 10-120 seconds depending on data volume. For a dashboard that needs near-real-time data, a practical approach is to pre-aggregate report data on a schedule (using Vercel Cron Jobs) and store results in your database. The dashboard then reads from your database rather than calling the Microsoft Advertising reporting API on demand. This avoids the slow asynchronous report generation for every page load. The example below uses the Campaign Management API for direct campaign data, which returns faster than the reporting API and includes current budget, status, and basic spend data.
Build a campaigns performance table that fetches from /api/bing-ads/campaigns and displays: Campaign Name, Status (Active/Paused/Ended badges with colors), Daily Budget, Impressions, Clicks, CTR percentage, Average CPC, Total Spend, Conversions, and ROAS. Add a search filter for campaign name. Show total row at the bottom summing numeric columns. Include a date range picker defaulting to last 30 days. Format currency as USD with 2 decimal places.
Paste this in V0 chat
1import { NextRequest, NextResponse } from 'next/server';2import { getBingAdsAccessToken, getBingAdsHeaders } from '@/lib/bing-ads';34const API_BASE = 'https://campaign.api.bingads.microsoft.com/api/advertiser/campaignmanagement/v13';56export async function GET(request: NextRequest) {7 const { searchParams } = new URL(request.url);8 const accountId = searchParams.get('accountId') || process.env.BING_ADS_ACCOUNT_ID;910 if (!accountId) {11 return NextResponse.json(12 { error: 'accountId query parameter or BING_ADS_ACCOUNT_ID environment variable required' },13 { status: 400 }14 );15 }1617 try {18 const accessToken = await getBingAdsAccessToken();19 const headers = getBingAdsHeaders(accessToken);2021 // Fetch campaigns for the account22 const response = await fetch(23 `${API_BASE}/Campaigns?AccountId=${accountId}&CampaignType=Search`,24 { headers }25 );2627 if (!response.ok) {28 const error = await response.text();29 console.error('Bing Ads API error:', error);30 return NextResponse.json(31 { error: 'Failed to fetch campaigns from Microsoft Advertising' },32 { status: response.status }33 );34 }3536 const data = await response.json();37 const campaigns = data.Campaigns || [];3839 // Map campaigns to a simpler format for the dashboard40 const formatted = campaigns.map((c: {41 Id: string;42 Name: string;43 Status: string;44 BudgetType: string;45 DailyBudget: number;46 TimeZone: string;47 }) => ({48 id: c.Id,49 name: c.Name,50 status: c.Status,51 budgetType: c.BudgetType,52 dailyBudget: c.DailyBudget,53 timeZone: c.TimeZone,54 }));5556 return NextResponse.json({ campaigns: formatted, total: formatted.length, accountId });57 } catch (error) {58 console.error('Campaigns fetch error:', error);59 return NextResponse.json(60 { error: error instanceof Error ? error.message : 'Unknown error' },61 { status: 500 }62 );63 }64}Pro tip: Add BING_ADS_ACCOUNT_ID and BING_ADS_CUSTOMER_ID as environment variables in Vercel. The Account ID is the numeric ID of the specific ad account; the Customer ID is the parent-level identifier. Both are visible in Microsoft Advertising URLs.
Expected result: The campaigns route returns a list of Microsoft Advertising campaigns with their name, status, and budget data. The V0-generated dashboard table displays real campaign data from your Microsoft Advertising account.
Add Environment Variables and Test the Integration
Add Environment Variables and Test the Integration
Configure all required Microsoft Advertising credentials in Vercel environment variables and test the end-to-end data flow from Microsoft Advertising to your dashboard. In Vercel Dashboard → Settings → Environment Variables, add these variables: BING_ADS_DEV_TOKEN (your developer token), BING_ADS_CLIENT_ID (Azure AD app client ID), BING_ADS_CLIENT_SECRET (Azure AD app client secret), BING_ADS_REFRESH_TOKEN (obtained from the OAuth flow), BING_ADS_CUSTOMER_ID (your Microsoft Advertising customer ID), and BING_ADS_ACCOUNT_ID (your default account ID for single-account dashboards). None of these variables should have the NEXT_PUBLIC_ prefix — they are all server-only credentials. The Microsoft Advertising API requires all of these for authentication and account identification. After adding variables, redeploy your Vercel project. Test by visiting your deployed dashboard URL and verifying that campaign data appears. Check Vercel Function Logs if data is not showing — authentication errors appear as 401 responses, invalid developer tokens as 403 responses, and incorrect account IDs as 404 responses. A critical testing note for V0 developers: the Microsoft Advertising sandbox environment at https://sandbox.bingads.microsoft.com uses different credentials from production. Sandbox developer tokens have a different format, and OAuth credentials require registration in the sandbox. For initial testing, use production credentials against a real account (even a small test account with minimal spend). Sandbox setup is complex and often skipped for dashboard-only integrations that only read data.
Pro tip: If your Microsoft Advertising account has multiple sub-accounts (common for agencies), add an account selector component to your dashboard. Fetch all accounts with the GetAccountsInfo API endpoint and allow users to switch between accounts without redeploying.
Expected result: All Microsoft Advertising credentials are configured in Vercel. The campaigns API route returns real data from your account. The dashboard displays campaign performance metrics. Vercel Function Logs show successful API calls without authentication errors.
Common use cases
Campaign Performance Dashboard
Build an advertising performance dashboard that displays Microsoft Advertising campaign metrics alongside other data sources. Show impressions, clicks, CTR, spend, conversions, and ROAS for each campaign with time-series charts and period-over-period comparisons. This gives marketers a single view of search advertising performance without logging into the Microsoft Advertising portal.
Create a campaign performance dashboard page that fetches data from /api/bing-ads/campaigns. Display metrics as a summary row: Total Spend, Total Impressions, Total Clicks, Average CTR, Total Conversions, and ROAS. Below, show a table of campaigns with columns for Campaign Name, Status badge (Active/Paused), Budget, Impressions, Clicks, CTR, CPC, Spend, Conversions, and ROAS. Add a date range selector (Last 7 days, Last 30 days, This month) and sorting on each column.
Copy this prompt to try it in V0
Keyword Performance Analyzer
Fetch keyword-level data from Microsoft Advertising to identify top-performing search terms, underperforming keywords, and Quality Score issues. Display keywords with their match type, bid, impressions, clicks, conversions, and Quality Score components (ad relevance, landing page relevance, expected CTR).
Build a keyword performance table that calls /api/bing-ads/keywords?campaignId={id}&adGroupId={id}. Show columns: Keyword, Match Type (Broad/Phrase/Exact badges), Status, Quality Score (1-10 with color coding: red < 5, yellow 5-7, green > 7), Impressions, Clicks, CTR, CPC, Conversions, Cost/Conversion. Add filters for match type and status. Sort by conversion volume by default.
Copy this prompt to try it in V0
Cross-Platform Advertising ROI Report
Combine Microsoft Advertising data with other advertising channels in a unified ROI dashboard. Fetch Bing Ads metrics alongside Google Ads or Facebook Ads data to show total advertising spend, blended ROAS, and channel attribution in one view. This allows budget allocation decisions across search advertising platforms.
Create a multi-channel advertising summary that calls /api/bing-ads/summary and /api/google-ads/summary in parallel. Show a comparison table with rows for Microsoft Advertising and Google Ads, columns for: Channel, Monthly Spend, Impressions, Clicks, Conversions, CPA, ROAS. Add bar charts comparing spend and ROAS side by side. Include a 'Last updated' timestamp showing when each channel's data was last fetched.
Copy this prompt to try it in V0
Troubleshooting
API returns 403 InvalidDeveloperToken — 'Developer token is not valid'
Cause: The BING_ADS_DEV_TOKEN value is incorrect, or you are using a sandbox developer token against the production environment (or vice versa). Developer tokens are environment-specific.
Solution: Go to Microsoft Advertising → Tools → API Center to verify your developer token. Ensure you are using the production developer token for production campaigns and the sandbox token for sandbox testing. Update BING_ADS_DEV_TOKEN in Vercel → Settings → Environment Variables and redeploy.
OAuth token refresh fails with 'invalid_grant' error
Cause: The refresh token has expired (Microsoft refresh tokens expire after 90 days of non-use), was revoked, or the Azure AD app credentials changed.
Solution: Re-authorize the application by running the OAuth authorization code flow again. Direct your browser to the authorization URL with your client ID and scope, complete the Microsoft login, and capture the new code from the redirect. Exchange the code for new access and refresh tokens, and update BING_ADS_REFRESH_TOKEN in Vercel.
Campaigns endpoint returns empty array even though campaigns exist in the account
Cause: The BING_ADS_ACCOUNT_ID or BING_ADS_CUSTOMER_ID values are incorrect, or the OAuth token does not have access to the specified account. The customer ID and account ID are different numbers and are often confused.
Solution: Log into Microsoft Advertising and check the URL: it shows ?cid={customerId}&aid={accountId}. The customer ID (cid) is the parent level; the account ID (aid) is the specific ad account. Verify both values and update them in Vercel environment variables. Make sure the OAuth token was generated by a user who has access to that specific account.
1// Log account info for debugging2console.log('Customer ID:', process.env.BING_ADS_CUSTOMER_ID);3console.log('Account ID:', process.env.BING_ADS_ACCOUNT_ID);4// These should match the cid= and aid= values in Microsoft Advertising URLsBest practices
- Cache Microsoft Advertising access tokens in a module-level variable with expiry tracking — tokens last 1 hour and refreshing on every request adds unnecessary latency to API calls.
- Store all Microsoft Advertising credentials (developer token, client ID, client secret, refresh token) as server-only Vercel environment variables without NEXT_PUBLIC_ prefix.
- Use Vercel Cron Jobs to pre-fetch and cache reporting data on a schedule rather than calling the Microsoft Advertising Reporting API on every dashboard page load — report generation is asynchronous and can take minutes.
- Implement refresh token rotation: when the Reporting API returns a new refresh token with the access token response, update BING_ADS_REFRESH_TOKEN in your database to avoid token expiry after 90 days.
- Separate sandbox and production credentials with Vercel environment scopes — use sandbox credentials in Preview deployments and production credentials in Production deployments.
- Handle the Microsoft Advertising API's rate limits gracefully: implement exponential backoff for 429 Too Many Requests responses and avoid making burst API calls during dashboard load.
- For agency dashboards managing multiple advertiser accounts, fetch account IDs dynamically with the Accounts API rather than hardcoding a single account ID.
Alternatives
Google Ads covers the much larger Google Search and Display network — integrate alongside Bing Ads for comprehensive search advertising coverage across both major platforms.
Twitter/X Ads is better for social advertising on X's platform rather than search intent advertising, making it complementary to Bing Ads rather than a direct alternative.
LinkedIn Ads targets professional audiences with B2B intent and is a common alternative to Microsoft Advertising for reaching business decision-makers.
Frequently asked questions
Do I need a Microsoft Advertising developer token to use the API?
Yes, a developer token is required for all Microsoft Advertising API requests — it is separate from OAuth credentials. To get one, log into ads.microsoft.com, go to Tools → API Center, and apply for a developer token. Standard tokens require an active Microsoft Advertising account with billing. The approval process is typically instant for accounts with existing spend history.
Can I use the Microsoft Advertising API with a new account that has no spend?
The Microsoft Advertising API requires an account with active campaigns and billing history for production developer token approval. New accounts or accounts with no spend may be limited to sandbox environment access. For testing purposes, set up at least one active campaign with a small budget to qualify for production API access.
How often does campaign performance data update in the Microsoft Advertising API?
Campaign Management API data (status, budget, settings) updates in near real-time. Performance metrics (impressions, clicks, conversions, spend) available through the Reporting API have a 3-hour delay for intraday data and are finalized for previous days by 10 AM UTC. For dashboard purposes, fetching data hourly or daily is the recommended approach rather than real-time polling.
Can V0 generate the complete Microsoft Advertising OAuth flow?
V0 can generate the code structure for OAuth initiation, callback handling, and token refresh, but it cannot complete the OAuth authorization or test with real credentials. You need to run the authorization flow manually once after deployment to get a real refresh token. For complex multi-user OAuth implementations, the RapidDev team can help architect the token storage and refresh flow.
What is the difference between the Bing Ads API and the Microsoft Advertising API?
They are the same API — Microsoft renamed Bing Ads to Microsoft Advertising in 2019. The API documentation and endpoints use 'Microsoft Advertising' and 'bingads' interchangeably. The API endpoint URLs still contain 'bingads.microsoft.com', and the npm package is called bingads. When searching for documentation, both terms return relevant results.
How do I access conversion and ROAS data from the API?
Conversion and ROAS data is available through the Microsoft Advertising Reporting API, not the Campaign Management API. Submit a PerformanceInsightsDetail or CampaignPerformanceReport request with ReturnOnAdSpend, Conversions, and Revenue columns specified. Note that conversions require Microsoft Advertising's UET (Universal Event Tracking) tag to be installed on your website and conversion goals configured in the platform.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation