Introduction to Zoho Books API
Zoho Books is a comprehensive accounting software that provides APIs for managing invoices, contacts, items, payments, and other financial data. This guide covers building a complete Java client for Zoho Books API integration.
Key Features
- Invoice Management - Create, read, update invoices
- Contact Management - Customer and vendor management
- Item Management - Product and service catalog
- Payment Processing - Payment recording and tracking
- Organization Management - Multi-organization support
- Report Generation - Financial reports and analytics
Dependencies and Setup
Maven Configuration
<properties> <okhttp.version>4.12.0</okhttp.version> <jackson.version>2.15.2</jackson.version> <oauth2.version>0.1.0</oauth2.version> </properties> <dependencies> <!-- HTTP Client --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>${okhttp.version}</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${jackson.version}</version> </dependency> <!-- OAuth2 Support --> <dependency> <groupId>com.github.scribejava</groupId> <artifactId>scribejava-core</artifactId> <version>8.3.3</version> </dependency> <!-- Logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.7</version> </dependency> <!-- Testing --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.9.3</version> <scope>test</scope> </dependency> </dependencies> Core Zoho Books Client
Main Zoho Books Client
package com.zohobooks.client; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; public class ZohoBooksClient { private static final Logger logger = LoggerFactory.getLogger(ZohoBooksClient.class); private final String baseUrl; private final String organizationId; private final String accessToken; private final OkHttpClient httpClient; private final ObjectMapper objectMapper; public ZohoBooksClient(String accessToken, String organizationId) { this("https://books.zoho.com/api/v3", accessToken, organizationId); } public ZohoBooksClient(String baseUrl, String accessToken, String organizationId) { this.baseUrl = baseUrl; this.accessToken = accessToken; this.organizationId = organizationId; this.objectMapper = new ObjectMapper(); this.httpClient = new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build(); } /** * Execute API request with authentication */ private Response executeRequest(Request request) throws ZohoBooksException { try { Response response = httpClient.newCall(request).execute(); if (!response.isSuccessful()) { handleErrorResponse(response); } return response; } catch (IOException e) { throw new ZohoBooksException("API request failed", e); } } /** * Handle error responses from Zoho Books API */ private void handleErrorResponse(Response response) throws IOException, ZohoBooksException { String errorBody = response.body().string(); logger.error("Zoho Books API error: {} - {}", response.code(), errorBody); try { ErrorResponse errorResponse = objectMapper.readValue(errorBody, ErrorResponse.class); throw new ZohoBooksException( errorResponse.getMessage() != null ? errorResponse.getMessage() : "API Error", response.code(), errorResponse.getCode() ); } catch (Exception e) { throw new ZohoBooksException("HTTP " + response.code() + ": " + errorBody, response.code()); } } /** * Create authenticated request builder */ private Request.Builder createAuthenticatedRequest(String endpoint) { HttpUrl url = HttpUrl.parse(baseUrl + endpoint) .newBuilder() .addQueryParameter("organization_id", organizationId) .build(); return new Request.Builder() .url(url) .addHeader("Authorization", "Zoho-oauthtoken " + accessToken) .addHeader("Content-Type", "application/json"); } /** * GET request */ public <T> T get(String endpoint, Map<String, String> params, Class<T> responseType) throws ZohoBooksException { try { HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl + endpoint).newBuilder() .addQueryParameter("organization_id", organizationId); if (params != null) { for (Map.Entry<String, String> param : params.entrySet()) { urlBuilder.addQueryParameter(param.getKey(), param.getValue()); } } Request request = new Request.Builder() .url(urlBuilder.build()) .addHeader("Authorization", "Zoho-oauthtoken " + accessToken) .get() .build(); try (Response response = executeRequest(request)) { String responseBody = response.body().string(); return objectMapper.readValue(responseBody, responseType); } } catch (IOException e) { throw new ZohoBooksException("GET request failed: " + endpoint, e); } } /** * POST request */ public <T> T post(String endpoint, Object data, Class<T> responseType) throws ZohoBooksException { return post(endpoint, data, null, responseType); } public <T> T post(String endpoint, Object data, Map<String, String> params, Class<T> responseType) throws ZohoBooksException { try { String jsonData = objectMapper.writeValueAsString(data); HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl + endpoint).newBuilder() .addQueryParameter("organization_id", organizationId); if (params != null) { for (Map.Entry<String, String> param : params.entrySet()) { urlBuilder.addQueryParameter(param.getKey(), param.getValue()); } } RequestBody body = RequestBody.create(jsonData, MediaType.parse("application/json")); Request request = new Request.Builder() .url(urlBuilder.build()) .addHeader("Authorization", "Zoho-oauthtoken " + accessToken) .post(body) .build(); try (Response response = executeRequest(request)) { String responseBody = response.body().string(); return objectMapper.readValue(responseBody, responseType); } } catch (IOException e) { throw new ZohoBooksException("POST request failed: " + endpoint, e); } } /** * PUT request */ public <T> T put(String endpoint, Object data, Class<T> responseType) throws ZohoBooksException { return put(endpoint, data, null, responseType); } public <T> T put(String endpoint, Object data, Map<String, String> params, Class<T> responseType) throws ZohoBooksException { try { String jsonData = objectMapper.writeValueAsString(data); HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl + endpoint).newBuilder() .addQueryParameter("organization_id", organizationId); if (params != null) { for (Map.Entry<String, String> param : params.entrySet()) { urlBuilder.addQueryParameter(param.getKey(), param.getValue()); } } RequestBody body = RequestBody.create(jsonData, MediaType.parse("application/json")); Request request = new Request.Builder() .url(urlBuilder.build()) .addHeader("Authorization", "Zoho-oauthtoken " + accessToken) .put(body) .build(); try (Response response = executeRequest(request)) { String responseBody = response.body().string(); return objectMapper.readValue(responseBody, responseType); } } catch (IOException e) { throw new ZohoBooksException("PUT request failed: " + endpoint, e); } } /** * DELETE request */ public <T> T delete(String endpoint, Class<T> responseType) throws ZohoBooksException { return delete(endpoint, null, responseType); } public <T> T delete(String endpoint, Map<String, String> params, Class<T> responseType) throws ZohoBooksException { try { HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl + endpoint).newBuilder() .addQueryParameter("organization_id", organizationId); if (params != null) { for (Map.Entry<String, String> param : params.entrySet()) { urlBuilder.addQueryParameter(param.getKey(), param.getValue()); } } Request request = new Request.Builder() .url(urlBuilder.build()) .addHeader("Authorization", "Zoho-oauthtoken " + accessToken) .delete() .build(); try (Response response = executeRequest(request)) { String responseBody = response.body().string(); return objectMapper.readValue(responseBody, responseType); } } catch (IOException e) { throw new ZohoBooksException("DELETE request failed: " + endpoint, e); } } /** * Get list with pagination */ public <T> PaginatedResponse<T> getList(String endpoint, Map<String, String> params, Class<T> itemType) throws ZohoBooksException { try { String responseBody = getRawResponse(endpoint, params); return objectMapper.readValue(responseBody, objectMapper.getTypeFactory().constructParametricType(PaginatedResponse.class, itemType)); } catch (IOException e) { throw new ZohoBooksException("Failed to get list: " + endpoint, e); } } /** * Get raw response as string */ public String getRawResponse(String endpoint, Map<String, String> params) throws ZohoBooksException { try { HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl + endpoint).newBuilder() .addQueryParameter("organization_id", organizationId); if (params != null) { for (Map.Entry<String, String> param : params.entrySet()) { urlBuilder.addQueryParameter(param.getKey(), param.getValue()); } } Request request = new Request.Builder() .url(urlBuilder.build()) .addHeader("Authorization", "Zoho-oauthtoken " + accessToken) .get() .build(); try (Response response = executeRequest(request)) { return response.body().string(); } } catch (IOException e) { throw new ZohoBooksException("Failed to get raw response: " + endpoint, e); } } // Custom exception public static class ZohoBooksException extends Exception { private final int statusCode; private final String errorCode; public ZohoBooksException(String message) { super(message); this.statusCode = 0; this.errorCode = null; } public ZohoBooksException(String message, Throwable cause) { super(message, cause); this.statusCode = 0; this.errorCode = null; } public ZohoBooksException(String message, int statusCode) { super(message); this.statusCode = statusCode; this.errorCode = null; } public ZohoBooksException(String message, int statusCode, String errorCode) { super(message); this.statusCode = statusCode; this.errorCode = errorCode; } public int getStatusCode() { return statusCode; } public String getErrorCode() { return errorCode; } } } Data Models
Core Data Classes
```java
package com.zohobooks.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
// Base Response Models
@JsonIgnoreProperties(ignoreUnknown = true)
class BaseResponse {
private int code;
private String message;
// Getters and setters public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
@JsonIgnoreProperties(ignoreUnknown = true)
class PaginatedResponse {
private int code;
private String message;
private PageContext pageContext;
private List data;
// Getters and setters public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public PageContext getPageContext() { return pageContext; } public void setPageContext(PageContext pageContext) { this.pageContext = pageContext; } public List<T> getData() { return data; } public void setData(List<T> data) { this.data = data; } }
@JsonIgnoreProperties(ignoreUnknown = true)
class PageContext {
private int page;
private int perPage;
private boolean hasMorePage;
private String reportName;
private String appliedFilter;
private String sortColumn;
private String sortOrder;
// Getters and setters public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getPerPage() { return perPage; } public void setPerPage(int perPage) { this.perPage = perPage; } public boolean isHasMorePage() { return hasMorePage; } public void setHasMorePage(boolean hasMorePage) { this.hasMorePage = hasMorePage; } public String getReportName() { return reportName; } public void setReportName(String reportName) { this.reportName = reportName; } public String getAppliedFilter() { return appliedFilter; } public void setAppliedFilter(String appliedFilter) { this.appliedFilter = appliedFilter; } public String getSortColumn() { return sortColumn; } public void setSortColumn(String sortColumn) { this.sortColumn = sortColumn; } public String getSortOrder() { return sortOrder; } public void setSortOrder(String sortOrder) { this.sortOrder = sortOrder; } }
@JsonIgnoreProperties(ignoreUnknown = true)
class ErrorResponse {
private int code;
private String message;
private Map details;
// Getters and setters public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Map<String, Object> getDetails() { return details; } public void setDetails(Map<String, Object> details) { this.details = details; } }
// Organization Models
@JsonIgnoreProperties(ignoreUnknown = true)
class Organization {
private String organizationId;
private String name;
private String contactName;
private String email;
private String languageCode;
private String locale;
private String timeZone;
private String currencyCode;
private String currencySymbol;
private String currencyFormat;
private int decimalPlaces;
private int yearEndMonth;
private String dateFormat;
private String fieldSeparator;
private String industryType;
private String industrySize;
private String companyIdLabel;
private String companyIdValue;
private String taxIdLabel;
private String taxIdValue;
private Address address;
private String orgAddress;
private String remitToAddress;
private String phone;
private String fax;
private String website;
private String fiscalYearStartMonth;
private boolean isOrgActive;
private boolean isDefaultOrg;
// Getters and setters public String getOrganizationId() { return organizationId; } public void setOrganizationId(String organizationId) { this.organizationId = organizationId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getContactName() { return contactName; } public void setContactName(String contactName) { this.contactName = contactName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getLanguageCode() { return languageCode; } public void setLanguageCode(String languageCode) { this.languageCode = languageCode; } public String getLocale() { return locale; } public void setLocale(String locale) { this.locale = locale; } public String getTimeZone() { return timeZone; } public void setTimeZone(String timeZone) { this.timeZone = timeZone; } public String getCurrencyCode() { return currencyCode; } public void setCurrencyCode(String currencyCode) { this.currencyCode = currencyCode; } public String getCurrencySymbol() { return currencySymbol; } public void setCurrencySymbol(String currencySymbol) { this.currencySymbol = currencySymbol; } public String getCurrencyFormat() { return currencyFormat; } public void setCurrencyFormat(String currencyFormat) { this.currencyFormat = currencyFormat; } public int getDecimalPlaces() { return decimalPlaces; } public void setDecimalPlaces(int decimalPlaces) { this.decimalPlaces = decimalPlaces; } public int getYearEndMonth() { return yearEndMonth; } public void setYearEndMonth(int yearEndMonth) { this.yearEndMonth = yearEndMonth; } public String getDateFormat() { return dateFormat; } public void setDateFormat(String dateFormat) { this.dateFormat = dateFormat; } public String getFieldSeparator() { return fieldSeparator; } public void setFieldSeparator(String fieldSeparator) { this.fieldSeparator = fieldSeparator; } public String getIndustryType() { return industryType; } public void setIndustryType(String industryType) { this.industryType = industryType; } public String getIndustrySize() { return industrySize; } public void setIndustrySize(String industrySize) { this.industrySize = industrySize; } public String getCompanyIdLabel() { return companyIdLabel; } public void setCompanyIdLabel(String companyIdLabel) { this.companyIdLabel = companyIdLabel; } public String getCompanyIdValue() { return companyIdValue; } public void setCompanyIdValue(String companyIdValue) { this.companyIdValue = companyIdValue; } public String getTaxIdLabel() { return taxIdLabel; } public void setTaxIdLabel(String taxIdLabel) { this.taxIdLabel = taxIdLabel; } public String getTaxIdValue() { return taxIdValue; } public void setTaxIdValue(String taxIdValue) { this.taxIdValue = taxIdValue; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String getOrgAddress() { return orgAddress; } public void setOrgAddress(String orgAddress) { this.orgAddress = orgAddress; } public String getRemitToAddress() { return remitToAddress; } public void setRemitToAddress(String remitToAddress) { this.remitToAddress = remitToAddress; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getFax() { return fax; } public void setFax(String fax) { this.fax = fax; } public String getWebsite() { return website; } public void setWebsite(String website) { this.website = website; } public String getFiscalYearStartMonth() { return fiscalYearStartMonth; } public void setFiscalYearStartMonth(String fiscalYearStartMonth) { this.fiscalYearStartMonth = fiscalYearStartMonth; } public boolean isOrgActive() { return isOrgActive; } public void setOrgActive(boolean orgActive) { isOrgActive = orgActive; } public boolean isDefaultOrg() { return isDefaultOrg; } public void setDefaultOrg(boolean defaultOrg) { isDefaultOrg = defaultOrg; } }
// Contact Models
@JsonIgnoreProperties(ignoreUnknown = true)
class Contact {
private String contactId;
private String contactName;
private String companyName;
private boolean hasTransaction;
private String contactType;
private boolean isCrmCustomer;
private String primaryContactId;
private String paymentTerms;
private int paymentTermsLabel;
private String currencyId;
private String currencyCode;
private String currencySymbol;
private double outstandingReceivableAmount;
private double outstandingReceivableAmountBcy;
private double outstandingPayableAmount;
private double outstandingPayableAmountBcy;
private double unusedCreditsReceivableAmount;
private double unusedCreditsReceivableAmountBcy;
private double unusedCreditsPayableAmount;
private double unusedCreditsPayableAmountBcy;
private String status;
private boolean paymentReminderEnabled;
private String customFields;
private String billingAddress;
private String shippingAddress;
private List contactPersons;
private String defaultTaxes;
private String notes;
private String createdAt;
private String lastModifiedAt;
// Getters and setters public String getContactId() { return contactId; } public void setContactId(String contactId) { this.contactId = contactId; } public String getContactName() { return contactName; } public void setContactName(String contactName) { this.contactName = contactName; } public String getCompanyName() { return companyName; } public void setCompanyName(String companyName) { this.companyName = companyName; } public boolean isHasTransaction() { return hasTransaction; } public void setHasTransaction(boolean hasTransaction) { this.hasTransaction = hasTransaction; } public String getContactType() { return contactType; } public void setContactType(String contactType) { this.contactType = contactType; } public boolean isCrmCustomer() { return isCrmCustomer; } public void setCrmCustomer(boolean crmCustomer) { isCrmCustomer = crmCustomer; } public String getPrimaryContactId() { return primaryContactId; } public void setPrimaryContactId(String primaryContactId) { this.primaryContactId = primaryContactId; } public String getPaymentTerms() { return paymentTerms; } public void setPaymentTerms(String paymentTerms) { this.paymentTerms = paymentTerms; } public int getPaymentTermsLabel() { return paymentTermsLabel; } public void setPaymentTermsLabel(int paymentTermsLabel) { this.paymentTermsLabel = paymentTermsLabel; } public String getCurrencyId() { return currencyId; } public void setCurrencyId(String currencyId) { this.currencyId = currencyId; } public String getCurrencyCode() { return currencyCode; } public void setCurrencyCode(String currencyCode) { this.currencyCode = currencyCode; } public String getCurrencySymbol() { return currencySymbol; } public void setCurrencySymbol(String currencySymbol) { this.currencySymbol = currencySymbol; } public double getOutstandingReceivableAmount() { return outstandingReceivableAmount; } public void setOutstandingReceivableAmount(double outstandingReceivableAmount) { this.outstandingReceivableAmount = outstandingReceivableAmount; } public double getOutstandingReceivableAmountBcy() { return outstandingReceivableAmountBcy; } public void setOutstandingReceivableAmountBcy(double outstandingReceivableAmountBcy) { this.outstandingReceivableAmountBcy = outstandingReceivableAmountBcy; } public double getOutstandingPayableAmount() { return outstandingPayableAmount; } public void setOutstandingPayableAmount(double outstandingPayableAmount) { this.outstandingPayableAmount = outstandingPayableAmount; } public double getOutstandingPayableAmountBcy() { return outstandingPayableAmountBcy; } public void setOutstandingPayableAmountBcy(double outstandingPayableAmountBcy) { this.outstandingPayableAmountBcy = outstandingPayableAmountBcy; } public double getUnusedCreditsReceivableAmount() { return unusedCreditsReceivableAmount; } public void setUnusedCreditsReceivableAmount(double unusedCreditsReceivableAmount) { this.unusedCreditsReceivableAmount = unusedCreditsReceivableAmount; } public double getUnusedCreditsReceivableAmountBcy() { return unusedCreditsReceivableAmountBcy; } public void setUnusedCreditsReceivableAmountBcy(double unusedCreditsReceivableAmountBcy) { this.unusedCreditsReceivableAmountBcy = unusedCreditsReceivableAmountBcy; } public double getUnusedCreditsPayableAmount() { return unusedCreditsPayableAmount; } public void setUnusedCreditsPayableAmount(double unusedCreditsPayableAmount) { this.unusedCreditsPayableAmount = unusedCreditsPayableAmount; } public double getUnusedCreditsPayableAmountBcy() { return unusedCreditsPayableAmountBcy; } public void setUnusedCreditsPayableAmountBcy(double unusedCreditsPayableAmountBcy) { this.unusedCreditsPayableAmountBcy = unusedCreditsPayableAmountBcy; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public boolean isPaymentReminderEnabled() { return paymentReminderEnabled; } public void setPaymentReminderEnabled(boolean paymentReminderEnabled) { this.paymentReminderEnabled = paymentReminderEnabled; } public String getCustomFields() { return customFields; } public void setCustomFields(String customFields) { this.customFields = customFields; } public String getBillingAddress() { return billingAddress; } public void setBillingAddress(String billingAddress) { this.billingAddress = billingAddress; } public String getShippingAddress() { return shippingAddress; } public void setShippingAddress(String shippingAddress) { this.shippingAddress = shippingAddress; } public List<ContactPerson> getContactPersons() { return contactPersons; } public void setContactPersons(List<ContactPerson> contactPersons) { this.contactPersons = contactPersons; } public String getDefaultTaxes() { return defaultTaxes; } public void setDefaultTaxes(String defaultTaxes) { this.defaultTaxes = defaultTaxes; } public String getNotes() { return notes; } public void setNotes(String notes) { this.notes = notes; } public String getCreatedAt() { return createdAt; } public void setCreatedAt(String createdAt) { this.createdAt = createdAt; } public String getLastModifiedAt() { return lastModifiedAt; } public void setLastModifiedAt(String lastModifiedAt) { this.lastModifiedAt = lastModifiedAt; } }
@JsonIgnoreProperties(ignoreUnknown = true)
class ContactPerson {
private String contactPersonId;
private String salutation;
private String firstName;
private String lastName;
private String email;
private String phone;
private String mobile;
private boolean isPrimaryContact;
// Getters and setters public String getContactPersonId() { return contactPersonId; } public void setContactPersonId(String contactPersonId) { this.contactPersonId = contactPersonId; } public String getSalutation() { return salutation; } public void setSalutation(String salutation) { this.salutation = salutation; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public boolean isPrimaryContact() { return isPrimaryContact; } public void setPrimaryContact(boolean primaryContact) { isPrimaryContact = primaryContact; } }
// Invoice Models
@JsonIgnoreProperties(ignoreUnknown = true)
class Invoice {
private String invoiceId;
private String customerId;
private String customerName;
private String contactPersons;
private String invoiceNumber;
private String referenceNumber;
private String placeOfSupply;
private String gstTreatment;
private String gstNo;
private String date;
private String dueDate;
private String dueDays;
private String paymentTerms;
private int paymentTermsLabel;
private String currencyId;
private String currencyCode;
private String currencySymbol;
private double exchangeRate;
private double discount;
private boolean isDiscountBeforeTax;
private String discountType;
private String entityDiscount;
private String itemDiscount;
private String salespersonId;
private String salespersonName;
private String shippingCharge;
private String adjustment;
private String adjustmentDescription;
private double subTotal;
private double taxTotal;
private double total;
private double totalInWords;
private double balance;
private boolean hasAttachment;
private double pricePrecision;
private String paymentOptions;
private boolean allowPartialPayments;
private String customFields;
private String templateId;
private String templateName;
private String notes;
private String terms;
private String shippingAddress;
private String billingAddress;
private String templateType;
private String createdTime;
private String lastModifiedTime;
private String status;
private String invoiceUrl;
private List lineItems;
private List taxes;
private List payments;
private List customFieldHash;
// Getters and setters public String getInvoiceId() { return invoiceId; } public void setInvoiceId(String invoiceId) { this.invoiceId = invoiceId; } public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } public String getContactPersons() { return contactPersons; } public void setContactPersons(String contactPersons) { this.contactPersons = contactPersons; } public String getInvoiceNumber() { return invoiceNumber; } public void setInvoiceNumber(String invoiceNumber) { this.invoiceNumber = invoiceNumber; } public String getReferenceNumber() { return referenceNumber; } public void setReferenceNumber(String referenceNumber) { this.referenceNumber = referenceNumber; } public String getPlaceOfSupply() { return placeOfSupply; } public void setPlaceOfSupply(String placeOfSupply) { this.placeOfSupply = placeOfSupply; } public String getGstTreatment() { return gstTreatment; } public void setGstTreatment(String gstTreatment) { this.gstTreatment = gstTreatment; } public String getGstNo() { return gstNo; } public void setGstNo(String gstNo) { this.gstNo = gstNo; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getDueDate() { return dueDate; } public void setDueDate(String dueDate) { this.dueDate = dueDate; } public String getDueDays() { return dueDays; } public void setDueDays(String dueDays) { this.dueDays = dueDays; } public String getPaymentTerms() { return paymentTerms; } public void setPaymentTerms(String paymentTerms) { this.paymentTerms = paymentTerms; } public int getPaymentTermsLabel() { return paymentTermsLabel; } public void setPaymentTermsLabel(int paymentTermsLabel) { this.paymentTermsLabel = paymentTermsLabel; } public String getCurrencyId() { return currencyId; } public void setCurrencyId(String currencyId) { this.currencyId = currencyId; } public String getCurrencyCode() { return currencyCode; } public void setCurrencyCode(String currencyCode) { this.currencyCode = currencyCode; } public String getCurrencySymbol() { return currencySymbol; } public void setCurrencySymbol(String currencySymbol) { this.currencySymbol = currencySymbol; } public double getExchangeRate() { return exchangeRate; } public void setExchangeRate(double exchangeRate) { this.exchangeRate = exchangeRate; } public double getDiscount() { return discount; } public void setDiscount(double discount) { this.discount = discount; } public boolean isDiscountBeforeTax() { return isDiscountBeforeTax; } public void setDiscountBeforeTax(boolean discountBeforeTax) { isDiscountBeforeTax = discountBeforeTax; } public String getDiscountType() { return discountType; } public void setDiscountType(String discountType) { this.discountType = discountType; } public String getEntityDiscount() { return entityDiscount; } public void setEntityDiscount(String entityDiscount) { this.entityDiscount = entityDiscount; } public String getItemDiscount() { return itemDiscount; } public void setItemDiscount(String itemDiscount) { this.itemDiscount = itemDiscount; } public String getSalespersonId() { return salespersonId; } public void setSalespersonId(String salespersonId) { this.salespersonId = salespersonId; } public String getSalespersonName() { return salespersonName; } public void setSalespersonName(String salespersonName) { this.salespersonName = salespersonName; } public String getShippingCharge() { return shippingCharge; } public void setShippingCharge(String shippingCharge) { this.shippingCharge = shippingCharge; } public String getAdjustment() { return adjustment; } public void setAdjustment(String adjustment) { this.adjustment = adjustment; } public String getAdjustmentDescription() { return adjustmentDescription; } public void setAdjustmentDescription(String adjustmentDescription) { this.adjustmentDescription = adjustmentDescription; } public double getSubTotal() { return subTotal; } public void setSubTotal(double subTotal) { this.subTotal = subTotal; } public double getTaxTotal() { return taxTotal; } public void setTaxTotal(double taxTotal) { this.taxTotal = taxTotal; } public double getTotal() { return total; } public void setTotal(double total) { this.total = total; } public double getTotalInWords() { return totalInWords; } public void setTotalInWords(double totalInWords) { this.totalInWords = totalInWords; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public boolean isHasAttachment() { return hasAttachment; } public void setHasAttachment(boolean hasAttachment) { this.hasAttachment = hasAttachment; } public double getPricePrecision() { return pricePrecision; } public void setPricePrecision(double pricePrecision) { this.pricePrecision = pricePrecision; } Java Observability, Logging Intelligence & AI-Driven Monitoring (APM, Tracing, Logs & Anomaly Detection)
https://macronepal.com/blog/beyond-metrics-observing-serverless-and-traditional-java-applications-with-thundra-apm/
Explains using Thundra APM to observe both serverless and traditional Java applications by combining tracing, metrics, and logs into a unified observability platform for faster debugging and performance insights.
https://macronepal.com/blog/dynatrace-oneagent-in-java-2/
Explains Dynatrace OneAgent for Java, which automatically instruments JVM applications to capture metrics, traces, and logs, enabling full-stack monitoring and root-cause analysis with minimal configuration.
https://macronepal.com/blog/lightstep-java-sdk-distributed-tracing-and-observability-implementation/
Explains Lightstep Java SDK for distributed tracing, helping developers track requests across microservices and identify latency issues using OpenTelemetry-based observability.
https://macronepal.com/blog/honeycomb-io-beeline-for-java-complete-guide-2/
Explains Honeycomb Beeline for Java, which provides high-cardinality observability and deep query capabilities to understand complex system behavior and debug distributed systems efficiently.
https://macronepal.com/blog/lumigo-for-serverless-in-java-complete-distributed-tracing-guide-2/
Explains Lumigo for Java serverless applications, offering automatic distributed tracing, log correlation, and error tracking to simplify debugging in cloud-native environments. (Lumigo Docs)
https://macronepal.com/blog/from-noise-to-signals-implementing-log-anomaly-detection-in-java-applications/
Explains how to detect anomalies in Java logs using behavioral patterns and machine learning techniques to separate meaningful incidents from noisy log data and improve incident response.
https://macronepal.com/blog/ai-powered-log-analysis-in-java-from-reactive-debugging-to-proactive-insights/
Explains AI-driven log analysis for Java applications, shifting from manual debugging to predictive insights that identify issues early and improve system reliability using intelligent log processing.
https://macronepal.com/blog/titliel-java-logging-best-practices/
Explains best practices for Java logging, focusing on structured logs, proper log levels, performance optimization, and ensuring logs are useful for debugging and observability systems.
https://macronepal.com/blog/seeking-a-loguru-for-java-the-quest-for-elegant-and-simple-logging/
Explains the search for simpler, more elegant logging frameworks in Java, comparing modern logging approaches that aim to reduce complexity while improving readability and developer experience.