OAuth 2.0 authorization
Sage Intacct uses the OAuth 2.0 authorization standard to allow REST API clients to obtain secure access to our web services on behalf of specific resource owners. Client applications can use the authorization code or the client credentials grant type depending on the type of access required.
Authorization code grant type
The authorization code grant type is supported for applications in which a user can click a button or link to grant the application access to their data in Sage Intacct. The OAuth 2.0 authorization code flow involves the following steps:
- The user signs into your application and clicks a link to authorize your application to access their Sage Intacct data.
- A Sage Intacct log in screen is displayed and the user logs in.
- The user is prompted to grant your application access to their data and must click Accept .
- The authentication server responds by redirecting the user to the registered callback URI with an authorization code in the query string.
- Your application captures the authorization code and uses it to request an access token.
- Your application receives the access token and includes it in the headers of all requests to the REST API.
Authorization code request
To request an authorization code, send a GET request to the following endpoint with the listed parameters:
Endpoint: https://api.intacct.com/ia/api/v1/oauth2/authorize
Parameter |
Value |
---|---|
response_type |
code |
client_id |
Your application's client ID |
redirect_uri |
The redirect URI set for your application in the Sage App Registry |
state |
A random value to use to validate the response |
scope |
Use offline_access if you want to get a refresh token in addition to an access token |
Sample authorization code request:
https://api.intacct.com/ia/api/v1/oauth2/authorize?response_type=code&client_id=*********&redirect_uri=https://mysite.com/callback.php&state=123456&scope=offline_access
Sample redirect URI response with code
and state
in query string:
https://mysite.com/callback.php?code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3&state=123456
Validate that the response is authentic by verifying that the state
value matches the value sent in the request. Extract the authorization code
from the response, then include it in a request for an access token.
Access token request
To request an access token, send a POST request to the following endpoint with the listed parameters:
https://api.intacct.com/ia/api/v1/oauth2/token
Parameter |
Value |
---|---|
grant_type |
authorization_code |
code |
The authorization code from the previous response |
redirect_uri |
The redirect URI set for your application in the Sage App Registry |
client_id |
Your application's client ID |
client_secret |
Your application's client secret |
Sample access token request:
curl --location --request POST 'https://api.intacct.com/api/v1/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IjkyZDRkY2Y0MTRlNmEyYzNkNzhkLlNhZ2VfSW50YWNjdF9VSS5hcHAuc2FnZS5jb20iLCJjbnlJZCI6Im9hdXRoMiIsImF1dGh6Q29kZSI6IjQ2MTkyMTYxNGZmMTM5ODcwMWQxY2UzOTdjZjI5M2M3ZWUwNDY5MjUiLCJ1c2VySWQiOiJBZG1pbiJ9.49P6x_nOqwTe5_Cr-MiMYTI2q9KOsvlyIGzTQgk7nc4' \
--data-urlencode 'redirect_uri=https://mysite.com/callback.php' \
--data-urlencode 'client_id=*********' \
--data-urlencode 'client_secret=*********'
Sample response, if a refresh token was requested in the authorization code request:
{
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FwaS5pbnRhY2N0LmNvbSIsImlhdCI6MTcyNjIxODkyMSwiZXhwIjoxNzI2MjIyNTIxLCJjbGllbnRJZCI6ImQ0ZjJiNmIzMTgxNzRiOWE2MGE3LklOVEFDQ1QuYXBwLnNhZ2UuY29tIiwiY255SWQiOiJvYXV0aDJfbWFpbjIiLCJjbnlLZXkiOiI0NTIwODgwMiIsInVzZXJJZCI6IkFkbWluIiwidXNlcktleSI6IjEiLCJzZXNzaW9uSWQiOiJ1MHRGV1UtdEpRTjNjSnlNeTRBVHV0MzhBM1p3bkx0TFJWbE5YUEhoZDNDY2pNdUFFN3MwRlFOMyIsImVudGl0eUtleSI6IjQiLCJlbnRpdHlJZCI6IkNlbnRyYWwgUmVnaW9uIn0.bWD3UmTeKa1Y-R-ZJDg1NwaZcAfcvpeBxWZALNQkZFQ",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IjkyZDRkY2Y0MTRlNmEyYzNkNzhkLlNhZ2VfSW50YWNjdF9VSS5hcHAuc2FnZS5jb20iLCJjbnlJZCI6Im9hdXRoMiIsInJlZnJlc2hUb2tlbiI6IjEwNjlmMjkzN2E1YTgwNGY2MzM4MDQyZWNhMTQyYTMyMTcxYjBhZTgifQ.qlXFKgGpEIJXY2CnEyuedS9IQqRpQP52IhQULzNSF_w",
"expires_in": 43200
}
Refresh token request
To request a refresh token, send a POST request to the following endpoint with the listed parameters:
https://api.intacct.com/ia/api/v1/oauth2/token
Parameter |
Value |
---|---|
grant_type |
refresh_token |
refresh_token |
The refresh token from the previous response |
client_id |
Your application's client ID |
client_secret |
Your application's client secret |
entity_id |
(optional) The ID of the entity that you want the user to have access to. Default is a top-level access token. |
Sample refresh token request:
curl --location --request POST 'https://api.intacct.com/api/v1/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IjkyZDRkY2Y0MTRlNmEyYzNkNzhkLlNhZ2VfSW50YWNjdF9VSS5hcHAuc2FnZS5jb20iLCJjbnlJZCI6Im9hdXRoMiIsInJlZnJlc2hUb2tlbiI6IjEwNjlmMjkzN2E1YTgwNGY2MzM4MDQyZWNhMTQyYTMyMTcxYjBhZTgifQ.qlXFKgGpEIJXY2CnEyuedS9IQqRpQP52IhQULzNSF_w' \
--data-urlencode 'client_id=92d4dcf414e6a2c3d78d.app.sage.com' \
--data-urlencode 'client_secret=a55a58f1aeaf09116cbe1bf28025c183e778268c'
Sample response:
{
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FwaS5pbnRhY2N0LmNvbSIsImlhdCI6MTcyNjIxODkyMSwiZXhwIjoxNzI2MjIyNTIxLCJjbGllbnRJZCI6ImQ0ZjJiNmIzMTgxNzRiOWE2MGE3LklOVEFDQ1QuYXBwLnNhZ2UuY29tIiwiY255SWQiOiJvYXV0aDJfbWFpbjIiLCJjbnlLZXkiOiI0NTIwODgwMiIsInVzZXJJZCI6IkFkbWluIiwidXNlcktleSI6IjEiLCJzZXNzaW9uSWQiOiJ1MHRGV1UtdEpRTjNjSnlNeTRBVHV0MzhBM1p3bkx0TFJWbE5YUEhoZDNDY2pNdUFFN3MwRlFOMyIsImVudGl0eUtleSI6IjQiLCJlbnRpdHlJZCI6IkNlbnRyYWwgUmVnaW9uIn0.bWD3UmTeKa1Y-R-ZJDg1NwaZcAfcvpeBxWZALNQkZFQ",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IjkyZDRkY2Y0MTRlNmEyYzNkNzhkLlNhZ2VfSW50YWNjdF9VSS5hcHAuc2FnZS5jb20iLCJjbnlJZCI6Im9hdXRoMiIsInJlZnJlc2hUb2tlbiI6IjEwNjlmMjkzN2E1YTgwNGY2MzM4MDQyZWNhMTQyYTMyMTcxYjBhZTgifQ.qlXFKgGpEIJXY2CnEyuedS9IQqRpQP52IhQULzNSF_w",
"expires_in": 43200
}
Client credentials grant type
The client credentials grant type is supported for applications needing direct access without user interaction.
To use the client credentials grant type, the client application must be associated with a Web Services user and explicitly authorized in your company's configuration:
-
Create a Web Services user:
- If you already have a Web Services user defined for your integration, you can skip this step.
- Log in to your company and navigate to Company > Admin > Web Services Users > Add .
- Create a new Web Services user and assign the necessary permissions or role.
-
Authorize the client application:
- Navigate to Company > Setup > Company > [Edit] > Security > Authorized Client Applications > Add .
- Enter the Client ID for your application.
- Enter the Web Services User ID created in step 1. This field is case-sensitive, so ensure you enter it exactly as it was created.
After these steps are completed, your client application is authorized to request client credentials tokens.
To request client credentials tokens, send a POST request to the following endpoint with the listed parameters, including either username
or session_id
:
https://api.intacct.com/ia/api/v1/oauth2/token
Parameter |
Value |
---|---|
grant_type |
client_credentials |
client_id |
Your application's client ID |
client_secret |
Your application's client secret |
username |
(optional) User ID to log in as, in userId@companyId|entityId format. Required if not using session_id . |
session_id |
(optional) Valid UI or API session ID. Required if not using username . |
Sample client credentials request with username
:
curl -s --request POST 'https://api.intacct.com/ia/api/v1/oauth2/token' \
--header 'Content-Type: application/json' \
--data-raw '{
"grant_type": "client_credentials",
"client_id": "*********",
"client_secret": "*********",
"username": "Admin@oauth2_main2|Central Region" }'
Sample client credentials request with session_id
:
curl -s --request POST 'https://api.intacct.com/ia/api/v1/oauth2/token' \
--header 'Content-Type: application/json' \
--data-raw '{
"grant_type": "client_credentials",
"client_id": "*********",
"client_secret": "*********",
"session_id": "CkAU0b-G_RCd42yvvJvCo7aUEJwmVwcCFNG-xJE6neNsr7ybwuKriRKe" }'
Sample response:
{
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FwaS5pbnRhY2N0LmNvbSIsImlhdCI6MTcyNjIxODkyMSwiZXhwIjoxNzI2MjIyNTIxLCJjbGllbnRJZCI6ImQ0ZjJiNmIzMTgxNzRiOWE2MGE3LklOVEFDQ1QuYXBwLnNhZ2UuY29tIiwiY255SWQiOiJvYXV0aDJfbWFpbjIiLCJjbnlLZXkiOiI0NTIwODgwMiIsInVzZXJJZCI6IkFkbWluIiwidXNlcktleSI6IjEiLCJzZXNzaW9uSWQiOiJ1MHRGV1UtdEpRTjNjSnlNeTRBVHV0MzhBM1p3bkx0TFJWbE5YUEhoZDNDY2pNdUFFN3MwRlFOMyIsImVudGl0eUtleSI6IjQiLCJlbnRpdHlJZCI6IkNlbnRyYWwgUmVnaW9uIn0.bWD3UmTeKa1Y-R-ZJDg1NwaZcAfcvpeBxWZALNQkZFQ",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FwaS5pbnRhY2N0LmNvbSIsImlhdCI6MTcyNjIxODkyMSwiZXhwIjoxNzMzOTk0OTIxLCJjbGllbnRJZCI6ImQ0ZjJiNmIzMTgxNzRiOWE2MGE3LklOVEFDQ1QuYXBwLnNhZ2UuY29tIiwiY255SWQiOiJvYXV0aDJfbWFpbjIiLCJyZWZyZXNoVG9rZW4iOiJiMzdiODg2ODcyNTQwZjk5Yjg2ZWQ4OWFiMjFiMWU0YmNlODMwZjUzIn0.2XgOzUcHQKGG7JkdF6gBHo6vmawld_TeCrjiyAXNBVw",
"expires_in": 43200
}
Entity-level access
Multi-entity companies have a top-level parent entity with one or more sub-entities underneath. These sub-entities may own their records, and the REST API provides mechanisms to interact with them. You must first obtain a top-level access token as described in Authorization code grant type or Client credentials grant type.
Send a single request to a sub-entity
To access records owned by a sub-entity within the multi-entity company structure, use the X-IA-API-Param-Entity
header to specify the entity context, for example Central Region
:
# Get Vendor List with 'X-IA-API-Param-Entity' Header
curl --request GET 'https://api.intacct.com/ia/api/v1/objects/vendor' \
--header 'Content-Type: application/json' \
--header 'X-IA-API-Param-Entity: Central Region' \
--header 'Authorization: Bearer <top_level_access_token>'
Change to a sub-entity access token
You can also switch from a top-level access token to a sub-entity access token. This allows you to utilize the new access token in subsequent REST API calls for creating and retrieving sub-entity records. To obtain the sub-entity token, use the location_id
parameter in the Refresh token request:
# Refresh Token to Get Sub-Entity Access Token
curl -k --request POST 'https://api.intacct.com/ia/api/v1/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'client_id=*********' \
--data-urlencode 'client_secret=*********' \
--data-urlencode 'refresh_token=<refresh_token>' \
--data-urlencode 'location_id=Central Region'
You can now use the new token to access records specific to the sub-entity.
Test your OAuth 2.0 integration
This section provides the steps and PHP code samples for testing your integration in a development environment. This can be done either locally, using a self-signed SSL certificate and a custom domain mapped to localhost
, or with a production domain.
Prerequisites
For local testing:
- Self-signed SSL certificate - Required for HTTPS communication.
-
Hosts file update - Map a custom domain (e.g.,
mycustomdomain.com
) tolocalhost
. - Sage app registry - Add the custom domain to your application's callback URI list. See the Get API keys topic for more details.
For testing with a production domain:
- Valid SSL certificate - Ensure your domain has a valid SSL certificate.
- Domain configuration - Set up the domain and ensure it points to your server.
- Sage app registry - Add the production domain to your application's callback URI list.
Test your integration
You can download and extract the OAuth 2.0 example zip file that contains these code samples:
-
auth_flow_sample.php
-
callback.php
-
exchange_token.php
Replace mycustomdomain
with your domain name. Provide the client ID and client secret values where needed. Make sure to store your credentials securely and exclude files that contain them from your remote repository.
-
Implement the OAuth 2.0 authorization flow.
This script generates an authorization URL and provides a link for obtaining an access token (
auth_flow_sample.php
).<?php define("CALLBACK_URL", "https://mycustomdomain.com/callback.php"); define("AUTH_URL", "https://api.intacct.com/ia/api/v1-beta2/oauth2/authorize"); define("CLIENT_ID", "***********"); define("SCOPE", "offline_access"); // Optional, used to return the refresh token with the access token. $url = AUTH_URL . "?" . "state=active" . "&response_type=code" . "&client_id=" . CLIENT_ID . "&scope=" . SCOPE . "&redirect_uri=" . CALLBACK_URL; ?> <a href="<?php echo $url; ?>">Get Access Token</a>
-
Handle the OAuth 2.0 callback and token exchange.
This script handles the OAuth 2.0 callback and exchanges the authorization code for an access token (
callback.php
).<?php $code = $_GET['code']; $postArray = array( 'grant_type' => 'authorization_code', 'client_id' => '******', 'client_secret' => '*******', 'code' => $code, 'redirect_uri' => 'https://mycustomdomain.com/callback.php' ); $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "https://api.intacct.com/ia/api/v1-beta2/oauth2/token", CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, // Ignore SSL certificate validation CURLOPT_POSTFIELDS => http_build_query($postArray), CURLOPT_HTTPHEADER => array("Content-Type: application/x-www-form-urlencoded") )); $response = curl_exec($curl); $decoded = json_decode($response, true); $access_token = $decoded['access_token']; $refresh_token = $decoded['refresh_token']; curl_close($curl); echo "Access Token: " . $access_token . "<BR><BR>"; ?> Exchage Refresh token for new access token <a href="exchange_token.php?refresh_token=<?php echo $refresh_token; ?>">here</a>.
-
Exchange the refresh token for a new access token.
This script exchanges a refresh token for a new access token. Optionally, you can include an
entity_id
parameter to retrieve an entity-level access token (exchange_token.php
).<?php $refresh_token = $_GET['refresh_token']; $postArray = array( 'grant_type' => 'refresh_token', 'client_id' => '********', 'client_secret' => '********', 'refresh_token' => $refresh_token, 'entity_id' => '10' // Optional, specify entity_id for entity-level access token. Obtain a top-level access token if entity_id is omitted. ); $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "https://api.intacct.com/ia/api/v1-beta2/oauth2/token", CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, // Ignore SSL certificate validation CURLOPT_POSTFIELDS => http_build_query($postArray), CURLOPT_HTTPHEADER => array("Content-Type: application/x-www-form-urlencoded") )); $response = curl_exec($curl); $decoded = json_decode($response, true); $access_token = $decoded['access_token']; curl_close($curl); echo "New Access Token: " . $access_token; ?>
Tutorials
See the PHP tutorial or the Node.js tutorial for more details on how to authenticate with the OAuth2 server, and send requests to the REST API.