Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate Zoho Books with V0

To integrate Zoho Books with V0 by Vercel, generate an invoicing or accounting dashboard UI with V0, create Next.js API routes that call the Zoho Books REST API using OAuth2 access tokens, and store credentials in Vercel environment variables. Your app can create invoices, manage contacts, track expenses, and generate financial reports without exposing API credentials to the browser.

What you'll learn

  • How to generate an invoicing or accounting dashboard UI with V0
  • How to set up Zoho Books OAuth2 authentication with refresh tokens in Next.js
  • How to create API routes that manage invoices, contacts, and expenses in Zoho Books
  • How to store Zoho OAuth credentials securely in Vercel environment variables
  • How to handle Zoho Books API pagination and organization ID scoping
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read40 minutesOtherApril 2026RapidDev Engineering Team
TL;DR

To integrate Zoho Books with V0 by Vercel, generate an invoicing or accounting dashboard UI with V0, create Next.js API routes that call the Zoho Books REST API using OAuth2 access tokens, and store credentials in Vercel environment variables. Your app can create invoices, manage contacts, track expenses, and generate financial reports without exposing API credentials to the browser.

Build Custom Accounting Dashboards for Zoho Books with V0 and Next.js API Routes

Zoho Books is the accounting component of the Zoho One business suite, positioned as a cost-effective alternative to QuickBooks and FreshBooks for small and medium businesses. Its tight integration with Zoho CRM, Zoho Invoice, and Zoho Inventory makes it particularly attractive for businesses already in the Zoho ecosystem. For V0-generated apps, Zoho Books integration enables building custom financial dashboards, automating invoice creation from project completion events, syncing customer data between your app and Zoho Books contacts, and generating branded financial reports.

Zoho Books uses OAuth2 for all API authentication, which is more complex to set up than simple API key authentication but provides proper token scoping and revocation. The integration requires creating a Zoho API client, obtaining an authorization code, exchanging it for a refresh token (a one-time setup), and then using the refresh token to generate short-lived access tokens for each API request. This initial setup takes 10-15 minutes but the resulting integration is secure and standards-compliant.

For V0-built financial apps, Zoho Books is particularly valuable for freelancers and small agencies because it handles VAT/GST tax compliance for global markets and provides multi-currency invoicing — features that simpler invoicing tools like Wave and FreshBooks handle less comprehensively. The Zoho Books API covers invoices, bills, expenses, contacts, items, journals, and reports, giving your V0 app full access to the accounting backend while presenting data in a completely custom interface.

Integration method

Next.js API Route

Zoho Books integrates with V0-generated Next.js apps through server-side API routes using the Zoho Books REST API with OAuth2 authentication. Client ID, client secret, and a long-lived refresh token are stored as server-only Vercel environment variables. API routes exchange the refresh token for short-lived access tokens on each request, then call the Zoho Books API to manage invoices, contacts, expenses, and reports. The V0-generated accounting UI fetches all data through these API routes, keeping Zoho credentials fully server-side.

Prerequisites

  • A Zoho Books account — the free plan allows up to 1,000 invoices per year, paid plans start at $15/month
  • A Zoho API client created at api-console.zoho.com — choose 'Server-based Applications' for Next.js API routes
  • Your Zoho OAuth client ID and client secret from the API console
  • A refresh token obtained through the one-time OAuth authorization flow (detailed in Step 1)
  • Your Zoho Books organization ID — found in Zoho Books → Settings → Organization Profile
  • A V0 account at v0.dev and a Vercel account for deploying your Next.js app

Step-by-step guide

1

Set Up Zoho OAuth2 Credentials

