To integrate Insightly with V0 by Vercel, create a Next.js API route at app/api/insightly/route.ts that calls the Insightly REST API using a Base64-encoded API key in the Authorization header. V0 generates custom CRM dashboards showing contacts, opportunities, and projects fetched from your API route. Insightly's SMB-friendly CRM is ideal for small businesses wanting a custom branded sales dashboard.
Building Custom Insightly CRM Dashboards with V0
Insightly is popular with small and mid-size businesses because it combines CRM functionality with lightweight project management — contacts become clients, opportunities become projects, all within one platform. The built-in Insightly interface works well for data entry and day-to-day work, but many businesses want custom dashboards that surface the metrics that matter most to them: pipeline value by stage, top opportunities by close date, or contact activity summaries.
The integration creates a Next.js API route that authenticates with Insightly using your API key encoded in Basic Auth format. V0 generates the front-end components — pipeline kanban boards, contact directories, opportunity tables, or executive summaries — that fetch data from the secure API route. Your Insightly API key never reaches the browser, which is important because it grants full read and write access to your CRM data.
Insightly's API uses a slightly unusual authentication pattern: rather than a Bearer token, it uses HTTP Basic Auth where the API key is the username and the password is empty. The key must be Base64 encoded before adding to the Authorization header. This is a one-time setup in your API route and does not require any additional npm packages.
Integration method
V0 generates custom CRM dashboard components that display Insightly contacts, opportunities, and pipeline data. A Next.js API route on Vercel proxies requests to the Insightly REST API, keeping your API key server-side. Components call /api/insightly/contacts rather than Insightly directly, preventing credential exposure and enabling CORS-free data access.
Prerequisites
- A V0 account with a Next.js project at v0.dev
- An Insightly account at insightly.com with contacts and opportunities
- An Insightly API key from your Insightly user settings
- Basic understanding of Base64 encoding (your API route handles this automatically)
- A Vercel account with your V0 project connected via GitHub
Step-by-step guide
Find Your Insightly API Key
Find Your Insightly API Key
Insightly's API key is found in your user profile settings. It is a unique key tied to your user account and grants the same access permissions as your Insightly user role. Log into your Insightly account at app.insightly.com. Click on your profile avatar or name in the top-right corner of the interface. Select 'User Settings' from the dropdown menu. In your User Settings page, scroll down to find the 'API Key' section. Your API key is displayed there as a long alphanumeric string. Click the copy icon or select the key text and copy it. Insightly uses HTTP Basic Authentication with the API key as the username and an empty string as the password. Before using the key in your API route, you need to Base64-encode the string 'YOUR_API_KEY:' (with the colon but without quotes, and with an empty string after the colon). The resulting Base64 string is what goes in the Authorization header as 'Basic {base64string}'. You can test your credentials quickly using curl: curl -H 'Authorization: Basic {base64}' https://api.insightly.com/v3.1/contacts. If it returns a JSON array, your authentication is working. Insightly's API base URL depends on your account's data region. North American accounts use https://api.insightly.com. European accounts may use a different subdomain. Check your account region in Insightly's documentation or contact Insightly support if standard API calls return 404. Note that Insightly API access is included on all paid plans. Free plan accounts may have limited or no API access.
Pro tip: To Base64-encode your Insightly API key in Node.js (which your API route uses), run: Buffer.from('YOUR_API_KEY:').toString('base64'). Store the raw API key in the environment variable and do the encoding in your route code.
Expected result: You have your Insightly API key (a long alphanumeric string). You understand the Basic Auth pattern and are ready to add the key to Vercel environment variables.
Add Insightly API Key to Vercel
Add Insightly API Key to Vercel
Store your Insightly API key in Vercel's environment variables. Your API route will Base64-encode it at runtime, so you store the raw key value rather than the encoded string. Open your Vercel Dashboard, navigate to your project, click 'Settings', and select 'Environment Variables'. Add: INSIGHTLY_API_KEY: Your raw Insightly API key. This is a secret — set it for Production, Preview, and Development environments. Do not add a NEXT_PUBLIC_ prefix. Save the variable and trigger a redeployment. For local development, add the same variable to your .env.local file. Optionally, if your account uses the European data region, also add INSIGHTLY_API_BASE_URL=https://api.na1.insightly.com or the appropriate regional URL for your account.
1# .env.local — local development only, excluded from Git2INSIGHTLY_API_KEY=your_insightly_api_key_here3# Optional: if your account uses EU region4# INSIGHTLY_API_BASE_URL=https://api.eu1.insightly.comPro tip: Insightly API keys are permanent and do not expire. If you suspect your key has been compromised, generate a new one from User Settings → API Key section and update your Vercel environment variable immediately.
Expected result: Vercel Dashboard shows INSIGHTLY_API_KEY saved as an environment variable across all deployment environments.
Create the Insightly API Routes
Create the Insightly API Routes
Create Next.js API routes for contacts and opportunities. The key detail for Insightly is the Basic Auth header format — your route must Base64-encode the API key with a trailing colon before sending it. Create app/api/insightly/contacts/route.ts. The contacts endpoint is GET https://api.insightly.com/v3.1/contacts. It supports query parameters including top (page size, max 500), skip (for pagination), and $filter (OData filter expression) and $orderby for sorting. Insightly returns contacts with nested arrays for email addresses and phone numbers (EMAIL_ADDRESSES array containing objects with EMAIL_ADDRESS and EMAIL_TYPE, and PHONE_NUMBERS array containing objects with PHONE_NUMBER and PHONE_TYPE). Your route should flatten these for easier component consumption. The opportunities endpoint is GET https://api.insightly.com/v3.1/opportunities with similar pagination support. Filter by STATE='open' using OData syntax: $filter=STATE eq 'open'. Each opportunity includes OPPORTUNITY_VALUE, PROBABILITY, CLOSE_DATE, STAGE_ORDER_NUMBER, and PIPELINE_ID along with basic metadata. Insightly also has a pipeline stages endpoint (GET /v3.1/OpportunityCategories) and a pipelines endpoint (GET /v3.1/Pipelines) to get the stages within each pipeline. Fetch these once to map stage order numbers to human-readable stage names.
Create a Next.js API route at app/api/insightly/contacts/route.ts. Use INSIGHTLY_API_KEY from environment variables. Create the Basic Auth header by Base64-encoding '{key}:' (key + colon). Fetch from https://api.insightly.com/v3.1/contacts with top=200. Return contacts with CONTACT_ID, FIRST_NAME, LAST_NAME, ORGANISATION_NAME, TITLE, primary email from EMAIL_ADDRESSES array, primary phone from PHONE_NUMBERS array, and DATE_UPDATED_UTC. Sort by LAST_NAME. Handle errors.
Paste this in V0 chat
1import { NextRequest, NextResponse } from 'next/server';23interface InsightlyEmailAddress {4 EMAIL_ADDRESS: string;5 EMAIL_TYPE: string;6}78interface InsightlyPhoneNumber {9 PHONE_NUMBER: string;10 PHONE_TYPE: string;11}1213interface InsightlyContact {14 CONTACT_ID: number;15 FIRST_NAME: string;16 LAST_NAME: string;17 ORGANISATION_NAME: string | null;18 TITLE: string | null;19 EMAIL_ADDRESSES: InsightlyEmailAddress[];20 PHONE_NUMBERS: InsightlyPhoneNumber[];21 DATE_UPDATED_UTC: string;22}2324function getInsightlyAuthHeader(apiKey: string): string {25 // Insightly Basic Auth: Base64-encode 'apiKey:' (key + colon, empty password)26 return 'Basic ' + Buffer.from(`${apiKey}:`).toString('base64');27}2829export async function GET(request: NextRequest) {30 const apiKey = process.env.INSIGHTLY_API_KEY;31 const apiBase =32 process.env.INSIGHTLY_API_BASE_URL || 'https://api.insightly.com';3334 if (!apiKey) {35 return NextResponse.json(36 { error: 'Insightly configuration missing' },37 { status: 500 }38 );39 }4041 const { searchParams } = new URL(request.url);42 const search = searchParams.get('search') || '';4344 const contactsUrl = new URL(`${apiBase}/v3.1/contacts`);45 contactsUrl.searchParams.set('top', '200');46 contactsUrl.searchParams.set('$orderby', 'LAST_NAME asc');47 if (search) {48 contactsUrl.searchParams.set(49 '$filter',50 `LAST_NAME eq '${search}' or FIRST_NAME eq '${search}'`51 );52 }5354 try {55 const response = await fetch(contactsUrl.toString(), {56 headers: {57 Authorization: getInsightlyAuthHeader(apiKey),58 'Content-Type': 'application/json',59 },60 next: { revalidate: 120 },61 });6263 if (!response.ok) {64 const error = await response.text();65 console.error('Insightly API error:', error);66 return NextResponse.json(67 { error: `Insightly returned ${response.status}` },68 { status: response.status }69 );70 }7172 const contacts: InsightlyContact[] = await response.json();7374 const transformed = contacts.map((c) => ({75 id: c.CONTACT_ID,76 firstName: c.FIRST_NAME || '',77 lastName: c.LAST_NAME || '',78 fullName: `${c.FIRST_NAME || ''} ${c.LAST_NAME || ''}`.trim(),79 company: c.ORGANISATION_NAME || '',80 title: c.TITLE || '',81 email:82 c.EMAIL_ADDRESSES?.find((e) => e.EMAIL_TYPE === 'WORK')?.EMAIL_ADDRESS ||83 c.EMAIL_ADDRESSES?.[0]?.EMAIL_ADDRESS ||84 '',85 phone:86 c.PHONE_NUMBERS?.find((p) => p.PHONE_TYPE === 'WORK')?.PHONE_NUMBER ||87 c.PHONE_NUMBERS?.[0]?.PHONE_NUMBER ||88 '',89 updatedAt: c.DATE_UPDATED_UTC,90 }));9192 return NextResponse.json({ contacts: transformed, total: transformed.length });93 } catch (error) {94 console.error('Insightly contacts fetch failed:', error);95 return NextResponse.json(96 { error: 'Failed to fetch contacts' },97 { status: 500 }98 );99 }100}Pro tip: The Insightly Basic Auth requires the format 'apiKey:' (with trailing colon and empty password). Forgetting the colon will cause authentication failures even with a valid API key.
Expected result: Calling /api/insightly/contacts returns a JSON array of contacts with flattened email and phone fields, sorted alphabetically by last name.
Generate CRM Dashboard Components with V0
Generate CRM Dashboard Components with V0
With the Insightly API routes returning data, prompt V0 to generate the CRM dashboard components. Sales dashboards need clear visual hierarchy — pipeline value should be prominent, stage groupings should be obvious, and overdue or high-priority items should stand out. First, review the JSON output of your /api/insightly/contacts and /api/insightly/opportunities routes to confirm the field names and data structure. Reference these exact field names in your V0 prompts. For a pipeline dashboard, describe the column layout (one column per pipeline stage), the card content (opportunity name, value, expected close date, owner), and the color coding scheme (green for on-track, yellow for closing soon, red for overdue). Tell V0 the stage names used in your Insightly pipeline. For a contact directory, describe the table columns, sort behavior, and search functionality. Ask V0 to add pagination if your contact list exceeds 50-100 entries, since rendering hundreds of rows at once slows the browser. Ask V0 to add summary metric cards at the top of the dashboard: total pipeline value, number of open opportunities, opportunities closing this month, and win rate. These high-level numbers are usually what executives and managers look at first.
Create a CRM dashboard with two tabs: 'Pipeline' and 'Contacts'. Pipeline tab: fetch from /api/insightly/opportunities. Show summary cards: total pipeline value (sum of all OPPORTUNITY_VALUE), open count, and opportunities closing within 30 days. Below, show a table with columns: Opportunity Name, Value ($XX,XXX), Owner, Stage, Close Date, Status badge (green 'On Track' if close date > today, red 'Overdue' if past). Contacts tab: fetch from /api/insightly/contacts. Show a searchable table with Name, Company, Title, Email, and Phone. Search filters both name and company client-side.
Paste this in V0 chat
Pro tip: Insightly opportunity values are stored as plain numbers without currency formatting. Format them as '$XX,XXX' using Intl.NumberFormat in your React component rather than in the API route.
Expected result: V0 generates a CRM dashboard with a pipeline table showing opportunity values and stages, and a contact directory with search. Summary metric cards display total pipeline value and opportunity counts.
Add an Opportunities API Route
Add an Opportunities API Route
Create the opportunities API route to complete the CRM dashboard. Opportunities in Insightly represent deals in your sales pipeline, each with a value, close date, stage, and probability. Create app/api/insightly/opportunities/route.ts. The opportunities endpoint is GET https://api.insightly.com/v3.1/opportunities. Useful query parameters include $filter=STATE eq 'open' to show only open deals, $top for page size, and $orderby=CLOSE_DATE asc for sorting by close date. Each Insightly opportunity includes OPPORTUNITY_ID, OPPORTUNITY_NAME, OPPORTUNITY_VALUE, OPPORTUNITY_STATE (open/won/lost), CLOSE_DATE, PROBABILITY, RESPONSIBLE_USER_ID, and PIPELINE_ID. The STAGE_ORDER_NUMBER field indicates the position within the pipeline (0 = first stage, higher numbers = later stages). For a complete pipeline view, you also want the stage name rather than just the order number. Fetch pipeline stages from GET /v3.1/Pipelines/{pipelineId}/Stages to get a mapping of stage order numbers to stage names. You can either cache this mapping in your API route or fetch it on each request since pipeline structures rarely change. For agencies and sales teams who want to build more complex Insightly integrations — such as syncing opportunity wins to trigger onboarding workflows, automatically creating Insightly contacts from form submissions, or building a two-way sync with another CRM — RapidDev can help design the full integration architecture.
Create a Next.js API route at app/api/insightly/opportunities/route.ts that fetches open opportunities from Insightly. Use INSIGHTLY_API_KEY with Basic Auth (Base64-encoded 'key:'). Fetch from https://api.insightly.com/v3.1/opportunities with filter STATE eq 'open'. Return opportunities with id, name, value, closeDate (ISO string), probability, ownerName, stageOrder, and state. Sort by closeDate ascending. Handle errors.
Paste this in V0 chat
1import { NextResponse } from 'next/server';23interface InsightlyOpportunity {4 OPPORTUNITY_ID: number;5 OPPORTUNITY_NAME: string;6 OPPORTUNITY_VALUE: number | null;7 OPPORTUNITY_STATE: string;8 CLOSE_DATE: string | null;9 PROBABILITY: number | null;10 RESPONSIBLE_USER_ID: number | null;11 STAGE_ORDER_NUMBER: number;12 PIPELINE_ID: number | null;13 OWNER_USER_ID: number;14 RESPONSIBLE_USER_NAME?: string;15}1617export async function GET() {18 const apiKey = process.env.INSIGHTLY_API_KEY;19 const apiBase =20 process.env.INSIGHTLY_API_BASE_URL || 'https://api.insightly.com';2122 if (!apiKey) {23 return NextResponse.json(24 { error: 'Insightly configuration missing' },25 { status: 500 }26 );27 }2829 const authHeader =30 'Basic ' + Buffer.from(`${apiKey}:`).toString('base64');3132 const oppsUrl = new URL(`${apiBase}/v3.1/opportunities`);33 oppsUrl.searchParams.set('$filter', "OPPORTUNITY_STATE eq 'Open'");34 oppsUrl.searchParams.set('$top', '200');35 oppsUrl.searchParams.set('$orderby', 'CLOSE_DATE asc');3637 try {38 const response = await fetch(oppsUrl.toString(), {39 headers: {40 Authorization: authHeader,41 'Content-Type': 'application/json',42 },43 next: { revalidate: 120 },44 });4546 if (!response.ok) {47 const error = await response.text();48 console.error('Insightly opportunities error:', error);49 return NextResponse.json(50 { error: `Insightly returned ${response.status}` },51 { status: response.status }52 );53 }5455 const opportunities: InsightlyOpportunity[] = await response.json();5657 const transformed = opportunities.map((o) => ({58 id: o.OPPORTUNITY_ID,59 name: o.OPPORTUNITY_NAME,60 value: o.OPPORTUNITY_VALUE ?? 0,61 state: o.OPPORTUNITY_STATE.toLowerCase(),62 closeDate: o.CLOSE_DATE,63 isOverdue: o.CLOSE_DATE64 ? new Date(o.CLOSE_DATE) < new Date()65 : false,66 probability: o.PROBABILITY ?? 0,67 stageOrder: o.STAGE_ORDER_NUMBER,68 pipelineId: o.PIPELINE_ID,69 }));7071 const totalValue = transformed.reduce((sum, o) => sum + o.value, 0);7273 return NextResponse.json({74 opportunities: transformed,75 total: transformed.length,76 totalValue,77 });78 } catch (error) {79 console.error('Insightly opportunities fetch failed:', error);80 return NextResponse.json(81 { error: 'Failed to fetch opportunities' },82 { status: 500 }83 );84 }85}Pro tip: Insightly filter values for STATE are case-sensitive — use 'Open' (capital O) not 'open'. Check the Insightly API documentation for your version to confirm exact enum values.
Expected result: Calling /api/insightly/opportunities returns open opportunities with values, close dates, and isOverdue flags. The totalValue field sums the entire pipeline value for display in summary cards.
Common use cases
Custom Sales Pipeline Dashboard
A startup's sales team wants a custom dashboard showing all active opportunities organized by pipeline stage, with color-coded deal values and expected close dates. V0 generates a kanban-style pipeline board that fetches opportunities from Insightly and groups them by opportunity state (pipeline stage).
Build a sales pipeline board that fetches opportunities from /api/insightly/opportunities. The response has opportunities array with OPPORTUNITY_NAME, OPPORTUNITY_VALUE (number), CLOSE_DATE (ISO string), STAGE_ORDER_NUMBER (0-10), RESPONSIBLE_USER_NAME, and STATE ('open', 'won', 'lost'). Display as columns by stage: Prospecting, Qualification, Proposal, Negotiation, Closed Won. Each card shows opportunity name, value formatted as '$XX,XXX', responsible user name, and close date formatted as 'Mar 31'. Won deals show a green badge, overdue close dates (past) show a red date. Only show open opportunities by default.
Copy this prompt to try it in V0
Contact Directory with Search
A business development team wants a searchable contact directory showing all Insightly contacts with their company, title, email, and relationship tags. V0 generates a contact directory page with alphabetical sorting, search by name or company, and a detail drawer that shows full contact information.
Create a contact directory that fetches from /api/insightly/contacts. Each contact has FIRST_NAME, LAST_NAME, ORGANISATION_NAME, TITLE, EMAIL_ADDRESS (from EMAIL_ADDRESSES array, first item), PHONE_NUMBER (from PHONE_NUMBERS array, first item). Display as a sortable table with columns: Name (linked to detail), Company, Title, Email, Phone. Add a search input filtering by name or company client-side. Show 'No contacts found' for empty results. Sort alphabetically by LAST_NAME by default.
Copy this prompt to try it in V0
Weekly Opportunities Report
A sales manager wants an automated weekly report email that summarizes newly created opportunities, opportunities closing this week, and recently won deals. V0 generates a report preview page with these three sections that can be screenshotted or printed for weekly team meetings.
Build a weekly opportunities report with three sections: 'New This Week' (created in the last 7 days), 'Closing This Week' (CLOSE_DATE within next 7 days), and 'Recently Won' (STATE=won, updated in last 7 days). Each section fetches from /api/insightly/opportunities with appropriate filters. Show each opportunity as a row with name, value ($XX,XXX), owner, and date. Show section totals. Add a print button.
Copy this prompt to try it in V0
Troubleshooting
API returns 401 Unauthorized
Cause: Insightly uses Basic Auth with the API key as username and an empty password. A common mistake is encoding 'key' without the trailing colon, or using Bearer token format instead of Basic auth.
Solution: Ensure your Base64 encoding includes the trailing colon: Buffer.from('YOUR_API_KEY:').toString('base64'). The colon separates the username (API key) from the password (empty string) in HTTP Basic Auth. Also verify INSIGHTLY_API_KEY is correctly set in Vercel and that you redeployed after saving it.
1// Correct Insightly Basic Auth encoding2const authHeader = 'Basic ' + Buffer.from(`${process.env.INSIGHTLY_API_KEY}:`).toString('base64');3// Note the colon after the key — empty passwordAPI returns 404 for all endpoints
Cause: Insightly has regional API endpoints. North American accounts use api.insightly.com, but European accounts use a different regional URL. Using the wrong regional endpoint returns 404 even with correct credentials.
Solution: Check your Insightly account's data region in Settings → Account → Data Region. If your account is in the EU region, set INSIGHTLY_API_BASE_URL to the correct regional endpoint (e.g., https://api.eu1.insightly.com) and use this env var as your API base URL.
1const apiBase = process.env.INSIGHTLY_API_BASE_URL || 'https://api.insightly.com';2// Set INSIGHTLY_API_BASE_URL=https://api.eu1.insightly.com for EU accountsOData filter returns 400 Bad Request
Cause: Insightly OData filters use specific syntax rules. String values must be wrapped in single quotes, not double quotes. Using spaces around eq without the correct OData format also causes parse errors.
Solution: Use single quotes around string filter values: $filter=OPPORTUNITY_STATE eq 'Open'. Verify the exact field name (uppercase) and value (case-sensitive string like 'Open' not 'open'). Test filters using the Insightly API Explorer in their developer documentation before adding to your route.
1// Correct OData filter syntax for Insightly2oppsUrl.searchParams.set('$filter', "OPPORTUNITY_STATE eq 'Open'");3// Wrong: $filter=state eq 'open'4// Wrong: $filter=OPPORTUNITY_STATE eq "Open"Best practices
- Base64-encode the API key at runtime in your API route rather than storing the encoded string in environment variables — store the raw key and encode it in code.
- Set your Insightly API base URL in an environment variable (INSIGHTLY_API_BASE_URL) to support regional endpoints without changing code.
- Use OData $filter parameters to limit results server-side (e.g., open opportunities only) rather than fetching all records and filtering in JavaScript — this reduces payload size significantly for large CRMs.
- Cache contact and opportunity lists for 2 minutes (next: { revalidate: 120 }) since CRM data changes frequently enough that longer caching could show stale pipeline data.
- Flatten nested contact fields (EMAIL_ADDRESSES and PHONE_NUMBERS arrays) in your API route to make V0 components simpler — return primary email and phone as direct string fields.
- Always include null checks for OPPORTUNITY_VALUE and CLOSE_DATE — Insightly allows creating opportunities without these fields, and null values cause JavaScript calculation errors.
- For client portals showing only one company's data, filter contacts by ORGANISATION_ID rather than returning all contacts and filtering client-side to minimize data transfer.
Alternatives
HubSpot offers a more feature-rich free CRM tier with a better-documented API, suitable for teams that need more marketing automation alongside contact management.
Pipedrive is a sales-focused CRM with a visual pipeline interface and a clean REST API, ideal for teams that primarily need sales pipeline management without Insightly's project management features.
Zoho CRM is part of a larger business software ecosystem with tighter integrations to Zoho's other tools, better for businesses already using Zoho Books, Zoho Desk, or other Zoho products.
Frequently asked questions
Does Insightly's API work on the free plan?
Insightly's free plan (up to 2 users) includes limited API access. Paid plans (Plus, Professional, Enterprise) include full API access with higher rate limits. If you are on the free plan and experiencing API errors, upgrading to a paid plan should resolve access restrictions.
Can I create contacts and opportunities via the Insightly API?
Yes. Use POST https://api.insightly.com/v3.1/contacts with a JSON body to create contacts, and POST /v3.1/opportunities to create opportunities. The same Basic Auth header applies. This enables form-to-CRM workflows where V0 contact forms create Insightly records automatically.
How do I get a list of my pipeline stages for the kanban board?
Fetch pipelines with GET /v3.1/Pipelines to get your pipeline IDs and names. Then fetch stages for a specific pipeline with GET /v3.1/Pipelines/{pipelineId}/Stages. Each stage has STAGE_ID, STAGE_NAME, and STAGE_ORDER. Map the STAGE_ORDER_NUMBER from opportunities to these stage names for your kanban column labels.
What is the Insightly API rate limit?
Insightly's API rate limit varies by plan. The Plus plan allows 10 requests per second, Professional allows higher limits, and Enterprise has the highest limits. For a dashboard accessed by a few users at a time, these limits are rarely hit with Next.js fetch caching (next: { revalidate: 120 }) reducing the frequency of API calls.
Can I use Insightly webhooks to push real-time updates to my V0 app?
Insightly supports webhooks for events like contact creation, opportunity stage changes, and task completion. Create a POST handler at app/api/insightly/webhook/route.ts on your Vercel deployment. In Insightly Settings → Webhooks, add your deployed URL as the webhook endpoint. The webhook can trigger cache invalidation or database updates to keep your dashboard current.
How do I display contact custom fields from Insightly?
Insightly contacts have a CUSTOMFIELDS array in the API response, where each item has FIELD_NAME and FIELD_VALUE. Include these in your API route response by mapping the CUSTOMFIELDS array. Custom field names match what you defined in your Insightly account settings under System Settings → Custom Fields.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation