ASP.NET Core Minimal API for creating invoices and credit notes through QuickBooks Online API. This project provides a clean, organized REST API for integrating with Intuit's QuickBooks Online platform.
-
Clone and navigate:
git clone <repository-url> cd test-intuint-invoicing-api/test-intuint-invoicing-api
-
Set up configuration:
cp appsettings.json.example appsettings.json # Edit appsettings.json with your Intuit credentials (see below) -
Install and run:
dotnet restore dotnet run
-
Get your Intuit credentials:
- Register at Intuit Developer Portal
- Create an app and get Client ID & Client Secret
- Add redirect URI:
http://localhost:5000/auth/callbackin Developer Portal
-
Authorize and get Company ID:
- Visit:
http://localhost:5000/auth/authorizein your browser - Complete OAuth flow
- Copy the
realmId(Company ID) from the callback page
- Visit:
-
Start testing:
# List all invoices ./scripts/list-invoices.sh YOUR_REALM_ID # Create an invoice ./scripts/create-invoice.sh "Customer Name" YOUR_REALM_ID
📖 For detailed setup instructions, see Getting Started section below.
- OAuth 2.0 authentication with Intuit
- Create invoices programmatically with automatic customer creation
- Create credit notes to cancel/adjust invoices
- List all invoices and credit notes with summary statistics
- Retrieve invoice and credit note details by ID
- Settle invoices using credit note + payment hybrid approach
- Token refresh mechanism with persistent storage
- Idempotency checks to prevent duplicate invoices
- Health check endpoints (application and QuickBooks API connectivity)
- Request validation middleware (automatic companyId and OAuth token validation)
- Correlation ID tracking for better request traceability
- Automatic retry logic with exponential backoff for transient failures
- In-memory caching for customer lookups
- Swagger UI documentation
- Comprehensive shell scripts for easy testing
- .NET 9.0 SDK or later
- Intuit Developer account
- QuickBooks Online sandbox company (for testing)
jq(optional but recommended) - For better JSON formatting in shell scripts- Install on Linux:
apt-get update && apt-get install -y jq - Install on macOS:
brew install jq - Install on Windows: Download from jq official site
- Install on Linux:
test-intuint-invoicing-api/
├── Endpoints/ # API endpoint handlers (controller-style)
│ ├── AuthEndpoints.cs # OAuth authentication endpoints
│ ├── InvoiceEndpoints.cs # Invoice CRUD operations
│ ├── CreditNoteEndpoints.cs # Credit note operations
│ └── HealthEndpoints.cs # Health check endpoints
├── Models/ # Data models and DTOs
│ ├── ApiResponse.cs # Standard API response wrapper
│ ├── InvoiceModels.cs # Invoice and credit memo models
│ └── IntuitSettings.cs # Configuration models
├── Services/ # Business logic services
│ ├── IntuitOAuthService.cs # OAuth 2.0 flow handling
│ └── QuickBooksApiClient.cs # QuickBooks API client
├── Middleware/ # ASP.NET Core middleware
│ ├── CorrelationIdMiddleware.cs # Correlation ID tracking
│ └── RequestValidationMiddleware.cs # Request validation
├── Extensions/ # Extension methods
│ ├── InvoiceExtensions.cs # Invoice-related extensions
│ └── LoggerExtensions.cs # Structured logging extensions
├── Helpers/ # Helper utilities
│ └── RetryHelper.cs # Retry logic with exponential backoff
├── Program.cs # Application entry point
├── appsettings.json # Configuration (create from appsettings.json.example)
├── appsettings.json.example # Configuration template (copy to appsettings.json)
└── scripts/ # Shell scripts for testing
├── create-invoice.sh
├── list-invoices.sh
├── get-invoice.sh
├── settle-invoice.sh
├── create-credit-note.sh
├── list-credit-notes.sh
└── get-credit-note.sh
git clone <repository-url>
cd test-intuint-invoicing-api/test-intuint-invoicing-apidotnet restore- Register your app at Intuit Developer Portal
- Create a new app and note your Client ID and Client Secret
- Add Redirect URI in Developer Portal:
- Go to your app → Settings tab → Redirect URIs section
- Make sure you're in Development mode (toggle at top)
- Click "Add URI" button
- CRITICAL: Enter exactly:
http://localhost:5000/auth/callback- ✅ Use
http://(NOThttps://) - ✅ Use port
5000(NOT5001) - ✅ Must match EXACTLY:
http://localhost:5000/auth/callback
- ✅ Use
- Common mistakes to avoid:
- ❌
https://localhost:5000/auth/callback(wrong protocol - using HTTPS) - ❌
http://localhost:5001/auth/callback(wrong port) - ❌
https://localhost:5001/auth/callback(wrong protocol AND port)
- ❌
- Click Save
- Wait 2-3 minutes for changes to propagate
-
Copy the example configuration file:
cd test-intuint-invoicing-api cp appsettings.json.example appsettings.json -
Edit
appsettings.jsonand add your credentials:{ "Intuit": { "ClientId": "YOUR_CLIENT_ID_HERE", "ClientSecret": "YOUR_CLIENT_SECRET_HERE", "RedirectUri": "http://localhost:5000/auth/callback", "Environment": "sandbox", "BaseUrl": "https://sandbox-quickbooks.api.intuit.com", "AuthorizationUrl": "https://appcenter.intuit.com/connect/oauth2", "TokenUrl": "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer" } } -
Replace the placeholders:
- Replace
YOUR_CLIENT_ID_HEREwith your actual Client ID from Intuit Developer Portal - Replace
YOUR_CLIENT_SECRET_HEREwith your actual Client Secret - Verify
RedirectUrimatches exactly what you added in the Developer Portal
- Replace
Important Security Note:
⚠️ Never commitappsettings.jsonto version control (it's already in.gitignore)- ✅ The
appsettings.json.examplefile is safe to commit (contains no secrets) - ✅ Each developer should create their own
appsettings.jsonfrom the example
dotnet runThe API will be available at https://localhost:5001 (or the port shown in your terminal).
Check that your configuration is correct:
# Verify the app builds successfully
dotnet build
# Check health endpoint
curl -k https://localhost:5001/healthIn development mode, navigate to:
- Swagger UI:
https://localhost:5001/swagger - OpenAPI spec:
https://localhost:5001/openapi/v1.json
-
Start the application first:
cd test-intuint-invoicing-api dotnet runThe app will run on
http://localhost:5000(HTTP) andhttps://localhost:5001(HTTPS) -
Navigate to authorize endpoint:
- Open in browser:
http://localhost:5000/auth/authorize - Or use:
https://localhost:5001/auth/authorize(if HTTPS is working)
- Open in browser:
-
Complete OAuth flow:
- You'll be redirected to Intuit's authorization page
- Log in and authorize the application
- You'll be redirected back to
/auth/callbackwithcode,state, andrealmIdparameters
-
Get your Company ID:
- The callback will display a beautiful HTML page with your Company ID (realmId)
- SAVE THIS VALUE - you'll need it for all API calls
- Copy the ready-to-use curl commands shown on the page
-
Tokens are automatically stored for the
realmId(company ID)
IMPORTANT: You must complete OAuth authorization BEFORE using the API endpoints!
All invoice and credit note endpoints require:
companyIdquery parameter - This is therealmIdfrom the OAuth callback URL- Example:
?companyId=9341455792225805
- Example:
- Valid access token (stored automatically after OAuth)
If you get "401 Unauthorized" or "No OAuth tokens found":
- You need to complete the OAuth flow first
- Visit:
http://localhost:5000/auth/authorizein your browser - Complete the authorization
- Copy the
realmId(Company ID) from the callback page - Then use that
realmIdas thecompanyIdparameter in API calls
After authorization, you'll see a response like:
{
"Success": true,
"Message": "OAuth authorization successful! Use the companyId below for API calls.",
"CompanyId": "9341455792225805",
"RealmId": "9341455792225805",
"Note": "Use companyId=9341455792225805 as query parameter in all API calls"
}Important: Copy the CompanyId value and use it in all subsequent API calls as the companyId query parameter.
If your access token expires, use the refresh endpoint:
POST /auth/refresh
Content-Type: application/json
{
"RefreshToken": "your-refresh-token"
}curl -X GET http://localhost:5000/healthNote: Use http://localhost:5000 (HTTP), not HTTPS. No -k flag needed for HTTP.
Response: 200 OK with application health status
curl -X GET "http://localhost:5000/health/quickbooks?companyId=YOUR_REALM_ID"Note:
- Replace
YOUR_REALM_IDwith your company ID - This endpoint verifies QuickBooks API connectivity and token validity
- Returns
200 OKif healthy,503 Service Unavailableif there are issues
Response: 200 OK with QuickBooks API connectivity status, or 503 if unhealthy
Open in browser:
https://localhost:5001/auth/authorize
This redirects to Intuit for authorization. After authorizing, you'll be redirected to /auth/callback with code and realmId parameters. Save the realmId (company ID) for subsequent API calls.
curl -X POST http://localhost:5000/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"RefreshToken": "your-refresh-token-here"
}'Note: Use http://localhost:5000 (HTTP), not HTTPS.
Response: 200 OK with new access and refresh tokens
Endpoint: POST /api/invoices/{invoiceId}/settle
curl -X POST "http://localhost:5000/api/invoices/INVOICE_ID/settle?companyId=YOUR_REALM_ID" \
-H "Content-Type: application/json" \
-d '{
"Amount": 100.00,
"TxnDate": "2025-01-15",
"Description": "Invoice settlement"
}'Note: Use http://localhost:5000 (HTTP), not HTTPS.
Note:
- Replace
INVOICE_IDwith the invoice ID you want to settle - Replace
YOUR_REALM_IDwith your company ID Amountis optional - defaults to full invoice balance if not specifiedDescriptionis optional - automatically generated if not provided- This uses a hybrid approach: creates a credit memo, then a payment that applies it to the invoice
- Invoice balance is reduced and marked as paid/partially paid
Response: 201 Created with credit memo details
curl -X POST "http://localhost:5000/api/invoices?companyId=YOUR_REALM_ID" \
-H "Content-Type: application/json" \
-d '{
"CustomerRef": {
"value": "1"
},
"Line": [
{
"DetailType": "SalesItemLineDetail",
"Amount": 100.00,
"Description": "Service fee",
"SalesItemLineDetail": {
"ItemRef": {
"value": "2"
},
"Qty": 1,
"UnitPrice": 100.00
}
}
],
"TxnDate": "2025-01-15",
"DueDate": "2025-02-15"
}'Note: Use http://localhost:5000 (HTTP), not https://localhost:5000 (HTTPS). The app runs on HTTP port 5000.
Note: Replace YOUR_REALM_ID with the realmId from the OAuth callback.
Response: 201 Created with invoice details including the invoice ID.
curl -X GET "http://localhost:5000/api/invoices/INVOICE_ID?companyId=YOUR_REALM_ID"Note: Use http://localhost:5000 (HTTP), not HTTPS.
Note: Replace INVOICE_ID with the actual invoice ID and YOUR_REALM_ID with your company ID.
Response: 200 OK with invoice details
Endpoint: GET /api/credit-notes
curl -X GET "http://localhost:5000/api/credit-notes?companyId=YOUR_REALM_ID"Optional Parameters:
maxResults- Limit the number of results (e.g.,?companyId=YOUR_REALM_ID&maxResults=50)
Response: 200 OK with a list of all credit memos
Note: This endpoint retrieves all credit notes (credit memos) created in QuickBooks for the specified company.
Endpoint: POST /api/invoices/{invoiceId}/credit-note
curl -X POST "http://localhost:5000/api/invoices/INVOICE_ID/credit-note?companyId=YOUR_REALM_ID"Note: Use http://localhost:5000 (HTTP), not HTTPS.
Note:
- Replace
INVOICE_IDwith the invoice ID you want to refund/cancel - Replace
YOUR_REALM_IDwith your company ID - This creates a credit memo matching the invoice amount, effectively canceling/adjusting it
- Use this for refunds, cancellations, or adjustments - NOT for normal payments
- Can be created at any time (before or after payment)
When to use credit notes:
- Customer returns goods/services
- Invoice needs to be cancelled
- Refund is required
- Pricing error correction
- Post-invoice discount/credit adjustment
Response: 201 Created with credit memo details including the credit note ID
Endpoint: GET /api/credit-notes/{creditNoteId}
curl -X GET "http://localhost:5000/api/credit-notes/CREDIT_NOTE_ID?companyId=YOUR_REALM_ID"Note: Use http://localhost:5000 (HTTP), not HTTPS.
Note: Replace CREDIT_NOTE_ID with the actual credit note ID and YOUR_REALM_ID with your company ID.
Response: 200 OK with credit memo details
Credit notes (credit memos) can be viewed in QuickBooks Online through:
-
Sales Menu → Products and Services
- Click on the "Credit Memos" tab to see all credit memos
-
Sales → All Sales
- Filter by "Credit Memos" to view credit notes
-
Reports → Sales
- Various sales reports include credit memo information
Note: Credit memos appear with negative amounts in QuickBooks, but when creating them via the API, you provide positive amounts (QuickBooks automatically treats them as credits).
-
Start the application:
cd test-intuint-invoicing-api dotnet run -
Check health:
curl http://localhost:5000/health
-
Authorize (use browser):
- Open:
http://localhost:5000/auth/authorize - Complete OAuth flow
- After authorization, you'll be redirected to callback URL like:
https://localhost:5001/auth/callback?code=...&state=...&realmId=9341455792225805 - Copy the
realmIdvalue (e.g.,9341455792225805) - this is yourcompanyId - The callback page will also display the CompanyId clearly
- Open:
-
Create an invoice (replace YOUR_REALM_ID with the realmId from step 3):
Single-line command (recommended):
curl -X POST "http://localhost:5000/api/invoices?companyId=YOUR_REALM_ID" -H "Content-Type: application/json" -d '{"CustomerRef":{"value":"1"},"Line":[{"DetailType":"SalesItemLineDetail","Amount":100.00,"Description":"Test Invoice","SalesItemLineDetail":{"ItemRef":{"value":"2"},"Qty":1,"UnitPrice":100.00}}],"TxnDate":"2025-01-15","DueDate":"2025-02-15"}'
Multi-line command (if you prefer):
curl -X POST "http://localhost:5000/api/invoices?companyId=YOUR_REALM_ID" \ -H "Content-Type: application/json" \ -d '{"CustomerRef":{"value":"1"},"Line":[{"DetailType":"SalesItemLineDetail","Amount":100.00,"Description":"Test Invoice","SalesItemLineDetail":{"ItemRef":{"value":"2"},"Qty":1,"UnitPrice":100.00}}],"TxnDate":"2025-01-15","DueDate":"2025-02-15"}'
Note: Make sure there are NO spaces after the backslash (
\) in multi-line commands! -
Get the created invoice (replace INVOICE_ID with actual invoice ID):
curl -X GET "http://localhost:5000/api/invoices/INVOICE_ID?companyId=YOUR_REALM_ID" | jq
-
Create credit note (cancel invoice):
curl -X POST "http://localhost:5000/api/invoices/INVOICE_ID/credit-note?companyId=YOUR_REALM_ID" | jq
The project includes convenient shell scripts in the scripts/ folder for common operations. All scripts support optional jq for enhanced JSON formatting.
Note: Scripts work without jq, but installing it provides better formatted output. See Prerequisites for installation instructions.
./scripts/list-invoices.sh [companyId] [maxResults]Examples:
# List all invoices (uses default company ID)
./scripts/list-invoices.sh
# List invoices for specific company
./scripts/list-invoices.sh 9341455793300229
# List invoices with max results limit
./scripts/list-invoices.sh 9341455793300229 50Features:
- Displays summary with total invoice count
- Pretty-prints JSON response (if
jqis installed) - Shows invoice IDs, DocNumbers, totals, and balances
- Provides quick action commands
./scripts/list-credit-notes.sh [companyId] [maxResults]Examples:
# List all credit notes (uses default company ID)
./scripts/list-credit-notes.sh
# List credit notes for specific company
./scripts/list-credit-notes.sh 9341455793300229
# List credit notes with max results limit
./scripts/list-credit-notes.sh 9341455793300229 50Features:
- Displays summary with total credit note count
- Pretty-prints JSON response (if
jqis installed) - Shows credit note IDs, DocNumbers, totals, and customer info
- Provides quick action commands and portal location info
./scripts/get-invoice.sh <invoiceId> [companyId]Examples:
# Get invoice by ID (uses default company ID)
./scripts/get-invoice.sh 147
# Get invoice for specific company
./scripts/get-invoice.sh 147 9341455793300229Features:
- Displays detailed invoice summary (ID, DocNumber, Customer, Dates, Amounts, Status)
- Shows all line items with quantities and prices
- Pretty-prints full JSON response (if
jqis installed) - Provides quick action commands (list, settle, create credit note)
- Shows invoice status (PAID/UNPAID)
./scripts/get-credit-note.sh <creditNoteId> [companyId]Examples:
# Get credit note by ID (uses default company ID)
./scripts/get-credit-note.sh 148
# Get credit note for specific company
./scripts/get-credit-note.sh 148 9341455793300229Features:
- Displays detailed credit note summary (ID, DocNumber, Customer, Date, Amount)
- Shows all line items with quantities and prices
- Pretty-prints full JSON response (if
jqis installed) - Provides quick action commands and portal location info
- Handles negative amounts correctly (displays as positive credit)
./scripts/create-invoice.sh [customerName] [companyId]Example:
./scripts/create-invoice.sh "Shipht It Company" 9341455793300229Features:
- Automatically creates customer if it doesn't exist
- Uses today's date and calculates due date (30 days)
- Comprehensive invoice with multiple line items
- Idempotency check to prevent duplicates
./scripts/settle-invoice.sh <invoiceId> <paymentAmount> [companyId]Example:
./scripts/settle-invoice.sh 147 16567.00 9341455793300229Features:
- Creates credit memo, then payment to apply it to invoice (hybrid approach)
- Supports full and partial settlement
- Verifies invoice balance reduction
- Shows settlement status (fully paid or partially paid)
- Includes description in credit memo for tracking
./scripts/create-credit-note.sh <invoiceId> [companyId]Example:
./scripts/create-credit-note.sh 147 9341455793300229Features:
- Creates credit memo matching invoice
- Verifies invoice settlement status
- Shows updated invoice balance
-
Use
http://localhost:5000(HTTP), nothttps://(HTTPS) - the app runs on HTTP port 5000 -
Pipe to
jqfor formatted JSON output:curl ... | jq -
Install
jqfor better script output:- Linux:
apt-get update && apt-get install -y jq(orsudo apt-get install jqif not root) - macOS:
brew install jq - Windows: Download from jq official site
- Linux:
-
All shell scripts automatically detect and use
jqif installed for enhanced formatting -
Save responses to variables in bash:
INVOICE_RESPONSE=$(curl -X POST "https://localhost:5001/api/invoices?companyId=YOUR_REALM_ID" \ -H "Content-Type: application/json" \ -d '{...}' \ -k) INVOICE_ID=$(echo $INVOICE_RESPONSE | jq -r '.data.id')
-
View full response with headers:
curl -v -X GET "http://localhost:5000/api/invoices/INVOICE_ID?companyId=YOUR_REALM_ID"
dotnet builddotnet test- Endpoints: Each endpoint group is in its own file under
Endpoints/ - Services: Business logic is separated into service classes
- Models: DTOs and data models are in the
Models/folder - Middleware: Request processing middleware (validation, correlation IDs)
- Extensions: Extension methods for common operations
- Helpers: Utility classes for retry logic and polling
- Comments: Functions include inline comments explaining their purpose
- Create or update the appropriate endpoint file in
Endpoints/ - Add the endpoint method with proper comments
- Register the endpoint mapping in
Program.cs
Example:
public static void MapMyEndpoints(this WebApplication app)
{
app.MapGet("/api/my-endpoint", MyEndpoint);
}
private static IResult MyEndpoint()
{
// Your logic here
return Results.Ok();
}Then in Program.cs:
app.MapMyEndpoints();- Retry Logic: Automatic retry with exponential backoff for transient QuickBooks API failures (using Polly)
- Request Validation: Middleware automatically validates
companyIdand OAuth tokens before processing - Correlation IDs: Every request gets a unique correlation ID for better traceability and debugging
- Customer Caching: In-memory cache for customer lookups to reduce API calls
- Structured Logging: Enhanced logging with correlation IDs for better request tracking
- Health Checks: Application health and QuickBooks API connectivity monitoring
- Async Token Storage: Non-blocking file I/O for OAuth token persistence
- User initiates OAuth via
/auth/authorize - Redirected to Intuit for authorization
- Intuit redirects back with authorization code
- Code is exchanged for access/refresh tokens
- Tokens are stored in-memory and persisted to file (keyed by
realmId) - Tokens are automatically refreshed when expired
- Client sends request with
companyIdquery parameter - Correlation ID Middleware adds a unique correlation ID to the request for traceability
- Request Validation Middleware validates
companyIdand checks for OAuth tokens - System retrieves stored tokens for that company (with automatic refresh if expired)
- Request is forwarded to QuickBooks API with Bearer token (with automatic retry on transient failures)
- Response is returned to client with correlation ID in headers
Standard Settlement (POST /api/invoices/{invoiceId}/settle):
- Uses hybrid approach: credit memo + payment
- Step 1: Creates a credit memo for the settlement amount
- Step 2: Creates a payment that links both credit memo and invoice
- Step 3: Payment applies the credit memo to the invoice
- Invoice balance is reduced and marked as paid/partially paid
- Includes description for tracking purposes
Credit Notes for Refunds/Cancellations (POST /api/invoices/{invoiceId}/credit-note):
- Use when customer returns goods/services
- Use when invoice needs to be cancelled
- Use when refund is required
- Use for pricing error correction
- Use for post-invoice discount/credit adjustment
- Note: These credit notes are standalone and don't automatically reduce invoice balances
Issue: "ERR_CONNECTION_REFUSED" or "This site can't be reached"
- Error: Browser shows connection refused when accessing callback URL
- Solution:
- Check if app is running: Make sure
dotnet runis executing - Use HTTP instead of HTTPS: If HTTPS port 5001 doesn't work, use HTTP port 5000:
- Update
appsettings.json: ChangeRedirectUritohttp://localhost:5000/auth/callback - Add
http://localhost:5000/auth/callbackin Intuit Developer Portal → Settings → Redirect URIs - Use
http://localhost:5000/auth/authorizeto start OAuth flow
- Update
- Or fix HTTPS: Ensure .NET development certificate is installed:
dotnet dev-certs https --trust
- Check if app is running: Make sure
Issue: "The redirect_uri query parameter value is invalid"
- Error Message: "Make sure it is listed in the Redirect URIs section on your app's keys tab and matches it exactly"
- Solution:
- Go to Intuit Developer Portal
- Select your app (Client ID:
ABNlWkUkrhvReqHfo4yfXCgxn6FFdRnfbdfXE3HfaMgjD5WPep) - Navigate to Settings tab → Redirect URIs section
- Make sure you're in Development mode (not Production)
- Click "Add URI" button
- Add BOTH URIs (you can add multiple):
https://localhost:5001/auth/callback(for HTTPS)http://localhost:5000/auth/callback(for HTTP - backup option)
- Important:
- The URI must match EXACTLY (including protocol, no trailing slash)
- Do NOT use the OAuth2 Playground URL - that's only for manual testing
- Click Save
- Wait 2-3 minutes for changes to propagate
- Try the OAuth flow again
Issue: "Unauthorized" responses
- Solution: Ensure you've completed the OAuth flow and tokens are stored for the
companyId
Issue: "Missing code or realmId"
- Solution: Complete the OAuth authorization flow from
/auth/authorize
Issue: "Failed to create invoice"
- Solution:
- Verify customer and item IDs exist in QuickBooks
- Check that required fields are provided
- Ensure access token is valid
Issue: Port already in use
- Solution: Change the port in
Properties/launchSettings.jsonor use:dotnet run --urls "https://localhost:5002"- Note: If you change the port, also update the
RedirectUriinappsettings.jsonand in Intuit Developer Portal
- Note: If you change the port, also update the
- Check application logs in the console
- Use Swagger UI to test endpoints interactively
- Verify
appsettings.jsonhas correct Intuit credentials - Ensure QuickBooks sandbox company is set up correctly
You can override configuration using environment variables:
export Intuit__ClientId="your-client-id"
export Intuit__ClientSecret="your-client-secret"For production:
- Update
BaseUrlto production URL - Change
Environmenttoproduction - Use secure token storage (current implementation uses in-memory storage)
- Configure proper HTTPS certificates
We welcome contributions! Here's how to get started:
-
Fork and clone the repository:
git clone <your-fork-url> cd test-intuint-invoicing-api/test-intuint-invoicing-api
-
Set up your development environment:
# Install dependencies dotnet restore # Create your configuration file from the example cp appsettings.json.example appsettings.json # Edit appsettings.json with your Intuit credentials # Replace YOUR_CLIENT_ID_HERE and YOUR_CLIENT_SECRET_HERE # (See "Configure Intuit Credentials" section above for detailed steps)
-
Get your Intuit Developer credentials:
- If you don't have an Intuit Developer account, create one at Intuit Developer Portal
- Create a new app in the Developer Portal
- Copy your Client ID and Client Secret
- Add the redirect URI:
http://localhost:5000/auth/callbackin your app settings
-
Verify everything works:
# Build the project dotnet build # Run the application dotnet run # Test the health endpoint curl http://localhost:5000/health
-
Create a feature branch:
git checkout -b feature/your-feature-name
-
Make your changes:
- Follow the existing code structure
- Add comments explaining what functions do
- Keep functions focused and single-purpose
- Use meaningful variable names
-
Test your changes:
# Build to check for errors dotnet build # Run the application and test endpoints dotnet run # Use the provided shell scripts to test functionality ./scripts/list-invoices.sh
-
Commit your changes:
git add . git commit -m "Description of your changes"
-
Push and create a pull request:
git push origin feature/your-feature-name
Then create a pull request on GitHub.
- Keep functions focused and single-purpose - Each function should do one thing well
- Add comments explaining what functions do - Help other developers understand your code
- Use meaningful variable names - Make code self-documenting
- Follow existing code structure - Maintain consistency with the project
- Handle errors gracefully - Provide clear error messages
- Test your changes - Use the provided scripts or Swagger UI
- Endpoints go in
Endpoints/folder - One file per endpoint group - Services go in
Services/folder - Business logic and external API clients - Models go in
Models/folder - DTOs and data models - Middleware go in
Middleware/folder - Request processing middleware - Extensions go in
Extensions/folder - Extension methods - Helpers go in
Helpers/folder - Utility classes - Scripts go in
scripts/folder - Shell scripts for testing and automation
- ✅ Code builds without errors (
dotnet build) - ✅ All endpoints tested and working
- ✅ Comments added for new functions
- ✅ No hardcoded credentials or secrets
- ✅ Follows existing code patterns
- ✅ README updated if adding new features
- ✅
appsettings.jsonis NOT committed (onlyappsettings.json.example)
Issue: "No OAuth tokens found"
- Solution: Complete the OAuth flow first by visiting
http://localhost:5000/auth/authorize
Issue: "Invalid redirect_uri"
- Solution: Make sure you added
http://localhost:5000/auth/callbackin Intuit Developer Portal
Issue: Build errors
- Solution: Run
dotnet restoreto ensure all packages are installed
Issue: Port already in use
- Solution: Stop other instances or change the port in
Properties/launchSettings.json
See LICENSE file for details.