Zoho Books requires OAuth2 authentication, which involves a one-time setup to obtain a refresh token. This setup is done before writing any Next.js code. First, go to api-console.zoho.com and click 'Add Client'. Select 'Server-based Applications' as the client type — this is appropriate for Next.js server-side API routes. Enter a redirect URI (use http://localhost:3000/auth/callback for initial setup, you can update it to your Vercel URL later). Note the Client ID and Client Secret. Next, generate the authorization URL: visit https://accounts.zoho.com/oauth/v2/auth?scope=ZohoBooks.fullaccess.all&client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=http://localhost:3000/auth/callback&access_type=offline. Open this URL in your browser, authorize your Zoho Books account, and you will be redirected to your redirect URI with a code parameter in the URL (e.g., http://localhost:3000/auth/callback?code=1000.abc123). Copy this authorization code. Then exchange it for a refresh token by making a POST request to https://accounts.zoho.com/oauth/v2/token with parameters: client_id, client_secret, code (the authorization code), redirect_uri, and grant_type=authorization_code. You can do this with curl or Postman. The response includes a refresh_token — copy and store it securely. This refresh_token is what you will store in Vercel and use in your API routes to obtain access tokens. Your Zoho Books Organization ID is found in Zoho Books → Settings → Organization Profile at the bottom of the page.

typescript
1# One-time curl command to exchange authorization code for refresh token:
2# Replace YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_AUTH_CODE
3curl -X POST 'https://accounts.zoho.com/oauth/v2/token' \
4 -d 'client_id=YOUR_CLIENT_ID' \
5 -d 'client_secret=YOUR_CLIENT_SECRET' \
6 -d 'code=YOUR_AUTH_CODE' \
7 -d 'redirect_uri=http://localhost:3000/auth/callback' \
8 -d 'grant_type=authorization_code'
9
10# Response includes:
11# { "access_token": "...", "refresh_token": "1000.xxx...", "expires_in": 3600 }
12# Save the refresh_token this is the long-lived credential for your app

Pro tip: The authorization code (code parameter) expires in 60 seconds — exchange it for a refresh token immediately after copying it from the redirect URL. If it expires, repeat the authorization URL step to get a new code.

Expected result: You have a Zoho Client ID, Client Secret, Refresh Token, and Organization ID. These four values are everything needed to authenticate Zoho Books API requests from your Next.js routes.

2

Generate the Accounting UI with V0

Open V0 at v0.dev and describe the accounting or invoicing interface you want to build. Financial dashboards require careful data presentation — currency formatting, status badge colors, date formatting, and data tables with sorting. Be specific about number formatting (use '$1,234.56' format with thousands separator), status colors (paid = green, overdue = red, draft = gray, sent = blue), and the date format you want (full date vs relative like '3 days ago'). For an invoice management dashboard, describe the key metrics at the top (outstanding amount, overdue amount, paid this month), the invoice table with sortable columns, and the invoice detail view when a row is clicked. For an expense tracker, describe the mobile-first form with receipt upload area, category selector, and submission confirmation. Include skeleton loading states and empty states (when no invoices exist yet) in your prompt. V0 generates financial dashboard layouts well when you describe them with specific field names matching the actual data structure — mention field names like invoice_number, customer_name, total, due_date, and status directly in your prompt so V0 generates the correct component props and data bindings. After generating, push to GitHub using V0's Git panel.

V0 Prompt

Create a financial overview dashboard with three KPI cards: 'Total Receivable' (large amount in blue), 'Overdue Amount' (in red), and 'Collected This Month' (in green). Below, an Invoices section with a data table: Invoice # (link), Customer, Issue Date, Due Date, Amount (right-aligned), Status (badge: Draft/Sent/Viewed/Paid/Overdue). Add a Create Invoice button top-right. Include table row hover states and a date range filter. Show skeleton loaders while data fetches from /api/zoho-books/invoices. Clean accounting software design.

Paste this in V0 chat

Pro tip: Tell V0 to right-align all currency columns in your tables — this is a standard financial table convention that makes amounts easier to compare visually, and V0 will apply the correct Tailwind text-right class when you specify it.

Expected result: A financial dashboard renders in V0's preview with KPI metric cards, invoice table with status badges, create button, and skeleton loading states. The component fetches from /api/zoho-books/invoices.

3

Create the Zoho Books API Routes

Create the Next.js API routes that authenticate with Zoho's OAuth2 token endpoint and then call the Zoho Books API. The key pattern is a helper function that exchanges your stored refresh token for a short-lived access token, then uses that access token for the actual Zoho Books API call. Access tokens expire in 1 hour — do not store them; instead, generate a fresh one at the start of each API route invocation. The Zoho Books API base URL is https://www.zohoapis.com/books/v3 and all requests require the Authorization: Zoho-oauthtoken ACCESS_TOKEN header and the organization_id query parameter (your Zoho Books organization ID). The invoices endpoint is GET /invoices and supports filters for status, customer_id, date range, and pagination via page and per_page. The response includes an invoices array and pagination metadata. For creating invoices, POST to /invoices with a JSON body containing customer_id, invoice_date, due_date, and a line_items array. Each line item needs name, quantity, rate, and optionally account_id and tax_id. Zoho Books uses different API domains depending on your account's data region — accounts.zoho.com for authentication and www.zohoapis.com for the Books API work for US accounts. European accounts may need eu.zohoapis.com and Indian accounts in.zohoapis.com — check your Zoho account's region in Zoho Books URL.

app/api/zoho-books/invoices/route.ts
1// app/api/zoho-books/invoices/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const ZOHO_TOKEN_URL = 'https://accounts.zoho.com/oauth/v2/token';
5const ZOHO_BOOKS_BASE = 'https://www.zohoapis.com/books/v3';
6
7async function getZohoAccessToken(): Promise<string> {
8 const response = await fetch(ZOHO_TOKEN_URL, {
9 method: 'POST',
10 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
11 body: new URLSearchParams({
12 client_id: process.env.ZOHO_CLIENT_ID!,
13 client_secret: process.env.ZOHO_CLIENT_SECRET!,
14 refresh_token: process.env.ZOHO_REFRESH_TOKEN!,
15 grant_type: 'refresh_token',
16 }),
17 });
18
19 if (!response.ok) {
20 throw new Error(`Failed to get Zoho access token: ${response.status}`);
21 }
22
23 const data = await response.json();
24 if (data.error) {
25 throw new Error(`Zoho OAuth error: ${data.error}`);
26 }
27
28 return data.access_token as string;
29}
30
31export async function GET(request: NextRequest) {
32 const orgId = process.env.ZOHO_BOOKS_ORG_ID;
33
34 if (!process.env.ZOHO_CLIENT_ID || !process.env.ZOHO_REFRESH_TOKEN || !orgId) {
35 return NextResponse.json(
36 { error: 'Zoho Books is not configured' },
37 { status: 500 }
38 );
39 }
40
41 const { searchParams } = new URL(request.url);
42 const status = searchParams.get('status') ?? 'all'; // draft, sent, overdue, paid
43 const page = searchParams.get('page') ?? '1';
44
45 try {
46 const accessToken = await getZohoAccessToken();
47
48 const params = new URLSearchParams({
49 organization_id: orgId,
50 page,
51 per_page: '25',
52 });
53
54 if (status !== 'all') {
55 params.set('status', status);
56 }
57
58 const response = await fetch(
59 `${ZOHO_BOOKS_BASE}/invoices?${params.toString()}`,
60 {
61 headers: {
62 Authorization: `Zoho-oauthtoken ${accessToken}`,
63 'Content-Type': 'application/json',
64 },
65 }
66 );
67
68 if (!response.ok) {
69 const error = await response.json();
70 return NextResponse.json(
71 { error: 'Zoho Books API error', details: error.message },
72 { status: response.status }
73 );
74 }
75
76 const data = await response.json();
77 return NextResponse.json({
78 invoices: data.invoices ?? [],
79 pageContext: data.page_context ?? {},
80 });
81 } catch (error) {
82 const message = error instanceof Error ? error.message : 'Unknown error';
83 console.error('Zoho Books invoices fetch failed:', message);
84 return NextResponse.json(
85 { error: 'Failed to fetch invoices', details: message },
86 { status: 500 }
87 );
88 }
89}

Pro tip: Generate a fresh access token on every API route invocation using getZohoAccessToken() — do not cache or store the access token since it expires in 1 hour and caching across multiple serverless function instances would cause token-sharing issues on Vercel.

Expected result: GET /api/zoho-books/invoices returns real invoice data from your Zoho Books account including invoice numbers, customer names, amounts, due dates, and payment status.

4

Add Environment Variables and Deploy to Vercel

Push your code to GitHub and configure all four Zoho Books credentials in Vercel. Open the Vercel Dashboard, select your project, and navigate to Settings → Environment Variables. Add ZOHO_CLIENT_ID (your OAuth client ID from api-console.zoho.com), ZOHO_CLIENT_SECRET (the client secret from the same page), ZOHO_REFRESH_TOKEN (the long-lived refresh token obtained in Step 1), and ZOHO_BOOKS_ORG_ID (your organization ID from Zoho Books → Settings → Organization Profile). None of these variables should have the NEXT_PUBLIC_ prefix — all four are server-side secrets. Set all variables for Production, Preview, and Development environments. Click Save and trigger a redeployment. After deployment, open your dashboard and verify that real Zoho Books invoices appear in the table. If invoices do not load, check Vercel function logs for the specific error — common issues are using the wrong Zoho data region URL, an expired or incorrectly copied refresh token, or an incorrect organization ID. For European accounts, update ZOHO_BOOKS_BASE in your code to https://eu.zohoapis.com/books/v3 and ZOHO_TOKEN_URL to https://accounts.zoho.eu/oauth/v2/token.

Pro tip: European Union Zoho accounts use eu.zohoapis.com instead of www.zohoapis.com for API calls, and accounts.zoho.eu for OAuth token requests. Indian accounts use in.zohoapis.com and accounts.zoho.in. Check your Zoho Books URL in the browser to identify your data region.

Expected result: The deployed Vercel app displays real Zoho Books invoices in the custom V0-generated dashboard. All four OAuth credentials are set in Vercel and the API routes authenticate and fetch data successfully.

Common use cases

Custom Invoice Creation Dashboard

A V0-generated internal tool where team members create and send invoices without logging into Zoho Books directly. The dashboard shows recent invoices, lets users create new ones with a simplified form (client, items, due date), and tracks payment status in real time.

V0 Prompt

Build an invoice management dashboard with a Recent Invoices table showing invoice number, client name, amount, due date, and status badge (Draft/Sent/Paid/Overdue). Include a New Invoice button that opens a slide-over form with client dropdown, line items table (description, quantity, rate, amount), and Send/Save Draft buttons. Add summary metrics at top: Total Outstanding, Overdue Amount, Paid This Month. Fetch from /api/zoho-books/invoices. Professional finance tool design.

Copy this prompt to try it in V0

Client Portal with Invoice History

A customer-facing portal where clients log in to see all their invoices from Zoho Books, view outstanding balances, download PDF copies, and pay via a Stripe payment link. The portal pulls invoice data from Zoho Books and presents it with your brand design instead of the Zoho Books interface.

V0 Prompt

Create a client billing portal with a header showing client company name and total outstanding balance. Below, show an invoices list with: invoice number, date, due date, amount, and status. Clicking an invoice expands to show line items and a Download PDF button. For unpaid invoices, show a Pay Now button (link to Stripe). Add tabs for All/Pending/Paid invoice filtering. Fetch from /api/zoho-books/client-invoices. Clean portal design with the client's industry aesthetic.

Copy this prompt to try it in V0

Business Expenses Tracker

A mobile-friendly expense capture form where team members log business expenses. Submitted expenses are automatically created in Zoho Books with the correct category, project, and tax treatment. Managers see a dashboard with pending expense approvals and monthly spend by category.

V0 Prompt

Design an expense submission form with: amount input, currency selector, category dropdown (Travel/Software/Marketing/Office/Other), date picker, merchant name input, description textarea, and a Receipt Upload button. Below the form, show My Expenses table with pending/approved/rejected status. On submission (POST to /api/zoho-books/expenses), show a success confirmation with the expense ID. Mobile-first design suitable for quick expense logging from a phone.

Copy this prompt to try it in V0

Troubleshooting

Token request returns 'invalid_code' or 'invalid_grant' error

Cause: The authorization code used to generate the refresh token has expired (codes expire in 60 seconds) or the refresh token itself has been revoked or expired. Zoho refresh tokens are long-lived but can be revoked if the user removes your API client's authorization.

Solution: Re-authorize the application: visit the authorization URL from Step 1 again, authorize, copy the new code immediately, and exchange it for a new refresh token with the curl command. Update ZOHO_REFRESH_TOKEN in Vercel with the new value and redeploy.

Zoho Books API returns 'Invalid Organization' error

Cause: The ZOHO_BOOKS_ORG_ID is incorrect or the authorized Zoho account does not have access to the specified organization. The organization ID must be the numeric ID from your Zoho Books settings, not the organization name.

Solution: Confirm your organization ID by calling GET https://www.zohoapis.com/books/v3/organizations with your access token — it returns all organizations accessible to your account. Use the numeric id field, not the name. Update ZOHO_BOOKS_ORG_ID in Vercel.

typescript
1// Find your organization ID:
2// GET https://www.zohoapis.com/books/v3/organizations
3// Authorization: Zoho-oauthtoken ACCESS_TOKEN
4// Response: { organizations: [{ organization_id: '12345678', name: 'My Business' }] }

API returns 401 despite a valid-looking access token

Cause: The API is being called against the wrong Zoho regional domain. Zoho separates its infrastructure by region, and an account created on Zoho's European servers cannot be accessed via the US API endpoints.

Solution: Check which region your Zoho account is on by looking at the URL when logged into Zoho Books. If the URL shows books.zoho.eu or books.zoho.in, update your API base URLs to eu.zohoapis.com or in.zohoapis.com respectively. Also update the token URL to accounts.zoho.eu or accounts.zoho.in.

typescript
1// For EU accounts:
2const ZOHO_TOKEN_URL = 'https://accounts.zoho.eu/oauth/v2/token';
3const ZOHO_BOOKS_BASE = 'https://eu.zohoapis.com/books/v3';
4
5// For India accounts:
6// const ZOHO_TOKEN_URL = 'https://accounts.zoho.in/oauth/v2/token';
7// const ZOHO_BOOKS_BASE = 'https://in.zohoapis.com/books/v3';

Invoice creation fails with 'Customer does not exist' error

Cause: The customer_id used in the invoice creation request does not exist in Zoho Books, or it belongs to a different organization than the one in ZOHO_BOOKS_ORG_ID.

Solution: Fetch the customer list from GET /contacts?contact_type=customer to get valid customer IDs for your organization. Add a customer lookup API route and a customer dropdown to your V0 invoice creation form that pre-populates with valid Zoho Books contact IDs.

Best practices

  • Store all four Zoho OAuth credentials (client ID, client secret, refresh token, organization ID) as server-only Vercel environment variables without NEXT_PUBLIC_ prefix
  • Generate a fresh access token for each API route request rather than caching the 1-hour access token — serverless function instances cannot share tokens reliably
  • Handle Zoho's regional API domains upfront — EU and India accounts use different base URLs, and using the wrong region causes 401 errors that are confusing to debug
  • Add the organization_id query parameter to every Zoho Books API call — omitting it causes ambiguous errors when the account has multiple organizations
  • Implement pagination for invoice and contact list endpoints — Zoho Books paginates at 25-200 items per page and large accounts will silently return incomplete data without pagination handling
  • Re-authorize the application (regenerate the refresh token) if Zoho users change their account password or revoke OAuth permissions — build a re-authorization flow or document the re-auth process for your team
  • Use Zoho Books webhooks for real-time invoice status updates rather than polling — configure webhooks in Zoho Books → Settings → Integrations → Webhooks to receive instant notifications when invoice status changes

Alternatives

Frequently asked questions

Does Zoho Books have a free plan with API access?

Zoho Books offers a free plan for businesses with annual revenue under $50,000 (in supported regions) that includes invoicing and expense tracking. The API is available on paid plans starting at $15/month. If you are on the free plan and need API access, you will need to upgrade. The paid Standard plan includes full API access and supports the complete set of endpoints for invoices, contacts, items, and reports.

How long does the Zoho refresh token last?

Zoho refresh tokens are long-lived and do not expire on a fixed schedule, but they are invalidated if the user revokes the application's authorization in Zoho's Connected Apps settings, if the client's OAuth application is deleted from api-console.zoho.com, or if the user changes their Zoho account password. Plan for occasional re-authorization by documenting the refresh token regeneration process.

Can I create invoices in Zoho Books from my V0 app?

Yes — POST to /invoices with customer_id, invoice_date, due_date, and a line_items array containing name, quantity, and rate for each item. The API returns the created invoice with its invoice_id and invoice_number. You can then send the invoice via email directly through the API with a POST to /invoices/{invoice_id}/email, which triggers Zoho Books to send the invoice email to the customer.

How do I sync Zoho Books contacts with my V0 app's user database?

Fetch contacts from GET /contacts and match them by email address to your app's users. For creating new contacts, POST to /contacts with contact_name, contact_type (customer or vendor), and email. For bidirectional sync, use Zoho Books webhooks to receive contact creation/update events in your Next.js webhook route and update your local database accordingly. For complex integrations, RapidDev's team can help design the sync architecture.

What is the Zoho Books API rate limit?

Zoho Books API rate limits are 1,000 requests per organization per day on the Standard plan, and higher on Professional and Premium plans. For dashboards that load invoice lists, contact details, and summary statistics, you can easily reach 100 requests per user session. Implement response caching (Next.js route revalidation or in-memory caching for frequently accessed data like contact lists) to stay within quota. Check your API usage in Zoho API Console.

Can I download PDF invoices from Zoho Books via the API?

Yes — Zoho Books provides a PDF download endpoint for invoices. Use GET /invoices/{invoice_id}?accept=pdf with the appropriate Accept: application/pdf header to download the invoice as a PDF binary. Your Next.js API route can stream this PDF to the browser for download using a ReadableStream response, enabling invoice PDF downloads directly from your V0-generated dashboard.

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.