Complete QuickBooks Online Authorization (OAuth Callback)
GET/qbo/callback
Called by the merchant's browser, not by an integrator (note: no /api prefix). This is the redirect URI registered with Intuit: after the merchant approves SKU.io on Intuit's consent screen (opened from the authorization_url returned by Initialize OAuth), Intuit redirects the browser here. No bearer token; the request is tied to the workspace by the state SKU.io issued.
Query parameters sent by Intuit
code— authorization code to exchange for tokens.state— the value from Initialize OAuth (<tenant id>_<uuid>); the prefix identifies the workspace.realmId— the QuickBooks company id.error,error_description— sent instead when the merchant declines or Intuit fails.
Behaviour: for a first connection the code and realm are stored against the state and the browser is sent back with success=true; the app then calls Complete OAuth Setup with the same state to create the integration. If the workspace already has a QuickBooks Online integration, it is reconnected here directly with the new tokens (isReconnect=true); connecting a different QuickBooks company than the one already linked fails with error=account_mismatch.
Response: always a 302 redirect to the workspace's own host at /v2/integrations/quickbooks/callback with success, state, message, error, errorMessage and isReconnect query parameters. Error codes: the Intuit error value, missing_parameters (no code, state or realmId), account_mismatch, callback_failed.
Authentication: none (public redirect target, secured by state).
Request
Responses
- 302
- 401
- 403
- 429
Found
Response Headers
Unauthenticated — the bearer token is missing, revoked, expired, or malformed. Never retry automatically; fix the credential. See the Errors guide.
Forbidden — the token lacks a required scope, the endpoint is not available to API tokens, or the user behind the token lacks the permission. A human must adjust the token scopes or user permissions; do not retry.
Rate limited — platform limit is 1,000 requests/min; individual tokens may carry lower limits. Honor the Retry-After header before retrying. See the Rate Limits guide.