Use webhooks to receive event triggered callbacks for entities that your app needs to stay on top of. Webhooks automatically notify you whenever data changes in your end-user’s QuickBooks Online company files.
Webhooks apply to all QuickBooks Online companies connected to your app.
You’ll need to configure an endpoint our servers can call whenever user data changes trigger notifications. Once webhooks are active, we’ll send the requested event data, changes, and notifications.
If you haven’t already, set up OAuth 2.0 for your app.
Even if webhooks are active, you’ll only receive change notifications for QuickBooks Online companies that are connected and authorized via OAuth 2.0.
Here ia an example webhook implementation for Java.
See which entities and operations support webhooks
This table shows the entities that support webhooks and the permitted operations.
| Create | Update | Delete | Merge | Void | Emailed | |
| Account | ✓ | ✓ | ✓ | ✓ | ||
| Bill | ✓ | ✓ | ✓ | |||
| BillPayment | ✓ | ✓ | ✓ | ✓ | ||
| Budget | ✓ | ✓ | ||||
| Class | ✓ | ✓ | ✓ | ✓ | ||
| CreditMemo | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Currency | ✓ | ✓ | ||||
| Customer | ✓ | ✓ | ✓ | ✓ | ||
| Department | ✓ | ✓ | ✓ | |||
| Deposit | ✓ | ✓ | ✓ | |||
| Employee | ✓ | ✓ | ✓ | ✓ | ||
| Estimate | ✓ | ✓ | ✓ | ✓ | ||
| Invoice | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Item | ✓ | ✓ | ✓ | ✓ | ||
| JournalCode | ✓ | ✓ | ||||
| JournalEntry | ✓ | ✓ | ✓ | |||
| Payment | ✓ | ✓ | ✓ | ✓ | ✓ | |
| PaymentMethod | ✓ | ✓ | ✓ | |||
| Preferences | ✓ | |||||
| Purchase | ✓ | ✓ | ✓ | ✓ | ||
| PurchaseOrder | ✓ | ✓ | ✓ | ✓ | ||
| RefundReceipt | ✓ | ✓ | ✓ | ✓ | ✓ | |
| SalesReceipt | ✓ | ✓ | ✓ | ✓ | ✓ | |
| TaxAgency | ✓ | ✓ | ||||
| Term | ✓ | ✓ | ||||
| TimeActivity | ✓ | ✓ | ✓ | |||
| Transfer | ✓ | ✓ | ✓ | ✓ | ||
| Vendor | ✓ | ✓ | ✓ | ✓ | ||
| VendorCredit | ✓ | ✓ | ✓ |
There are two sets of webhooks: one for live, in-production apps and a separate set for sandbox and testing environments.
You need to set up webhooks for production apps and sandbox environments separately.
After you configure webhook endpoints, we provide an app-specific verifier token. Use verifier tokens to validate the webhook notifications from the callback are from Intuit.
To see verifier tokens:
To use verifier tokens:
Here’s a sample header:
1 2 3 4 5 6 7 8 9 10 | content-length:262 intuit-created-time:2016-02-02T16:25:00-0800 intuit-t-id:9cf50b60-8b0e-4fea-8327-e6a66099fe6f proxy-connection:keep-alive host:sample-endpoint.ilb.idg-notify-ppd.a.intuit.com:8443 intuit-notification-schema-version:0.1 content-type:application/json; charset=utf-8 intuit-signature:6kQBQtjwjupelRMwkyJsnpq80uhz2o+Rn92+m03GhKE= accept:application/json user-agent:intuit_notification_server/0.1 |
Here’s a sample signature verification in Java:
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 | import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Base64; import java.util.Map; public class VerifySignatureExample { private static final String SIGNATURE = "intuit-signature"; private static final String ALGORITHM = "HmacSHA256"; public boolean isRequestValid(Map<String, String> headers, String payload, String verifier) { String signature = headers.get(SIGNATURE); if (signature == null) { return false; } try { SecretKeySpec secretKey = new SecretKeySpec(verifier.getBytes("UTF-8"), ALGORITHM); Mac mac = Mac.getInstance(ALGORITHM); mac.init(secretKey); String hash = Base64.getEncoder().encodeToString(mac.doFinal(payload.getBytes())); return hash.equals(signature); } catch (NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeyException e) { return false; } } } |
Webhook notifications are POSTs with a JSON body. The notification payload contains the following fields:
| Field | Description |
|---|---|
specversion |
The version of the CloudEvents specification. Value is always 1. Can be ignored. |
id |
Unique ID of the event. May be useful in troubleshooting or reporting any errors. |
source |
GUID value. Can be ignored. |
type |
Represents the entity and event for the notification, in the format: namespace.entitytype.eventname.version |
datacontenttype |
The content type of the data value: application/json |
time |
The timestamp of when the occurrence happened, provided in RFC 3339 (ISO 8601) format at UTC+0 (e.g., “2018-04-05T03:56:24Z”). |
intuitentityid |
The ID of the entity that was changed. |
intuitaccountid |
The QuickBooks Online company ID or realm ID. |
data |
Name-value pairs containing additional information about the occurrence. Can be ignored if empty. |
Here’s an example notification payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 | [ { "specversion": "1.0", "id": "88cd52aa-33b6-4351-9aa4-47572edbd068", "source": "intuit.dsnBgbseACLLRZNxo2dfc4evmEJdxde58xeeYcZliOU=", "type": "qbo.account.created.v1", "datacontenttype": "application/json", "time": "2025-09-10T21:31:25.179851517Z", "intuitentityid": "1234", "intuitaccountid": "310687", "data": {} } ] |
Webhook events are composed of an array of individual event notifications. Each of these event notifications correspond to unique information associated with a specific realm ID. A single notification can contain a list of events, each for a different QuickBooks Online company/realm ID. Your app must be updated to handle events for multiple companies per notification.
Using the above example, if your app is connected to multiple companies, you will receive an array of event notifications. Each element in this array represents a unique update for a specific company.
Each event notification can include multiple entities such as Customer or Vendor. These entities within the same realm ID denote changes or operations, such as Create, that happened at the given lastUpdated time.
Reliability: To compensate for the possibility of missed events, make a ChangeDataCapture (CDC) call for all required entities, dating back to the last known successfully processed webhook event for each entity.
Additionally, you can make a daily CDC call for all required entities to ensure your app has always processed the most up-to-date data.
You can see this in the example webhook implementations.
Respond promptly: If your endpoint doesn’t respond within three seconds, the transaction will time out and retry.
Make sure your app can always respond quickly. Don’t process the notification payload or perform complex operations within the webhooks endpoint implementation. Do the processing on a separate thread asynchronously using a queue.
You can see this in the example webhook implementations.
Manage concurrency: Event notifications are sent one realm ID at a time. When there are multiple rapid changes, your app may get frequent notifications. Process the queue linearly to avoid processing the same changes more than once.
Notification ordering: It’s possible to receive events out of sequence. The timestamp field in the notification payload is always the source of truth for when events occur.
Retry policy: Your endpoint must respond to notifications with an HTTP 200 status within 3 seconds. When our webhooks delivery system does not receive a successful acknowledgement from your listener, we retry the failed event. The retry will happen at the following intervals: 10s, 20s, 30s, 5m, 20m, 2h, 4h, 6h and then on stays at 6-hour intervals. You may not receive subsequent events from our system until you correctly acknowledge the first event.