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

How to Integrate Bolt.new with Eloqua

Oracle Eloqua integrates with Bolt.new through a Next.js API route using OAuth 2.0 or HTTP Basic authentication. Eloqua requires an active Oracle Eloqua license — there is no free tier. Use the Eloqua REST API for CRUD operations on contacts and campaigns, and the Bulk API for large-scale data import and export. OAuth requires a deployed redirect URI; Basic auth is simpler for server-to-server integrations.

What you'll learn

  • How to configure Eloqua API access using HTTP Basic auth or OAuth 2.0 from a registered Eloqua app
  • How to manage contacts and contact fields via Eloqua's REST API from a Next.js API route
  • How to use Eloqua's Bulk API for large-scale contact data import and export operations
  • How to build a campaign performance dashboard displaying Eloqua analytics in a React app
  • How to capture leads from Bolt forms and sync them to Eloqua with custom field mapping
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate18 min read35 minutesMarketingApril 2026RapidDev Engineering Team
TL;DR

Oracle Eloqua integrates with Bolt.new through a Next.js API route using OAuth 2.0 or HTTP Basic authentication. Eloqua requires an active Oracle Eloqua license — there is no free tier. Use the Eloqua REST API for CRUD operations on contacts and campaigns, and the Bulk API for large-scale data import and export. OAuth requires a deployed redirect URI; Basic auth is simpler for server-to-server integrations.

Oracle Eloqua Marketing Automation Integration for Bolt.new Apps

Oracle Eloqua is one of the leading enterprise marketing automation platforms, used by large organizations to orchestrate complex B2B marketing campaigns, manage large contact databases, and score leads based on behavioral data. Unlike SMB-focused tools like Mailchimp or Constant Contact, Eloqua is designed for marketing operations teams managing hundreds of thousands of contacts across multi-touch campaign sequences. The platform's API reflects this enterprise orientation — it is comprehensive, well-documented, and designed for deep system integration.

For Bolt.new developers, Eloqua integration is typically requested by enterprise clients who want custom internal tools: a campaign analytics dashboard surfacing Eloqua data in a branded interface, a lead capture form that feeds directly into Eloqua's contact database with specific field mapping, or a prospect scoring report that combines Eloqua's lead scores with other business data. Because Eloqua requires an active Oracle Eloqua license (starting at several thousand dollars annually — there is no free tier), this integration is appropriate for organizations that are already Eloqua customers.

The Eloqua API offers two main interfaces: the REST API for real-time CRUD operations on individual contacts, campaigns, lists, and assets, and the Bulk API for high-volume data operations that would be impractical through individual REST calls. A useful architectural pattern for Bolt.new is using the REST API for interactive features (form submissions, live contact lookups) and the Bulk API for batch reporting (exporting contact lists, downloading campaign analytics). Authentication supports both OAuth 2.0 and HTTP Basic auth — Basic auth is simpler to configure and is the recommended starting point for server-to-server integrations where users are not authorizing with their own Eloqua credentials.

Integration method

Bolt Chat + API Route

Eloqua integrates with Bolt.new through Next.js API routes that proxy requests to Eloqua's REST API. Authentication supports both OAuth 2.0 (requires deployed redirect URI — cannot be completed in Bolt's WebContainer preview) and HTTP Basic auth (username/password encoded as Base64). The REST API handles CRUD for contacts, campaigns, and assets; the Bulk API handles large-scale data imports and exports. All credentials must be kept server-side in .env.

