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. Client applications can also use the proof key for code exchange (PKCE) flow, with the authorization code grant type, for mobile apps and public clients where storing the client secret is unsafe.

Use the OAuth 2.0 authorization code or the client credentials grant type to obtain an access token, then include it in REST API requests to access your company's data. The tokens generated by Sage Intacct are JSON Web Tokens (JWT). JWT tokens are designed for securely exchanging information encoded as JSON objects. They contain the ID of the currently logged-in user, the company ID, and other required information. You can examine the components of your access token by visiting JWT.

The company to which you will be sending API requests must authorize your sender ID. You can either add your web sender ID to the Company Security tab or log in as an admin user when approving the OAuth authorization request.

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:

  1. The user signs into your application and clicks a link to authorize your application to access their Sage Intacct data.
  2. A Sage Intacct log in screen is displayed and the user logs in.
  3. The user is prompted to grant your application access to their data and must click Accept .
  4. The authentication server responds by redirecting the user to the registered callback URI with an authorization code in the query string.
  5. Your application captures the authorization code and uses it to request an access token.
  6. 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:

Copy
Copied
    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:

Copy
Copied
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:

Copy
Copied
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:

Copy
Copied
{
  "token_type": "Bearer",
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6ImRhaXN5LmJsdWUifQ.9uMW6BqnYNTbS3x7XYSSU1rq_jxi29F7FfWTEOjk2-4",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6InJvc2Uud2hpdGUifQ.SdOUDrZE80FUNq9hO0ZhgXPOttb4WhXRrVOGzRhbC1I",
  "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:

Copy
Copied
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.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6ImRhaXN5LmJsdWUifQ.9uMW6BqnYNTbS3x7XYSSU1rq_jxi29F7FfWTEOjk2-4' \
--data-urlencode 'client_id=92d4dcf414e6a2c3d78d.app.sage.com' \
--data-urlencode 'client_secret=a55a58f1aeaf09116cbe1bf28025c183e778268c'

Sample response:

Copy
Copied
{
  "token_type": "Bearer",
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6ImRhaXN5LmJsdWUifQ.9uMW6BqnYNTbS3x7XYSSU1rq_jxi29F7FfWTEOjk2-4",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6InJvc2Uud2hpdGUifQ.SdOUDrZE80FUNq9hO0ZhgXPOttb4WhXRrVOGzRhbC1I",
  "expires_in": 43200
}

Authorization code grant type with PKCE flow

The proof key for code exchange (PKCE) grant type is an extension of the OAuth 2.0 authorization code grant type. It adds an additional layer of security by requiring the client to generate a cryptographically random secret called the code verifier that is used to generate a code challenge sent to the authorization server. This prevents authorization code interception attacks. PKCE is recommended for mobile apps and public clients where storing the client secret is unsafe.

Follow these steps to get an access token using the PKCE flow:

  1. Generate a cryptographically random code verifier (43-128 characters):
    Copy
    Copied
    uuidgen | tr -d '-' | cut -c1-32 | base64
    code_verifier = "zWiRBuiUcmnIbPBCoNqA5cWDFuaEZwZ7jLJJGJ4P3NQ"
  2. Generate the code challenge by running the code verifier through a one-way hash function. This is typically done by taking the SHA256 hash of the code verifier and then URL-encoding the result:
    Copy
    Copied
    echo -n zWiRBuiUcmnIbPBCoNqA5cWDFuaEZwZ7jLJJGJ4P3NQ | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '='
    code_challenge = "manPXpjp75EFeofO+YWtY3gIPp0S6/CJ+ciRJyYIonw"
  3. Create an authorization request by redirecting the user to the authorization server’s authorize endpoint.

    https://api.intacct.com/ia/api/v1/oauth2/authorize

    Include the following parameters:

    • response_type - code
    • client_id - Your application's client ID
    • state - A random value to use to validate the response
    • redirect_uri - The redirect URI set for your application in the Sage App Registry
    • code_challenge - The code challenge generated in the prior step
    • code_challenge_method - S256

    Sample PKCE authorization request:

    Copy
    Copied
    https://api.intacct.com/ia/api/v1/oauth2/authorize?response_type=code&client_id=d4f2b6b318174b9a60a7.INTACCT.app.sage.com&state=0d091469-c244-4056-a23d-49e6a6cc93d7&redirect_uri=https://mysite.com/callback&code_challenge=manPXpjp75EFeofO-YWtY3gIPp0S6_CJ-ciRJyYIonw&code_challenge_method=S256
  4. Use your credentials to log in and grant the requested permissions to receive the authorization code:
    Copy
    Copied
    {
      "code": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImQ0ZjJiNmIzMTgxNzRiOWE2MGE3LklOVEFDQ1QuYXBwLnNhZ2UuY29tIiwiY255SWQiOiJvYXV0aDJpaSIsImF1dGh6Q29kZSI6IjliMWQ1ZjhkNjNmMGY4NmU3YzU5YjE1MmRkMzg4OWQ5ODJkOTM4NWQiLCJ1c2VySWQiOiJBZG1pbiJ9.EE3jzQQ4--0JM2z7eO3DEBDFD6Nn4S5swyrtkW4Lt9o",
      "state": "0d091469-c244-4056-a23d-49e6a6cc93d7"
    }
  5. Exchange the authorization code for an access token by sending a POST request to the token endpoint. This request must include the code verifier:
    Copy
    Copied
    curl --location 'https://api.intacct.com/ia/api/v1/oauth2/token' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --header 'Cookie: DFT_LOCALE=en_US.UTF-8' \
    --data-urlencode 'grant_type=authorization_code' \
    --data-urlencode 'code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImQ0ZjJiNmIzMTgxNzRiOWE2MGE3LklOVEFDQ1QuYXBwLnNhZ2UuY29tIiwiY255SWQiOiJvYXV0aDJpaSIsImF1dGh6Q29kZSI6IjliMWQ1ZjhkNjNmMGY4NmU3YzU5YjE1MmRkMzg4OWQ5ODJkOTM4NWQiLCJ1c2VySWQiOiJBZG1pbiJ9.EE3jzQQ4--0JM2z7eO3DEBDFD6Nn4S5swyrtkW4Lt9o' \
    --data-urlencode 'redirect_uri=https://mysite.com/callback' \
    --data-urlencode 'code_verifier=zWiRBuiUcmnIbPBCoNqA5cWDFuaEZwZ7jLJJGJ4P3NQ' \
    --data-urlencode 'client_id=*******' | jq
  6. The authorization server verifies the code challenge matches the code verifier and issues an access token:
    Copy
    Copied
    {
     "token_type": "Bearer",
     "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6InJvc2Uud2hpdGUifQ.SdOUDrZE80FUNq9hO0ZhgXPOttb4WhXRrVOGzRhbC1I",
     "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6ImRhaXN5LmJsdWUifQ.9uMW6BqnYNTbS3x7XYSSU1rq_jxi29F7FfWTEOjk2-4",
     "expires_in": 28800
    }

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:

  1. Create a Web Services user:
    • If the company already has a Web Services user defined for your application, you can skip this step.
    • Have an admin user log in to the company and navigate to Company > Admin > Web Services Users > Add .
    • Create a new Web Services user and assign the necessary permissions or role.
  2. 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:

Copy
Copied
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:

Copy
Copied
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:

Copy
Copied
{
  "token_type": "Bearer",
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6ImRhaXN5LmJsdWUifQ.9uMW6BqnYNTbS3x7XYSSU1rq_jxi29F7FfWTEOjk2-4",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6InJvc2Uud2hpdGUifQ.SdOUDrZE80FUNq9hO0ZhgXPOttb4WhXRrVOGzRhbC1I",
  "expires_in": 43200
}

Revoke a token

You may want to revoke an active token when it is no longer needed or if a security concern arises:

  • If you suspect a token has been compromised, revoking it immediately limits potential risk.
  • To ensure inactive or idle sessions are closed as part of a security best practice.
  • If a user's role is downgraded or permissions are reduced, revoking the current token ensures the user can no longer access data beyond their updated permissions.

To revoke an access or a refresh token, send a POST request to the following endpoint with the listed parameters:

https://api.intacct.com/ia/api/v1/oauth2/revoke

Parameter
Value
token Access token or refresh token

Sample revoke token request:

Copy
Copied
curl --location --request POST 'https://api.intacct.com/ia/api/v1/oauth2/revoke' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6ImI1OTc0YjZjNWQ2ZjJmMWVkYjg0LmFwcC5zYWdlLmNvbSIsImNueUlkIjoiR2FyZGVyIFN1cHBsaWVzIiwiYXV0aHpDb2RlIjoiZWIxYTRlZTBiMjVjNjgyYjJkZmMzNzg5OTcxNzFmYmJhYmE2NDA4NyIsInVzZXJJZCI6ImRhaXN5LmJsdWUifQ.9uMW6BqnYNTbS3x7XYSSU1rq_jxi29F7FfWTEOjk2-4'

Sample revoke token response:

Copy
Copied
{
    "revoked": true
}

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 a multi-entity company structure, use the X-IA-API-Param-Entity header to specify the entity ID (company-config/entity.id property), for example Central Region:

Copy
Copied
# 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 a sub-entity token, set the location_id parameter to the sub-entity ID (company-config/entity.id property) for your sub-entity in the Refresh token request:

Copy
Copied
# 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 ) to localhost .
  • 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.

  1. 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).

    Copy
    Copied
    <?php
    
    define("CALLBACK_URL", "https://mycustomdomain.com/callback.php");
    define("AUTH_URL", "https://api.intacct.com/ia/api/v1/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>
  2. 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).

    Copy
    Copied
    <?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/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>.
  3. 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).

    Copy
    Copied
    <?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/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.