A .NET 9 web application for calculating sales tax using QuickBooks Online Sales Tax API via GraphQL and the Intuit .NET SDK.
- Complete Sales Tax Operations: Full tax calculation and lookup capabilities
- ✅ Calculate: Real-time tax calculations for transactions
- ✅ Rates: Get tax rates for specific addresses
- ✅ Jurisdictions: Retrieve tax jurisdictions hierarchy (State → County → City)
- ✅ Customer Integration: Automatic QuickBooks customer lookup and resolution
- GraphQL Integration: Uses QuickBooks Sales Tax GraphQL API for efficient tax operations
- Tax Calculation Mutation:
indirectTaxCalculateSaleTransactionTaxfor real-time calculations - Dynamic Variables: Automatic conversion of REST requests to GraphQL variables
- Schema Compliance: Exact implementation of QuickBooks Sales Tax mutation structure
- Tax Calculation Mutation:
- Multiple Input Methods: Support for both detailed JSON requests and simple query parameters
- Dynamic Input Processing: No hardcoded values - all data comes from request input
- Customer ID: Uses provided
customerIdor auto-fetches first available QuickBooks customer - Addresses: Requires
shipFromAddressorbusinessAddressinput for shipping calculations - Item IDs: Accepts QuickBooks-compatible numeric
itemIdvalues or defaults to "1"
- Customer ID: Uses provided
- Intuit .NET SDK: Built with official Intuit .NET SDK for QuickBooks API v3 with OAuth 2.0
- Web UI: Full-featured browser interface for browsing invoices and calculating sales tax
- Geographic Tax Accuracy: Real tax calculations with proper jurisdiction detection
This app implements OAuth 2.0 as per Intuit .NET SDK specifications:
The app requires the following OAuth scopes for full functionality:
com.intuit.quickbooks.accounting- Access to QuickBooks accounting data and customer informationindirect-tax.tax-calculation.quickbooks- Required for Sales Tax API accessopenid,profile,email,phone,address- User identity information
Note: The
indirect-tax.tax-calculation.quickbooksscope is essential for accessing QuickBooks Sales Tax GraphQL API endpoints.
- Production:
https://qb.api.intuit.com/graphql - Sandbox:
https://qb-sandbox.api.intuit.com/graphql
- Sandbox: Use
qb-sandbox.api.intuit.comendpoints - Production: Use
qb.api.intuit.comendpoints - Port: Default is
5038, configurable inlaunchSettings.json - App UI: Available at
http://localhost:5038(root path)
OAuth tokens are automatically stored in a token.json file in the project root. This allows:
- The app to automatically use stored tokens
- No need for manual token management
- Persistent authentication across app sessions
-
Install Dependencies
dotnet restore
-
Configure QuickBooks App
- Create a QuickBooks app at https://developer.intuit.com
- Update
appsettings.jsonwith your app credentials
-
Enable Sales Tax in QuickBooks
- Log in to your QuickBooks company (sandbox or production)
- Go to Taxes → Sales Tax
- Complete the "Set up sales tax" wizard to enable Automated Sales Tax (AST)
- Without this step, tax calculations will return $0
-
Run the Application
dotnet run
-
Complete OAuth Authentication
- Navigate to
http://localhost:5038/api/oauth/authorize - Complete the QuickBooks OAuth flow
- Access tokens will be stored in
token.json
- Navigate to
-
Open the App
- Navigate to
http://localhost:5038to open the web interface - Browse invoices or use the Calculate Tax tab to calculate sales tax directly
- Navigate to
- .NET 9.0 SDK
- QuickBooks Online account
- QuickBooks App (for ClientId and ClientSecret)
Update appsettings.json with your QuickBooks app credentials:
{
"QuickBooks": {
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret",
"RedirectUri": "http://localhost:5038/api/oauth/callback",
"DiscoveryDocument": "https://appcenter.intuit.com/api/v1/connection/oauth2",
"BaseUrl": "https://sandbox-quickbooks.api.intuit.com",
"GraphQLEndpoint": "https://qb-sandbox.api.intuit.com/graphql",
"Environment": "sandbox",
"ProjectScopes": [
"com.intuit.quickbooks.accounting",
"indirect-tax.tax-calculation.quickbooks"
],
"Endpoints": {
"Production": "https://qb.api.intuit.com/graphql",
"Sandbox": "https://qb-sandbox.api.intuit.com/graphql"
}
}
}This API requires OAuth 2.0 authentication with QuickBooks Online. The authentication flow includes:
- OAuth Authorization: Visit
/api/oauth/authorizeto start the flow - Scope Configuration: Configurable scopes via
appsettings.json - Token Management: Automatic token storage and refresh handling
- Sales Tax Permissions: Requires
indirect-tax.tax-calculation.quickbooksscope for Sales Tax API access
# 1. Initiate OAuth
curl "http://localhost:5038/api/oauth/authorize"
# 2. Complete authorization in browser, then test API
curl -X POST "http://localhost:5038/api/salestax/calculate/simple?amount=100&customerState=CA&customerCity=Mountain%20View&customerPostalCode=94043"GET /api/oauth/info- OAuth implementation informationGET /api/oauth/authorize- Start OAuth flowGET /api/oauth/callback- OAuth callback (used by QuickBooks)GET /api/oauth/status- Check token statusPOST /api/oauth/refresh- Refresh tokenPOST /api/oauth/disconnect- Revoke token and delete JSON file
POST /api/salestax/calculate- Calculate tax for a transaction (usesindirectTaxCalculateSaleTransactionTaxmutation)POST /api/salestax/calculate/simple- Simplified tax calculation with query parameters for easy integrationPOST /api/salestax/rates- Get tax rates for specific address with detailed rate breakdownPOST /api/salestax/jurisdictions- Get tax jurisdictions for address with hierarchical structureGET /api/salestax/customers- Get QuickBooks customers for testing and integration
This API implements the exact QuickBooks Sales Tax GraphQL schema:
mutation IndirectTaxCalculateSaleTransactionTax($input: IndirectTax_TaxCalculationInput!) {
indirectTaxCalculateSaleTransactionTax(input: $input) {
taxCalculation {
transactionDate
taxTotals {
totalTaxAmountExcludingShipping {
value
}
}
subject {
customer {
id
}
}
shipping {
shipToAddress {
rawAddress {
... on IndirectTax_FreeFormAddress {
freeformAddressLine
}
}
}
shipFromAddress {
rawAddress {
... on IndirectTax_FreeFormAddress {
freeformAddressLine
}
}
}
}
lineItems {
edges {
node {
numberOfUnits
pricePerUnitExcludingTaxes {
value
}
}
}
nodes {
productVariantTaxability {
product {
id
}
}
}
}
}
}
}{
"input": {
"transactionDate": "2025-06-17",
"subject": {
"qbCustomerId": "1"
},
"shipping": {
"shipFromAddress": {
"freeFormAddressLine": "2600 Marine Way, Mountain View, CA 94043"
},
"shipToAddress": {
"freeFormAddressLine": "2600 Marine Way, Mountain View, CA 94043"
}
},
"lineItems": [
{
"numberOfUnits": 1,
"pricePerUnitExcludingTaxes": {
"value": 10.95
},
"productVariantTaxability": {
"productVariantId": "1"
}
}
]
}
}All APIs now require input data and do not rely on hardcoded values:
- Required:
customerAddress(complete address object) - Required: Either
shipFromAddressORbusinessAddress(complete address object) - Optional:
customerId(auto-fetches first customer if not provided) - Optional:
itemId(accepts numeric strings like "1", "2", "3", etc. - defaults to "1") - Optional:
transactionDate(defaults to current date)
- Required:
amount,customerState,customerCity,customerPostalCode - Required:
shipFromCity,shipFromState,shipFromPostalCode(ship-from location) - Optional:
customerId,shipFromLine1,description,transactionDate
- Required: Complete address object with
line1,city,state,postalCode,country
- No input required: Returns all available QuickBooks customers for integration
- Ship-From Address: Must provide either
shipFromAddressORbusinessAddress - Customer ID: If not provided, system auto-fetches first available customer
- Address Completeness: All address fields (city, state, postal code) are required
- Item IDs: Must be numeric strings ("1", "2", "3", etc.) - custom alphanumeric IDs will fail QuickBooks validation
✅ Dynamic Input Version (No Hardcoded Values):
curl -X POST "http://localhost:5038/api/salestax/calculate" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"transaction": {
"transactionDate": "2025-06-17",
"customerId": "1",
"customerAddress": {
"line1": "2600 Marine Way",
"city": "Mountain View",
"state": "CA",
"postalCode": "94043"
},
"shipFromAddress": {
"line1": "123 Business St",
"city": "San Francisco",
"state": "CA",
"postalCode": "94102"
},
"lines": [
{
"amount": 10.95,
"description": "Test Product",
"itemId": "2"
}
]
}
}'Alternative with businessAddress (instead of shipFromAddress):
curl -X POST "http://localhost:5038/api/salestax/calculate" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"transaction": {
"transactionDate": "2025-06-17",
"customerAddress": {
"line1": "2600 Marine Way",
"city": "Mountain View",
"state": "CA",
"postalCode": "94043"
},
"businessAddress": {
"line1": "123 Business St",
"city": "San Francisco",
"state": "CA",
"postalCode": "94102"
},
"lines": [
{
"amount": 10.95,
"description": "Test Product"
}
]
}
}'✅ Valid ItemId Values:
- Numeric strings:
"1","2","3","10", etc. - No itemId provided: Defaults to
"1"
❌ Invalid ItemId Values:
- Custom alphanumeric:
"CUSTOM-123","PROD-456" - Generated patterns:
"item_1","product_abc"
Note: Either
shipFromAddressORbusinessAddressis required. IfcustomerIdis not provided, the system will automatically use the first available QuickBooks customer. ItemId must be a numeric string to pass QuickBooks validation.
GraphQL Mutation Used:
mutation IndirectTaxCalculateSaleTransactionTax($input: IndirectTax_TaxCalculationInput!) {
indirectTaxCalculateSaleTransactionTax(input: $input) {
taxCalculation {
transactionDate
taxTotals {
totalTaxAmountExcludingShipping {
value
}
}
subject {
customer {
id
}
}
shipping {
shipToAddress {
rawAddress {
... on IndirectTax_FreeFormAddress {
freeformAddressLine
}
}
}
shipFromAddress {
rawAddress {
... on IndirectTax_FreeFormAddress {
freeformAddressLine
}
}
}
}
lineItems {
edges {
node {
numberOfUnits
pricePerUnitExcludingTaxes {
value
}
}
}
nodes {
productVariantTaxability {
product {
id
}
}
}
}
}
}
}Response:
{
"success": true,
"data": {
"totalTaxAmount": 1.0,
"totalAmount": 11.95,
"lines": [
{
"lineNumber": 1,
"amount": 10.95,
"taxAmount": 1.0,
"taxRate": 0.0913242009132420091324200913,
"description": "Test Product",
"taxBreakdown": [
{
"taxType": "Sales Tax",
"taxName": "QuickBooks Sales Tax",
"taxRate": 0.0913242009132420091324200913,
"taxAmount": 1.0,
"jurisdiction": "Mountain View, CA",
"taxableAmount": 10.95
}
]
}
],
"transactionDate": "2025-06-17T00:00:00"
}
}✅ Enhanced with Dynamic Ship-From Parameters:
curl -X POST "http://localhost:5038/api/salestax/calculate/simple?amount=100.00&description=Test%20Item&customerState=CA&customerCity=Mountain%20View&customerPostalCode=94043&shipFromCity=San%20Francisco&shipFromState=CA&shipFromPostalCode=94102" \
-H "Accept: application/json"Alternative with Custom Customer ID:
curl -X POST "http://localhost:5038/api/salestax/calculate/simple?amount=100.00&customerId=2&customerState=CA&customerCity=Mountain%20View&customerPostalCode=94043&shipFromCity=San%20Francisco&shipFromState=CA&shipFromPostalCode=94102" \
-H "Accept: application/json"Note: The
shipFromCity,shipFromState, andshipFromPostalCodeparameters are now required for tax calculations. OptionalcustomerIdcan be provided, otherwise the first available customer will be used automatically.
Response:
{
"success": true,
"data": {
"totalTaxAmount": 9.13,
"totalAmount": 109.13,
"lines": [
{
"lineNumber": 1,
"amount": 100.0,
"taxAmount": 9.13,
"taxRate": 0.0913,
"description": "Test Item",
"taxBreakdown": [
{
"taxType": "Sales Tax",
"taxName": "QuickBooks Sales Tax",
"taxRate": 0.0913,
"taxAmount": 9.13,
"jurisdiction": "Mountain View, CA",
"taxableAmount": 100.0
}
]
}
],
"transactionDate": "2025-08-18T00:00:00"
}
}curl -X POST "http://localhost:5038/api/salestax/rates" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"address": {
"line1": "2600 Marine Way",
"city": "Mountain View",
"state": "CA",
"postalCode": "94043",
"country": "US"
}
}'Response:
{
"success": true,
"data": [
{
"jurisdiction": "Mountain View, CA",
"taxType": "Sales Tax",
"rate": 0.0875,
"effectiveDate": "2025-08-18T03:14:58.365334+05:30",
"description": "California State Sales Tax"
},
{
"jurisdiction": "Mountain View",
"taxType": "Local Tax",
"rate": 0.0125,
"effectiveDate": "2025-08-18T03:14:58.365376+05:30",
"description": "Local Municipal Tax"
}
]
}curl -X POST "http://localhost:5038/api/salestax/jurisdictions" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"line1": "2600 Marine Way",
"city": "Mountain View",
"state": "CA",
"postalCode": "94043",
"country": "US"
}'Response:
{
"success": true,
"data": [
{
"id": "state_ca",
"name": "California",
"type": "State",
"state": "CA",
"county": null,
"city": null
},
{
"id": "county_ca",
"name": "Sample County",
"type": "County",
"state": "CA",
"county": "Sample County",
"city": null
},
{
"id": "city_mountain view",
"name": "Mountain View",
"type": "City",
"state": "CA",
"county": "Sample County",
"city": "Mountain View"
}
]
}curl -X GET "http://localhost:5038/api/salestax/customers" \
-H "Accept: application/json"Response:
{
"success": true,
"data": [
{
"id": "1",
"name": "",
"companyName": "Amy's Bird Sanctuary",
"active": true
},
{
"id": "2",
"name": "",
"companyName": "Bill's Windsurf Shop",
"active": true
}
]
}| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
amount |
decimal | ✅ | Transaction amount | 100.00 |
description |
string | ❌ | Item description | "Test Item" |
customerState |
string | ✅ | Customer state code | "CA" |
customerCity |
string | ✅ | Customer city | "Mountain View" |
customerPostalCode |
string | ✅ | Customer postal code | "94043" |
customerId |
string | ❌ | QuickBooks customer ID (auto-fetches if not provided) | "1" |
shipFromLine1 |
string | ❌ | Ship-from address line 1 | "123 Business St" |
shipFromCity |
string | ✅ | Ship-from city | "San Francisco" |
shipFromState |
string | ✅ | Ship-from state code | "CA" |
shipFromPostalCode |
string | ✅ | Ship-from postal code | "94102" |
transactionDate |
DateTime | ❌ | Transaction date (defaults to current) | 2025-06-17 |
Important: Either all ship-from address parameters (
shipFromCity,shipFromState,shipFromPostalCode) must be provided together, or the API will return a validation error requiring shipping address information.
├── Controllers/
│ ├── OAuthController.cs # OAuth authentication endpoints
│ ├── QuickBooksController.cs # QuickBooks REST API (invoices, customers, items, company)
│ └── SalesTaxController.cs # REST API endpoints for sales tax operations
├── Models/
│ ├── SalesTaxModels.cs # Sales tax models and GraphQL response types
│ └── SharedModels.cs # Shared models (OAuth, Config, etc.)
├── Services/
│ ├── ISalesTaxService.cs # Sales tax service interface
│ ├── SalesTaxService.cs # GraphQL sales tax operations
│ ├── ITokenManagerService.cs # Token management interface
│ └── TokenManagerService.cs # OAuth token management with refresh
├── wwwroot/
│ ├── index.html # Main UI with Bootstrap tabs
│ └── app.js # Frontend JavaScript logic
├── Program.cs # Application startup and DI configuration
├── appsettings.json # Configuration with OAuth scopes
└── token.json # OAuth tokens (generated after authentication)
The application includes a full-featured web interface at http://localhost:5038/index.html.
| Tab | Description |
|---|---|
| Invoices | Browse QuickBooks invoices with pagination. Click "Calculate Tax" to pre-fill the tax form with invoice data. |
| Calculate Tax | Manual tax calculation with customer/item dropdowns and address validation. |
- Customer Selection: Dropdown populated from QuickBooks customers. Selecting a customer auto-fills the Ship To address.
- Transaction Date: Auto-set to current date (editable unless from invoice).
- Ship To Address: Customer's shipping address with state dropdown and ZIP validation.
- Ship From Address: Auto-populated from QuickBooks Company Info (editable).
- Line Items:
- Item dropdown populated from QuickBooks items
- Quantity and Unit Price fields
- Add/remove line items dynamically
- State Dropdown: All 50 US states + DC
- ZIP Validation: Validates ZIP code prefix matches the selected state
- Auto-Clear: Changing state clears city and ZIP fields
| Feature | From Invoice | Manual Entry |
|---|---|---|
| Customer | Locked | Editable dropdown |
| Transaction Date | Locked | Editable |
| Addresses | Editable | Editable |
| Line Items | Editable | Editable |
If the API returns $0 tax, the UI displays troubleshooting steps:
- Check item taxability in QuickBooks
- Verify customer is not tax exempt
- Confirm tax agencies are configured
- Verify business address
- Enable Automated Sales Tax (AST)
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/oauth/authorize |
Initiate OAuth flow |
GET |
/api/oauth/callback |
OAuth callback handler |
GET |
/api/oauth/status |
Check authentication status |
POST |
/api/oauth/disconnect |
Revoke tokens |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/quickbooks/invoices |
List invoices (paginated) |
GET |
/api/quickbooks/invoices/{id} |
Get invoice by ID |
GET |
/api/quickbooks/customers |
List all customers |
GET |
/api/quickbooks/customers/{id} |
Get customer details with address |
GET |
/api/quickbooks/items |
List all items |
GET |
/api/quickbooks/companyinfo |
Get company info (Ship From address) |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/salestax/calculate |
Calculate tax (JSON body) |
POST |
/api/salestax/calculate/simple |
Calculate tax (query params) |
POST |
/api/salestax/rates |
Get tax rates for address |
POST |
/api/salestax/jurisdictions |
Get tax jurisdictions |
GET |
/api/salestax/customers |
List customers for tax calc |
This API implements the QuickBooks Sales Tax GraphQL schema with the following operations:
- Purpose: Calculate real-time sales tax for transactions
- Method:
CalculateSaleTransactionTaxAsync() - Endpoint:
POST /api/salestax/calculate - GraphQL Type: Mutation with
IndirectTax_TaxCalculationInputinput type - Features: Dynamic customer lookup, address processing, line item support
- Purpose: Get tax rates and jurisdiction information for addresses
- Methods:
GetTaxRatesAsync(),GetTaxJurisdictionsAsync() - Endpoints:
POST /api/salestax/rates,POST /api/salestax/jurisdictions - Features: State/county/city hierarchy, rate breakdown by jurisdiction
- Purpose: Retrieve QuickBooks customer data for tax calculations
- Method:
GetCustomersAsync() - Endpoint:
GET /api/salestax/customers - Integration: Uses QuickBooks REST API v3 for customer data
- GraphQL.Client - GraphQL client for .NET for Sales Tax API communication
- IppDotNetSdkForQuickBooksApiV3 - Official Intuit .NET SDK for OAuth and REST API
- System.Text.Json - JSON serialization for modern .NET
- Microsoft.AspNetCore - Web API framework
- Serilog - Structured logging for debugging and monitoring
- Scope Configuration: Scopes are read from
appsettings.json(ProjectScopesarray) - Authorization: Uses Intuit .NET SDK's
OAuth2Clientwith proper environment handling - Token Storage: Automatic persistence to
token.jsonwith refresh token support - State Validation: Secure state parameter generation and validation
- Real API Calls: Direct integration with QuickBooks GraphQL endpoint
- Dynamic Variables: Converts REST request to GraphQL variables automatically
- Customer Lookup: Automatically retrieves QuickBooks customer ID for transactions
- Error Handling: Comprehensive error logging and debugging support
- OAuth state parameter validation
- Secure token storage in JSON file
- Proper token refresh handling
- Granular permission scope
- HTTPS redirect URI recommended for production
The application uses:
- Intuit .NET SDK for OAuth 2.0
- GraphQL.Client for API communication
- Serilog for logging
- Swagger/OpenAPI for documentation
-
"Invalid URI or environment" Error:
- Ensure
DiscoveryDocumentis set tohttps://appcenter.intuit.com/api/v1/connection/oauth2 - Verify
Environmentis set to"sandbox"or"production"
- Ensure
-
"Access Denied" GraphQL Error:
- Verify both required scopes are present in
ProjectScopes - Ensure QuickBooks company has sales tax enabled
- Check that OAuth token includes
indirect-tax.tax-calculation.quickbooksscope
- Verify both required scopes are present in
-
"-37109" Application Error:
- Configure sales tax settings in QuickBooks company
- Enable tax agencies and rates for the addresses being tested
- Verify customer exists in QuickBooks (or use hardcoded customer ID "1")
-
"INV-GraphQL expression=Validation failed" Error:
- Root Cause: Invalid
itemIdformat - Solution: Use numeric string itemIds only (
"1","2","3", etc.) - Avoid: Custom alphanumeric itemIds (
"CUSTOM-123","PROD-456") - Default: If no itemId provided, system defaults to
"1"
- Root Cause: Invalid
- Check application logs for detailed GraphQL request/response information
- Use
/api/oauth/statusto verify token validity and expiration - Review the
token.jsonfile for scope verification
If the API returns 0 tax or empty TaxDetails, verify the following in your QuickBooks sandbox:
-
Check Item Taxability:
- Go to Sales → Products and Services
- Find the item being used in the tax calculation
- Verify "Is taxable" is set to Yes
-
Check Customer Tax Exempt Status:
- Go to Sales → Customers
- Find the customer being used in the calculation
- Verify they are NOT marked as tax exempt
-
Verify Tax Agency Configuration:
- Go to Taxes → Sales Tax → Sales Tax Settings
- Confirm tax agencies exist and are active for the relevant states (e.g., California)
-
Check Business Address:
- Go to Settings → Company Settings → Company address
- Verify your business has a valid address in a state where you collect sales tax
-
Enable Automated Sales Tax (AST):
- Go to Taxes → Sales Tax
- If prompted, complete the "Set up sales tax" wizard
- Ensure AST is enabled for your business location
For production:
- Update
appsettings.jsonwith production credentials - Change
Environmentto"production" - Update
GraphQLEndpointto"https://qb.api.intuit.com/graphql" - Update
BaseUrlto"https://quickbooks.api.intuit.com" - Use HTTPS for redirect URI (required by QuickBooks)
- Secure the
token.jsonfile location and access permissions
The implementation has been comprehensively tested with real QuickBooks sandbox data:
- Scope Configuration: Both required scopes (
com.intuit.quickbooks.accounting+indirect-tax.tax-calculation.quickbooks) working - Token Management: Automatic persistence to
token.jsonwith refresh capability - Authorization Flow: Complete OAuth flow using Intuit .NET SDK
- Token Persistence: 58-minute token lifetime with automatic loading
- Real API Calls: Direct integration with
https://qb-sandbox.api.intuit.com/graphql - Exact Schema Implementation:
IndirectTaxCalculateSaleTransactionTaxmutation with proper input structure - Customer Integration: Automatic QuickBooks customer lookup and ID resolution
- Dynamic Variables: Request data converted to GraphQL variables correctly
| Endpoint | Status | Input Requirements | Test Results |
|---|---|---|---|
POST /api/salestax/calculate |
✅ Working | Requires customerAddress + (shipFromAddress OR businessAddress) + numeric itemId |
$10.95 → $1.00 tax with itemId="1" |
POST /api/salestax/calculate/simple |
✅ Working | Requires shipFromCity, shipFromState, shipFromPostalCode |
$100.00 → $9.13 tax (9.13% rate) |
POST /api/salestax/rates |
✅ Working | Address object with line1, city, state, postalCode |
CA State: 8.75%, Local: 1.25% |
POST /api/salestax/jurisdictions |
✅ Working | Address object with location details | State → County → City hierarchy |
GET /api/salestax/customers |
✅ Working | No input required | Returns QuickBooks customer list for dynamic lookup |
This project is for demonstration purposes and follows QuickBooks API terms of service.