Prerequisites

  • An active Oracle Eloqua license — Eloqua has no free tier; contact Oracle sales for pricing. Your organization must already be an Eloqua customer.
  • Eloqua API access enabled for your account — your Eloqua administrator may need to enable API access and create an API-specific user account
  • Your Eloqua base URL (typically https://secure.eloqua.com or a custom subdomain), company name (sitename), and API credentials (username and password)
  • A Bolt.new project using Next.js for server-side API routes that keep Eloqua credentials out of the browser
  • Your Eloqua instance's contact field internal names — these differ from the display names in the Eloqua UI and are required for correct field mapping in API payloads

Step-by-step guide

1

Configure Eloqua API credentials and base URL

Eloqua's API requires your organization's site name (company identifier), a username, a password, and the base URL for your Eloqua instance. These credentials combine to form either a Basic auth header or an OAuth flow. For server-to-server integrations — which is the typical Bolt.new pattern — HTTP Basic auth is the simplest and most direct approach. To find your Eloqua base URL, log into Eloqua and look at the URL in your browser. If it shows secure.eloqua.com, your base URL is https://secure.eloqua.com. Some enterprise installations use custom subdomains. Alternatively, you can use the Eloqua Login Service to discover your instance's URL programmatically: send a GET request to https://login.eloqua.com/id with Basic auth credentials (where the username is formatted as CompanyName\\Username). The response includes the base URLs for REST and Bulk APIs specific to your instance. Your Eloqua credentials follow the format CompanyName\\Username for the username component of Basic auth. This backslash-separated format is specific to Eloqua and different from standard OAuth. In Base64 encoding for the Authorization header, encode the full string CompanyName\\Username:Password as a single Base64 value. For API access, it is best practice to create a dedicated API user in Eloqua rather than using an admin account. Ask your Eloqua administrator to create a user with the 'API' or 'Advanced User' role, which provides the necessary permissions for contact and campaign management without full platform admin rights. Store this user's credentials in .env as ELOQUA_COMPANY, ELOQUA_USERNAME, and ELOQUA_PASSWORD. Never use NEXT_PUBLIC_ prefixes for any of these — they are server-side credentials that must never reach the browser. The Eloqua API has rate limits that vary by plan, typically allowing several hundred requests per minute. For production applications with heavy API usage, implement request caching at the API route level to reduce redundant calls — campaign data and contact lists change infrequently enough that a 5-minute cache is reasonable.

Bolt.new Prompt

Add Eloqua API credentials to .env. Create the file with: ELOQUA_BASE_URL=https://secure.eloqua.com, ELOQUA_COMPANY=YourCompanyName, ELOQUA_USERNAME=api_user@yourcompany.com, ELOQUA_PASSWORD=your_api_password. Add a comment explaining that the Basic auth username is formatted as CompanyName\\Username. Never use NEXT_PUBLIC_ for any Eloqua credentials.

Paste this in Bolt.new chat

.env
1# .env
2# Eloqua API credentials all server-side only, never NEXT_PUBLIC_
3# Base URL: check your Eloqua login URL or use the Login Service endpoint
4ELOQUA_BASE_URL=https://secure.eloqua.com
5
6# Eloqua company/site name (the identifier for your organization's Eloqua instance)
7ELOQUA_COMPANY=YourCompanyName
8
9# API user credentials (create a dedicated API user in Eloqua, not an admin account)
10ELOQUA_USERNAME=api.user@yourcompany.com
11ELOQUA_PASSWORD=your_secure_password_here
12
13# Contact list ID for lead capture forms (find in Eloqua Contacts Lists)
14ELOQUA_DEFAULT_LIST_ID=1

Pro tip: Use Eloqua's Login Service endpoint (GET https://login.eloqua.com/id with Basic auth) to discover your instance's correct API base URL. Large enterprise deployments often use custom subdomains or regional hosting that differs from the default secure.eloqua.com.

Expected result: Eloqua credentials are configured in .env with the correct base URL, company name, and API user credentials. The credentials are never prefixed with NEXT_PUBLIC_ and will not appear in the browser bundle.

2

Build the Eloqua API service and contact management route

Create the Eloqua API service module and a Next.js API route for contact management. The service module handles Basic auth header construction and common request patterns, while the API route provides an endpoint for the React frontend to call without directly accessing Eloqua. Eloqua's REST API versioning uses /api/REST/2.0/ as the base path for all current endpoints. Contact operations use the /data/contact endpoint: POST creates a new contact, GET retrieves a contact by ID, PUT updates an existing contact (using the Eloqua contact ID), and DELETE removes a contact. To find or upsert a contact by email address, use GET /data/contacts?search=emailAddress=user@example.com to first check if the contact exists before deciding to create or update. Eloqua contact fields have internal names that differ from their display names in the UI. Standard fields include: firstName, lastName, emailAddress (not 'email'), company (not 'companyName'), title (job title), businessPhone, and address1 through address3. Custom fields created in Eloqua have generated internal names like 'M_Company_Revenue_Range' or names you defined when creating the field. Check your Eloqua administrator or use the API's /assets/contact/fields endpoint to retrieve the internal names for all fields. The Bolt prompt below generates the service module and API route. After generation, test the contact creation endpoint by submitting the lead form in Bolt's preview — outbound HTTP calls to Eloqua's REST API work in the WebContainer since they use standard HTTPS. The 401 error is the most common issue: verify the Base64 encoding of CompanyName\\Username:Password is correct, as the backslash in the company-username separator must be included literally before encoding.

Bolt.new Prompt

Create an Eloqua REST API integration for this Next.js app. (1) Create lib/eloqua.ts with an eloquaFetch(endpoint, options) utility that constructs Basic auth from ELOQUA_COMPANY, ELOQUA_USERNAME, ELOQUA_PASSWORD environment variables (Base64 of 'Company\\Username:Password'). Export: createContact(fields), updateContact(id, fields), findContactByEmail(email), and addToList(contactId, listId). Use ELOQUA_BASE_URL from process.env for the base URL. (2) Create app/api/eloqua/contacts/route.ts with POST (create/upsert contact by email) and GET (search contacts). The POST handler should check if the email exists first, then create or update accordingly. Include TypeScript interfaces for Eloqua contact fields.

Paste this in Bolt.new chat

lib/eloqua.ts
1// lib/eloqua.ts
2function getEloquaAuth(): string {
3 const company = process.env.ELOQUA_COMPANY;
4 const username = process.env.ELOQUA_USERNAME;
5 const password = process.env.ELOQUA_PASSWORD;
6 if (!company || !username || !password) {
7 throw new Error('Eloqua credentials not configured');
8 }
9 // Eloqua Basic auth format: Base64 of 'CompanyName\\Username:Password'
10 return Buffer.from(`${company}\\${username}:${password}`).toString('base64');
11}
12
13const BASE = () => {
14 const url = process.env.ELOQUA_BASE_URL;
15 if (!url) throw new Error('ELOQUA_BASE_URL not configured');
16 return `${url}/api/REST/2.0`;
17};
18
19export interface EloquaContactFields {
20 firstName?: string;
21 lastName?: string;
22 emailAddress?: string;
23 company?: string;
24 title?: string;
25 businessPhone?: string;
26 [key: string]: string | undefined;
27}
28
29async function eloquaFetch<T>(path: string, options: RequestInit = {}): Promise<T> {
30 const res = await fetch(`${BASE()}${path}`, {
31 ...options,
32 headers: {
33 Authorization: `Basic ${getEloquaAuth()}`,
34 'Content-Type': 'application/json',
35 ...options.headers,
36 },
37 });
38
39 if (!res.ok) {
40 const body = await res.text();
41 throw Object.assign(new Error(`Eloqua API error: ${res.status}`), { status: res.status, body });
42 }
43
44 return res.json();
45}
46
47export async function findContactByEmail(email: string) {
48 const encoded = encodeURIComponent(`emailAddress='${email}'`);
49 return eloquaFetch<{ elements: Array<{ id: string; emailAddress: string }> }>(
50 `/data/contacts?search=${encoded}&depth=minimal`
51 );
52}
53
54export async function createContact(fields: EloquaContactFields) {
55 return eloquaFetch('/data/contact', {
56 method: 'POST',
57 body: JSON.stringify(fields),
58 });
59}
60
61export async function updateContact(contactId: string, fields: EloquaContactFields) {
62 return eloquaFetch(`/data/contact/${contactId}`, {
63 method: 'PUT',
64 body: JSON.stringify({ ...fields, id: contactId }),
65 });
66}
67
68export async function addToList(contactId: string, listId: string) {
69 return eloquaFetch(`/data/contact/list/${listId}`, {
70 method: 'POST',
71 body: JSON.stringify({ type: 'Contact', id: contactId }),
72 });
73}

Pro tip: Eloqua's search syntax for the REST API uses single quotes around string values: emailAddress='user@example.com'. Using double quotes or omitting quotes causes a 400 error. Special characters in search values should be URL-encoded.

Expected result: lib/eloqua.ts provides authenticated access to Eloqua's REST API using Basic auth. The /api/eloqua/contacts route can create new contacts and upsert existing ones by email address. Contact creation from the Bolt preview creates real contacts in your Eloqua instance.

3

Implement the Bulk API for large-scale data operations

Eloqua's Bulk API is a separate, asynchronous API designed for data operations involving thousands or millions of records — volumes where individual REST API calls would be impractical due to rate limits and response times. The Bulk API uses a three-step pattern: define an export or import job, start a sync to execute the job, and retrieve the results after the sync completes. For a Bolt.new dashboard, the most useful Bulk API operation is exporting contact data for reporting. The export workflow: POST a definition to /api/bulk/2.0/contacts/exports describing which fields to include and any filters (for example, contacts created in the last 30 days). The response includes an export URI. POST to /api/bulk/2.0/syncs to start the export sync, referencing the export URI. Poll GET /api/bulk/2.0/syncs/{syncId}/status until the status changes from 'pending' or 'active' to 'success.' Retrieve the exported data from GET /api/bulk/2.0/contacts/exports/{exportId}/data, which returns paginated JSON records. The Bulk API uses the same Basic auth as the REST API but with a different base path: /api/bulk/2.0/ instead of /api/REST/2.0/. Note that the Bulk API has its own set of field names for exports — they follow an extended naming convention and are retrieved from /api/bulk/2.0/contacts/fields. For large exports, implement server-side polling rather than client-side polling — have the API route poll the sync status with a short delay between checks, then return the complete data when ready. Set a maximum polling timeout (for example, 60 seconds) to prevent hanging requests. Very large exports should use a background job pattern: start the export, return a job ID to the client, and let the client poll a status endpoint.

Bolt.new Prompt

Create an Eloqua Bulk API export tool. (1) Add bulkExportContacts(fields, filter) to lib/eloqua.ts that uses ELOQUA_BASE_URL/api/bulk/2.0/: POST an export definition, POST to syncs to start it, poll sync status every 3 seconds until 'success' or timeout after 60 seconds, then GET the data. (2) Create app/api/eloqua/bulk/contacts/route.ts as a GET handler that calls bulkExportContacts with fields ['firstName', 'lastName', 'emailAddress', 'company', 'createdAt', 'modifiedAt'] and returns the records. (3) Build a React component with an 'Export Contacts' button that fetches /api/eloqua/bulk/contacts and displays the results in a table with a CSV download option. Show a loading spinner while the bulk export is processing.

Paste this in Bolt.new chat

lib/eloqua-bulk.ts
1// Bulk API export helper — add to lib/eloqua.ts
2const BULK_BASE = () => {
3 const url = process.env.ELOQUA_BASE_URL;
4 if (!url) throw new Error('ELOQUA_BASE_URL not configured');
5 return `${url}/api/bulk/2.0`;
6};
7
8async function bulkFetch<T>(path: string, options: RequestInit = {}): Promise<T> {
9 const res = await fetch(`${BULK_BASE()}${path}`, {
10 ...options,
11 headers: {
12 Authorization: `Basic ${getEloquaAuth()}`,
13 'Content-Type': 'application/json',
14 ...options.headers,
15 },
16 });
17 if (!res.ok) throw new Error(`Bulk API error: ${res.status}`);
18 return res.json();
19}
20
21export async function bulkExportContacts(fields: string[]) {
22 // Step 1: Create export definition
23 const def = await bulkFetch<{ uri: string }>('/contacts/exports', {
24 method: 'POST',
25 body: JSON.stringify({
26 name: 'BoltExport_' + Date.now(),
27 fields: Object.fromEntries(fields.map((f) => [f, `{{Contact.Field(C_${f})}}`])),
28 }),
29 });
30
31 // Step 2: Start sync
32 const sync = await bulkFetch<{ uri: string; syncedInstanceUri: string }>('/syncs', {
33 method: 'POST',
34 body: JSON.stringify({ syncedInstanceUri: def.uri }),
35 });
36
37 // Step 3: Poll for completion
38 const syncId = sync.uri.split('/').pop();
39 let attempts = 0;
40 while (attempts < 20) {
41 await new Promise((r) => setTimeout(r, 3000));
42 const status = await bulkFetch<{ status: string }>(`/syncs/${syncId}`);
43 if (status.status === 'success') break;
44 if (status.status === 'error') throw new Error('Bulk export sync failed');
45 attempts++;
46 }
47
48 // Step 4: Retrieve data
49 const exportId = def.uri.split('/').pop();
50 return bulkFetch<{ items: Record<string, string>[] }>(
51 `/contacts/exports/${exportId}/data?limit=1000`
52 );
53}

Pro tip: Eloqua Bulk API field names in export definitions follow the format {{Contact.Field(C_FieldName)}} for custom fields and standard names like {{Contact.FirstName}} for built-in fields. Use GET /api/bulk/2.0/contacts/fields to retrieve the exact field name format for your Eloqua instance.

Expected result: The bulk export tool creates an export definition, starts a sync job, polls until completion, and returns contact records as JSON. Large exports of thousands of contacts complete within the 60-second polling window for typical enterprise Eloqua instances.

4

Handle OAuth 2.0 for multi-user Eloqua access

If your Bolt.new app needs to access multiple Eloqua customer accounts (not just your own), you need OAuth 2.0 authentication rather than Basic auth. OAuth 2.0 is also required by some Eloqua enterprise configurations that disable Basic auth for security reasons. Eloqua's OAuth 2.0 implementation follows the standard authorization code flow. Register an application in Eloqua's App Cloud Developer portal (appcloud.eloqua.com) to get a client ID and client secret. The authorization URL is https://login.eloqua.com/auth/oauth2/authorize. The token endpoint is https://login.eloqua.com/auth/oauth2/token. Required scopes include 'full' for complete API access or more granular scopes for specific operations. The critical constraint for OAuth 2.0 with Eloqua in Bolt.new is identical to other OAuth providers: the redirect URI must be a stable, publicly accessible URL — meaning your deployed Netlify or Bolt Cloud site, not the Bolt WebContainer preview. The preview uses a dynamic StackBlitz URL that changes between sessions and cannot be registered in the App Cloud Developer portal. Set up the OAuth flow on your deployed site: create an authorization URL endpoint that redirects users to Eloqua's authorize page, handle the callback in a Next.js API route that exchanges the code for tokens, and store the access token securely. Eloqua OAuth access tokens expire after one hour, so implement token refresh using the refresh token returned alongside the access token.

Bolt.new Prompt

Create Eloqua OAuth 2.0 routes for this Next.js app. (1) Create app/api/auth/eloqua/route.ts that redirects to https://login.eloqua.com/auth/oauth2/authorize with ELOQUA_CLIENT_ID, redirect_uri of {NEXT_PUBLIC_APP_URL}/api/auth/callback/eloqua, and scope='full'. (2) Create app/api/auth/callback/eloqua/route.ts that exchanges the authorization code by POSTing to https://login.eloqua.com/auth/oauth2/token with client_id, client_secret, code, and redirect_uri. Log the access token for manual storage in .env. (3) Create app/api/auth/eloqua/refresh/route.ts for refreshing expired tokens using the refresh_token. Add ELOQUA_CLIENT_ID and ELOQUA_CLIENT_SECRET to .env.

Paste this in Bolt.new chat

app/api/auth/callback/eloqua/route.ts
1// app/api/auth/callback/eloqua/route.ts
2import { NextResponse } from 'next/server';
3
4export async function GET(request: Request) {
5 const { searchParams } = new URL(request.url);
6 const code = searchParams.get('code');
7 if (!code) {
8 return NextResponse.json({ error: 'Missing authorization code' }, { status: 400 });
9 }
10
11 const clientId = process.env.ELOQUA_CLIENT_ID!;
12 const clientSecret = process.env.ELOQUA_CLIENT_SECRET!;
13 const redirectUri = `${process.env.NEXT_PUBLIC_APP_URL}/api/auth/callback/eloqua`;
14
15 const tokenRes = await fetch('https://login.eloqua.com/auth/oauth2/token', {
16 method: 'POST',
17 headers: {
18 Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,
19 'Content-Type': 'application/x-www-form-urlencoded',
20 },
21 body: new URLSearchParams({
22 grant_type: 'authorization_code',
23 code,
24 redirect_uri: redirectUri,
25 }),
26 });
27
28 if (!tokenRes.ok) {
29 return NextResponse.json({ error: 'Token exchange failed' }, { status: 400 });
30 }
31
32 const tokens = await tokenRes.json();
33 // Store access_token and refresh_token securely
34 // For single-user setup: copy access_token to ELOQUA_ACCESS_TOKEN in .env
35 console.log('Eloqua OAuth tokens received:', {
36 access_token: tokens.access_token?.substring(0, 10) + '...', // truncated for security
37 expires_in: tokens.expires_in,
38 has_refresh_token: !!tokens.refresh_token,
39 });
40
41 return NextResponse.redirect(new URL('/dashboard', request.url));
42}

Pro tip: Eloqua OAuth tokens expire after 3600 seconds (one hour). For production apps, store both access_token and refresh_token in your database and implement automatic refresh before the token expires. Use the expires_in value from the token response to calculate when to refresh.

Expected result: The OAuth callback route exchanges the Eloqua authorization code for access and refresh tokens. The flow works on the deployed site. Token exchange cannot be completed in the Bolt WebContainer preview because the preview URL is not a stable redirect URI.

Common use cases

Lead Capture Form with Eloqua Contact Creation

A prospect intake form on a Bolt.new marketing site that creates contacts directly in Eloqua when submitted. The form captures standard B2B lead fields (company name, job title, email, phone) and maps them to the correct Eloqua contact field names. New contacts are automatically added to a specified contact list for immediate follow-up sequencing.

Bolt.new Prompt

Create a lead capture form that creates contacts in Eloqua. Build a form component with fields: firstName, lastName, emailAddress, company, title, and phone. On submit, POST to /api/eloqua/contacts which calls https://{ELOQUA_BASE_URL}/api/REST/2.0/data/contact using Basic auth (base64 of ELOQUA_COMPANY\\ELOQUA_USERNAME:ELOQUA_PASSWORD from process.env). Map form fields to Eloqua field names: firstName, lastName, emailAddress, company, title, businessPhone. After creating the contact, add them to the contact list with ID ELOQUA_LIST_ID. Show a success state with the created contact ID. Use TypeScript and Tailwind CSS.

Copy this prompt to try it in Bolt.new

Campaign Performance Analytics Dashboard

An internal marketing dashboard showing Eloqua campaign performance across email sends, open rates, click rates, and conversion data. Marketing team members and executives can view campaign results in a custom branded interface without needing individual Eloqua logins, and the dashboard can incorporate non-Eloqua data (Salesforce revenue, web analytics) that is not available in Eloqua's native reporting.

Bolt.new Prompt

Build an Eloqua campaign analytics dashboard. Create /api/eloqua/campaigns that GETs https://{ELOQUA_BASE_URL}/api/REST/2.0/assets/emails with Basic auth. Return campaign name, subject, sentDate, and stats. Create /api/eloqua/campaigns/[id]/stats that fetches https://{ELOQUA_BASE_URL}/api/REST/2.0/data/activities/campaign/{id} for detailed metrics. In React, display a campaign list table with name, date sent, and open/click counts. Add a Recharts BarChart showing email performance trends over the last 10 campaigns. Clicking a row expands to show detailed stats. All API calls use ELOQUA_BASE_URL, ELOQUA_COMPANY, ELOQUA_USERNAME, ELOQUA_PASSWORD from process.env.

Copy this prompt to try it in Bolt.new

Bulk Contact Export for Reporting

A data export tool that uses Eloqua's Bulk API to extract contact data for a specified contact segment or date range. The exported data is returned as JSON for display in a React table or download as CSV. This is more efficient than paginating through individual REST API calls for large contact databases.

Bolt.new Prompt

Create a Bolt tool that uses Eloqua's Bulk API to export contacts. Build /api/eloqua/bulk/export that: (1) POSTs a definition to https://{ELOQUA_BASE_URL}/api/bulk/2.0/contacts/exports to define the fields to export (firstName, lastName, emailAddress, company, createdAt, modifiedAt), (2) POSTs to the sync endpoint to start the export job, (3) Polls the sync status until complete, (4) GETs the data from the results endpoint and returns it as JSON. Use ELOQUA_BASE_URL and Basic auth from process.env. In React, add a button that triggers the export and displays the results in a sortable table with a CSV download button.

Copy this prompt to try it in Bolt.new

Troubleshooting

Eloqua API returns 401 Unauthorized on all requests using Basic auth

Cause: The Basic auth header is not correctly formatted. Eloqua requires Base64 encoding of the string 'CompanyName\\Username:Password' — note the backslash between company name and username, which is unusual compared to standard Basic auth.

Solution: Verify the auth string format before encoding. In Node.js, use Buffer.from(`${company}\\${username}:${password}`).toString('base64'). The double backslash in the template literal produces a single literal backslash in the string. Also confirm the company name matches exactly as shown in your Eloqua instance settings (it is case-sensitive).

typescript
1// Correct Eloqua Basic auth construction
2const company = process.env.ELOQUA_COMPANY; // e.g., 'AcmeCorp'
3const username = process.env.ELOQUA_USERNAME; // e.g., 'api.user'
4const password = process.env.ELOQUA_PASSWORD;
5
6// The '\\' produces a single backslash — Eloqua requires: AcmeCorp\\api.user:password
7const authString = `${company}\\${username}:${password}`;
8const encoded = Buffer.from(authString).toString('base64');
9const header = `Basic ${encoded}`;

Eloqua REST API returns 404 Not Found for valid-looking endpoint URLs

Cause: Your Eloqua instance may be hosted at a different base URL than secure.eloqua.com. Enterprise deployments often use custom subdomains or regional hosting. Using the wrong base URL causes all endpoints to return 404.

Solution: Use the Eloqua Login Service to discover your instance's correct base URL. Send a GET request to https://login.eloqua.com/id with your Basic auth header. The response contains 'urls.base' with the correct REST API base URL for your instance. Update ELOQUA_BASE_URL in .env with this value.

typescript
1// Discover correct Eloqua base URL using Login Service
2async function discoverEloquaBaseUrl(company: string, username: string, password: string) {
3 const auth = Buffer.from(`${company}\\${username}:${password}`).toString('base64');
4 const res = await fetch('https://login.eloqua.com/id', {
5 headers: { Authorization: `Basic ${auth}` },
6 });
7 const data = await res.json();
8 console.log('Eloqua REST base URL:', data.urls.base);
9 // Set ELOQUA_BASE_URL to this value in .env
10 return data.urls.base as string;
11}

Eloqua Bulk API sync stays in 'pending' status indefinitely

Cause: Large exports take longer to process in Eloqua's backend. The sync may take several minutes for large contact databases. Also, Eloqua has a limit on concurrent bulk syncs — if another sync is running, new syncs queue behind it.

Solution: Increase the polling timeout from 60 seconds to 300 seconds for large datasets. Check the sync status endpoint response for an 'active' vs 'pending' status — 'active' means it is running, 'pending' means it is queued. Reduce the export scope using filters (for example, export only contacts modified in the last 7 days) to decrease processing time.

Best practices

  • Use a dedicated Eloqua API user account with the minimum required role (not a system administrator account) to limit the blast radius if credentials are ever compromised
  • Store all Eloqua credentials (ELOQUA_COMPANY, ELOQUA_USERNAME, ELOQUA_PASSWORD) in server-side .env with no NEXT_PUBLIC_ prefix — they give full access to your organization's marketing database
  • Complete OAuth 2.0 flows on your deployed site, not in Bolt's WebContainer preview — the preview does not have a stable URL for Eloqua's redirect URI registration
  • Use the Eloqua Login Service (login.eloqua.com/id) to discover your instance's correct API base URL rather than hardcoding secure.eloqua.com — enterprise installations commonly use custom subdomains
  • Prefer the Bulk API for any operation involving more than 100 contacts — individual REST API calls for large datasets hit rate limits and are significantly slower than a single bulk export
  • Cache campaign analytics responses in your API routes for at least 5 minutes — Eloqua campaign data is not real-time and does not change faster than human review cycles
  • Implement access token refresh logic for OAuth integrations — Eloqua tokens expire after one hour and stale tokens will silently break your integration until refreshed

Alternatives

Frequently asked questions

Does Eloqua work with Bolt.new?

Yes. Eloqua's REST API and Bulk API use HTTPS requests that work in Bolt's WebContainer via Next.js API routes. The main constraints are that Eloqua requires an active paid license (no free tier), and OAuth 2.0 flows require a deployed site for the redirect URI. HTTP Basic auth works directly and is the simplest integration pattern for server-to-server connections.

How do I connect Bolt.new to Eloqua?

Store your Eloqua credentials (ELOQUA_COMPANY, ELOQUA_USERNAME, ELOQUA_PASSWORD, ELOQUA_BASE_URL) in .env. Create a Next.js API route that constructs Basic auth by Base64-encoding 'CompanyName\\Username:Password' and adds it as an Authorization header to requests to your Eloqua REST API base URL. All contact, campaign, and list operations call this server-side route — never Eloqua's API directly from the frontend.

Can I use Eloqua without a paid Oracle license?

No. Eloqua is an enterprise platform with no free tier or trial — you need an active Oracle Eloqua subscription to access the API. Pricing starts at several thousand dollars per year. If you need marketing automation without an enterprise budget, consider HubSpot (free CRM with API access) or Mailchimp (free tier up to 500 contacts) as alternatives.

What is the difference between Eloqua's REST API and Bulk API?

Eloqua's REST API is for real-time CRUD operations on individual records — creating a single contact, retrieving a specific campaign, updating a contact field. The Bulk API is for asynchronous large-scale data operations: exporting thousands of contacts, importing large prospect lists, or running data quality updates across segments. For interactive Bolt.new features, use the REST API. For reporting, data migration, or batch processing, use the Bulk API.

Why does the Eloqua OAuth callback not work in Bolt's preview?

Bolt's WebContainer runs in a browser sandbox with dynamic, session-specific URLs (generated by StackBlitz) that cannot be registered as stable OAuth redirect URIs in Eloqua's developer portal. Deploy your app to Netlify or Bolt Cloud first, register the deployed URL as the redirect URI, and complete OAuth authorization on the deployed site. Once you have an access token, you can continue development in the preview.

How do I handle Eloqua API rate limits in a Bolt.new dashboard?

Eloqua rate limits vary by subscription tier but typically allow several hundred REST API requests per minute. For dashboard applications, cache API responses in your Next.js API routes using in-memory caching or a revalidation strategy — campaign performance data changes at human speeds, so a 5-minute cache significantly reduces API calls. For bulk data needs, use the Bulk API instead of paginating through REST endpoints, which is both faster and more rate-limit-friendly.

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.