If you’re familiar with our QuickBooks Online Accounting API (referred to as Accounting API for the remainder of this section), you may be used to the REST framework. On this page, we’ll go over some general differences between REST and GraphQL, and some differences between the Accounting API and the GraphQL API.
Using REST, you would do a GET
request to retrieve data from the server and a POST
, PATCH
, PUT
or DELETE
to modify data on the server.
With GraphQL, all requests are POST
requests and the body of the request tells the server what needs to be done.
All of the HTTP calls are made the same way and to the same resource but with different request bodies. To retrieve data, you would use a query operation, and to modify data you would use a mutation operation.
Let’s say you wanted to read an invoice and find out how that invoice was paid. In REST, these would typically be separate endpoints or entities called Invoice and Payment, which is what the Accounting API does. You would have to make one call to the Invoice endpoint to get the invoice information. You would then find the related Payment ID and then make another call to Payment endpoint to find out more information about the payment transaction.
If you were to do this in GraphQL, you would be dealing with a single resource. Depending on the schema, you would make a call to one resource and ask for the Invoice fields you need and the fields on the related Payment.
The Accounting API would return all the information it has about an entity that is queried. A simple read or query operation would return all the fields associated with the entity for the record that has been requested.
The GraphQL API gives you more control over what data you want from the server. Whether you are doing a query or a mutation, you can specify exactly which fields (and nested fields) you want from the server.
In the Accounting API, when you query for records, each record comes with an ID, which is unique only within that entity. So you may have an Invoice with ID 123 and a Payment with ID 123.
The GraphQL API has global IDs. Each entity returned in response has an ID that is unique across all entities.
The Accounting API returns HTTP status codes like 4** or 5** to indicate different types of errors.
The GraphQL API handles errors differently. Errors related to the API gateway later will return status codes 4** or 5**, but API errors will return HTTP status code 200 and provide all of the necessary information within the response body.
Let’s take a deeper dive into common operations: create, read, update, delete, and query. We’ll take the example of the Accounting API’s Invoice entity for this section. An Invoice represents a sales form where the customer pays for a product or service later. It is associated with Items, Customers, and Payments. Although Invoice is not supported in the GraphQL API, we’ll do a comparison between how we work with this entity in the Accounting API vs how we would hypothetically do this in the GraphQL API.
In all of the snippets below you will see that in the Accounting API (REST), the response will be the object with all of the fields. With the GraphQL API, however, you can specify which fields you want and only those fields are a part of the response.
Note
Note: The purpose of the following examples is to illustrate the differences between REST and GraphQL. The Intuit GraphQL API does not provide invoice requests.
This section shows how you can create an invoice using REST and GraphQL.
Request
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | POST <baseUrl>/v3/company/<realmID>/invoice { "Line": [ { "DetailType": "SalesItemLineDetail", "Amount": 100.0, "SalesItemLineDetail": { "ItemRef": { "name": "Services", "value": "1" } } } ], "CustomerRef": { "value": "1" } } |
Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | { "Invoice": { "Id": "238", "DocNumber": "1069", "Balance": 100.0, "TxnDate": "2020-07-24", "TotalAmt": 100.0, "CustomerRef": { "name": "Amy's Bird Sanctuary", "value": "1" }, "ShipAddr": { "City": "Bayshore", "Line1": "4581 Finch St.", "PostalCode": "94326", "CountrySubDivisionCode": "CA", "Id": "109" }, "DueDate": "2020-08-23", "Line": [ { "Amount": 100.0, "SalesItemLineDetail": { "TaxCodeRef": { "value": "NON" }, "ItemRef": { "name": "Services", "value": "1" } }, "DetailType": "SalesItemLineDetail" } ], ... other fields ... } |
Request
1 2 3 4 5 6 7 8 | POST <graphBaseURL>/v1 mutation Create{ createInvoice(item: {type: "inventory", amount: 100, itemref: "111"}, customerRef: "222", paymentRef: "333") { id docNumber } } |
Response
1 2 3 4 | { "id": 1, "docNumber": "101" } |
This section shows how to read an invoice and get the payment type of the linked payment using REST or GraphQL.
Request Example 1
1 | GET /v3/company/<realmID>/invoice/101 |
Response Example 1
1 2 3 4 5 6 7 8 9 10 | { "Invoice": { "Id": "101", "DocNumber": "1069", "LinkedTxn": { "TxnType": "Payment", "TxnId": "801" } ... other fields ... } |
Request Example 2
1 | GET /v3/company/<realmID>/payment/801 |
Response Example 2
1 2 3 4 5 6 | { "Payment": { "Id": "801", "PaymentType": "CreditCard", ... other fields ... } |
Request
1 2 3 4 5 6 7 8 9 | POST <graphBaseURL>/v1 query getPaymentInfo { invoices (id : 1) { docNumber payments { paymentType } } |
Response
1 2 3 4 5 6 | { docNumber: "101", payments{ paymentType: "Credit Card" } } |
This section shows how to update an existing invoice with REST or GraphQL.
Request
1 2 3 4 5 6 7 8 | POST <baseUrl>/v3/company/<realmID>/invoice { "SyncToken": "0", "Id": "101", "sparse": true, "DueDate": "2020-09-30" } |
Response
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "Invoice": { "Id": "101", "SyncToken": "1", "DocNumber": "1069", "DueDate": "2020-09-30", "Line": [ { ... other fields ... } ], ... other fields ... } |
Request
1 2 3 4 5 6 7 8 | POST <graphBaseURL>/v1 mutation Update($id: ID!) { updateInvoice(id: $id, dueDate: "2020-09-30") { id dueDate } } |
Response
1 2 3 4 | { id: 1, dueDate: "2020-09-30" } |
Delete an invoice using REST or GraphQL.
Request
1 2 3 4 5 6 | POST <baseUrl>/v3/company/<realmID>/invoice?operation=delete { "Id": "239", "SyncToken":"3" } |
Response
1 2 3 4 5 6 7 | { "Invoice": { "domain": "QBO", "status": "Deleted", "Id": "239" } } |
Request
1 2 3 4 5 6 7 | POST <graphBaseURL>/v1 mutation Delete($id: ID!) { deleteInvoice(id: $id) { status } } |
Response
1 2 3 | { status: "void" } |
A common operation is to query invoices based on certain filters. Let’s say we want to get all invoices created within a date range.
Request
1 | GET <baseUrl>/v3/company/<realmID>/query?query=select * from Invoice where TxnDate>'2020-01-18' and TxnDate<'2020-01-18' |
Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | { "QueryResponse": { "Invoice": [ { "Id": "201", ... other fields ... }, { "Id": "202", ... other fields ... }, ... more records ... ] } } |
Request
1 2 3 4 5 6 7 | query getInvoices() { invoice(filter: {txnDate: {between: ['2020-01-18' , '2020-01-18' ]}}) { id status balance } } |
Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | { "data": { "invoice": [ { "id": "101", "status": "Paid", "balance": 0 }, { ... more records ... }, ... more records ... ] } } |