QuickBooksSharp
.NET client for QuickBooks Online API
Install / Use
/learn @Wish-Org/QuickBooksSharpREADME
QuickBooksSharp
Modern, async first, .NET client for QuickBooks Online Accounting API
This project was created because the official .NET client provided by Intuit is hard to work with and based on outdated .NET patterns.
https://developer.intuit.com/app/developer/qbo/docs/develop
API version: 3.75
https://www.nuget.org/packages/QuickBooksSharp/
Install-Package QuickBooksSharp
OAuth authentication
Generate URL to redirect user for approval of connection:
var authService = new AuthenticationService();
var scopes = new[] { "com.intuit.quickbooks.accounting" };
string redirectUrl = "https://myapp.com/quickbooks/authresult";
string state = Guid.NewGuid().ToString();
string authUrl = authService.GenerateAuthorizationPromptUrl(clientId, scopes, redirectUrl, state);
// Redirect the user to authUrl so that they can approve the connection
Exchange code for token
[HttpGet]
public async Task<IActionResult> AuthResult(string code, long realmId, string state)
{
//validate state parameter
var authService = new AuthenticationService();
string clientId = //get from config
string clientSecret = //get from config
var result = await authService.GetOAuthTokenAsync(clientId, clientSecret, code, redirectUrl);
//persit access token and refresh token
...
}
Refresh token
var authService = new AuthenticationService();
var result = await authService.RefreshOAuthTokenAsync(clientId, clientSecret, refreshToken);
//persit access token and refresh token
Get User Info
var authService = new AuthenticationService();
var userInfo = await authService.GetUserInfo(accessToken, useSandbox: true);
//persit access token and refresh token
Instantiating the DataService
var dataService = new DataService(accessToken, realmId, useSandbox: true);
Creating / Updating entities
var result = await dataService.PostAsync(new Customer
{
DisplayName = "Chandler Bing",
Suffix = "Jr",
Title = "Mr",
MiddleName = "Muriel",
FamilyName = "Bing",
GivenName = "Chandler",
});
//result.Response is of type Customer
var customer = result.Response;
//Sparse update some properties
result = await dataService.PostAsync(new Customer
{
Id = customer.Id,
SyncToken = customer.SyncToken,
GivenName = "Ross",
sparse = true
});
//Update all properties
customer = result.Response;
customer.FamilyName = "Geller";
customer.sparse = false;
result = await dataService.PostAsync(customer);
Delete entities
var result = await dataService.PostAsync(new Invoice { Id = "123", SyncToken = syncToken }, OperationEnum.delete);
Querying entities
var result = await dataService.QueryAsync<Customer>("SELECT * FROM Customer")
//res.Response.Entities is of type Customer[]
var customers = res.Response.Entities;
var result = await dataService.QueryCountAsync("SELECT COUNT(*) FROM Customer");
var count = res.Response.TotalCount;
Querying reports
var report = await dataService.GetReportAsync("ProfitAndLoss", new()
{
{ "accounting_method", "Accrual" },
{ "date_macro", "Last Fiscal Year" }
});
string reportName = report.Header.ReportName;
Change Data Capture (CDC)
var result = await dataService.GetCDCAsync(DateTimeOffset.UtcNow.AddDays(-10), "Customer,Invoice");
var queryResponses = result.Response.QueryResponse; //type QueryResponse[]
var customers = queryResponses[0].IntuitObjects.Cast<Customer>();
var invoices = queryResponses[1].IntuitObjects.Cast<Invoice>();
Batch
//Delete 30 bills in a batch
var bills = (await dataService.QueryAsync<Bill>("SELECT * FROM Bill MAXRESULTS 30")).Response.Entities;
var response = await dataService.BatchAsync(new IntuitBatchRequest
{
BatchItemRequest = bills.Select(b => new BatchItemRequest
{
bId = Guid.NewGuid().ToString(),
operation = OperationEnum.delete,
Bill = new Bill
{
Id = b.Id,
SyncToken = b.SyncToken
}
}).ToArray()
});
//Issue multiple queries in a batch
var response = await dataService.BatchAsync(new IntuitBatchRequest
{
BatchItemRequest = new[]
{
new BatchItemRequest
{
bId = Guid.NewGuid().ToString(),
Query = "SELECT * FROM Bill MAXRESULTS 30",
},
new BatchItemRequest
{
bId = Guid.NewGuid().ToString(),
Query = "SELECT * FROM Invoice MAXRESULTS 30",
}
}
});
Verifying webhooks
[HttpPost]
[IgnoreAntiforgeryToken]
[AllowAnonymous]
public async Task<IActionResult> Webhook()
{
string signature = Request.Headers["intuit-signature"].ToString();
string webhookVerifierToken = //get from config
string requestBodyJSON = await base.ReadBodyToEndAsync();
if (!Helper.IsAuthenticWebhook(signature, webhookVerifierToken, requestBodyJSON))
return BadRequest();
//return HTTP error status
//Process webhook
WebhookEvent notification = JsonSerializer.Deserialize<WebhookEvent>(requestBodyJSON, QuickBooksHttpClient.JsonSerializerOptions);
}
Download Invoice PDF
var invoiceId = "1023";
var invoidePdfStream = await dataService.GetInvoicePDF(invoiceId);
Related Skills
node-connect
349.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
