A PHP sample app for exploring QuickBooks Online payroll compensation and time-activity workflows via GraphQL and REST, complete with OAuth 2.0 flow and lightweight UI pages for testing.
- Indirect Tax via GraphQL
- Calculate sales tax for a simple sale transaction
- Shows request URL, headers (masked), body, and full response
- Handles errors and surfaces friendly notice for sandbox limitations (e.g., -37109)
- Sales Tax Status (REST v3)
- Fetches Preferences to determine if
TaxPrefs.UsingSalesTaxis enabled - Displays raw JSON response and logs to the console
- Fetches Preferences to determine if
- OAuth 2.0 with QuickBooks Online (tokens stored in PHP session)
- OAuth Home:
OAuth_2/index.php - Indirect Tax (GraphQL):
IndirectTax/Calculate.php - Sales Tax Status (Preferences REST):
IndirectTax/SalesTaxStatus.php - Time Activity playground (employees/compensations):
Payroll/TimeActivity/timeActivity.php- Uses REST v3
POST /v3/company/{realmId}/timeactivity?minorversion=75for creation (employees via REST, compensation via GraphQL)
- Uses REST v3
- Recent Time Activities (last 30 days via REST query):
Payroll/TimeActivity/listTimeActivities.php
- Mutation:
indirectTaxCalculateSaleTransactionTax- Definitions in
IndirectTax/graphql/sales_tax.graphql - Variables template in
IndirectTax/graphql/graphql_variables.json
- Definitions in
- If
QB_GRAPHQL_URLis set, it is used - Else if
QB_ENVIRONMENT=production→https://qb.api.intuit.com/graphql - Else (default sandbox) →
https://qb-sandbox.api.intuit.com/graphql
Edit OAuth_2/config.php and set:
client_id,client_secret- Environment selection is automatic via
APP_ENV(defaults tosandbox). Bothproductionandsandboxblocks are defined with per-envbase_urland redirect URLs. - URLs (use your ngrok domain when testing):
oauth_redirect_uri→https://<ngrok-domain>/OAuth_2/OAuth2PHPExample.phpopenID_redirect_uri→https://<ngrok-domain>/OAuth_2/OAuthOpenIDExample.phpmainPage→https://<ngrok-domain>/OAuth_2/index.phprefreshTokenPage→https://<ngrok-domain>/OAuth_2/RefreshToken.php
com.intuit.quickbooks.accounting– baseline access to QBO accounting data (employees, customers, items, time activities)payroll.compensation.read– required for the GraphQL employee compensation lookup used on the Time Activity page
- Start ngrok (or any HTTPS tunnel) pointing at your local server, e.g.
https://your-subdomain.ngrok-free.app. - In developer.intuit.com → My Apps → choose your app → Keys & OAuth, add the following redirect URIs:
https://<your-ngrok-domain>/OAuth_2/OAuth2PHPExample.phphttps://<your-ngrok-domain>/OAuth_2/OAuthOpenIDExample.php
- Ensure the URIs entered in
OAuth_2/config.phpmatch exactly (protocol, host, path). For example:https://ngrok-free.app/OAuth_2/OAuth2PHPExample.php.
Environment variables used by GraphQL service (optional):
QB_ENVIRONMENT=sandbox|productionQB_GRAPHQL_URL(override endpoint)
composer install
php -S 127.0.0.1:5001 -t . | cat
# In another terminal
ngrok http 5001Open https://<ngrok-domain>/OAuth_2/index.php and complete the OAuth flow.
- GraphQL requests include:
Authorization: Bearer <token>,Content-Type: application/json,Accept: application/json;charset=UTF-8,User-Agent,Host(and optionallyintuit-realm-idwhen needed) - UI shows request URL, masked headers, request body, and response (headers/body). Errors log details to the browser console.
- Logging: Requests/responses are appended to
logs/graphql_requests.log.
- 401 AuthenticationFailed: refresh tokens or re-authenticate
- 403/UNAUTHORIZED/DENY: verify entitlements/scopes and correct environment/realm
-37109notice: sales tax calculation not available in this environment (sandbox limitation or account config). Try production or contact QuickBooks Developer Support.- Validation errors: ensure a valid
qbCustomerIdin the same realm,transactionDateformatyyyy-MM-dd, positive unit values, and address fields as required by schema.
If you want to prevent your local edits to OAuth_2/config.php from showing up in git status while keeping the file tracked on remote, use Git's skip-worktree flag:
Also ensure the OAuth redirect URIs configured above are added to your QuickBooks Developer app settings (Redirect URIs) exactly, including protocol and path.
After authenticating, create a customer using OAuth_2/CustomerCreate.php and copy the returned Customer Id to use in the Sales Tax UI.
# Ignore local changes going forward
git update-index --skip-worktree OAuth_2/config.php
# Verify (lines starting with S are skipped)
git ls-files -v | grep '^S'
# Stop ignoring later (to allow updates/pulls)
git update-index --no-skip-worktree OAuth_2/config.phpNote: This is a local-only setting; it does not modify the remote repository history.