Summary and recommendation
Sage Intacct exposes user management through an XML-over-HTTPS API - not REST or JSON.
All requests POST XML documents to https://api.intacct.com/ia/xml/xmlgw.phtml, and all responses are XML.
Authentication requires a Web Services sender ID registered with Sage support and explicitly whitelisted per company in Company > Company Info > Security;
session tokens expire after approximately 30 minutes of inactivity and must be refreshed.
The Sage Business Cloud Accounting product is an entirely separate API surface with its own OAuth 2.0 flow, base URL (https://api.accounting.sage.com/v3.1/), and data model - the two APIs are not interchangeable.
For teams building identity graph automation across both Sage products and adjacent systems, an MCP server with 60+ deep IT/identity integrations can normalize these divergent auth and data models into a unified provisioning layer.
API quick reference
| Has user API | Yes |
| Auth method | Session-based XML API (Sage Intacct): login credentials or web-services sender ID + password exchanged for a session token. Sage Accounting (Business Cloud): OAuth 2.0 Authorization Code flow. |
| Base URL | Official docs |
| SCIM available | No |
| SCIM plan required | Enterprise |
Authentication
Auth method: Session-based XML API (Sage Intacct): login credentials or web-services sender ID + password exchanged for a session token. Sage Accounting (Business Cloud): OAuth 2.0 Authorization Code flow.
Setup steps
- For Sage Intacct: Register a Web Services sender ID with Sage Intacct support; authorize the sender ID in Company > Company Info > Security.
- For Sage Intacct: POST an XML
block containing or credentials to obtain a session token. - For Sage Business Cloud Accounting: Register an application at developer.sage.com to obtain a client_id and client_secret.
- For Sage Business Cloud Accounting: Redirect the user to https://www.sageone.com/oauth2/auth/central?response_type=code&client_id=...&redirect_uri=...&scope=...
- Exchange the returned authorization code for an access_token and refresh_token via POST to https://oauth.accounting.sage.com/token.
- Include the access_token as a Bearer token in the Authorization header for subsequent API calls.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| full_access | Full read/write access to all resources in Sage Business Cloud Accounting | Creating, updating, and deactivating users via Sage Accounting API |
| readonly | Read-only access to all resources | Listing and reading user records |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| LOGINID | string | Unique login username | required | immutable | Sage Intacct only |
| USERTYPE | string | User type: 'business user', 'employee user', 'view only user', 'dashboard user', 'platform user' | required | optional | Sage Intacct only |
| FIRSTNAME | string | First name | required | optional | |
| LASTNAME | string | Last name | required | optional | |
| EMAIL1 | string | Primary email address | required | optional | |
| EMAIL2 | string | Secondary email address | optional | optional | Sage Intacct only |
| STATUS | string | Active/Inactive status | optional | optional | Sage Intacct: 'active' or 'inactive' |
| SSO_ENABLED | boolean | Whether SSO is enabled for the user | optional | optional | Sage Intacct; requires SSO configured at company level |
| SSO_FEDERATED_SSONAME | string | Federated SSO identifier (e.g., IdP username/email) | optional | optional | Sage Intacct SSO field |
| CONTACTINFO.CONTACT.NAME | string | Full display name from linked contact record | optional | optional | Sage Intacct nested contact object |
| ROLES | array | List of role names assigned to the user | optional | optional | Sage Intacct role-based permissions |
| PERMISSIONS | object | Explicit application/module permissions | optional | optional | Sage Intacct; alternative to roles |
| id | string | Unique user ID (UUID) | system-generated | immutable | Sage Business Cloud Accounting REST API |
| string | User email address | required | optional | Sage Business Cloud Accounting REST API | |
| first_name | string | First name | required | optional | Sage Business Cloud Accounting REST API |
| last_name | string | Last name | required | optional | Sage Business Cloud Accounting REST API |
| created_at | datetime | ISO 8601 creation timestamp | system-generated | immutable | Sage Business Cloud Accounting REST API |
| updated_at | datetime | ISO 8601 last-updated timestamp | system-generated | system-generated | Sage Business Cloud Accounting REST API |
Core endpoints
Create User (Sage Intacct)
- Method: POST
- URL:
https://api.intacct.com/ia/xml/xmlgw.phtml - Watch out for: The sender ID must be explicitly authorized in the target Sage Intacct company before API calls succeed. Missing this step returns an authorization error.
Request example
<?xml version="1.0"?>
<request><control>...</control><operation><authentication>...</authentication>
<content><function controlid="1"><create><USERINFO>
<LOGINID>jdoe</LOGINID><USERTYPE>business user</USERTYPE>
<FIRSTNAME>Jane</FIRSTNAME><LASTNAME>Doe</LASTNAME>
<EMAIL1>jdoe@example.com</EMAIL1><STATUS>active</STATUS>
</USERINFO></create></function></content></operation></request>
Response example
<response><operation><result><status>success</status>
<function>create</function><controlid>1</controlid>
<data><userinfo><LOGINID>jdoe</LOGINID></userinfo></data>
</result></operation></response>
Read User (Sage Intacct)
- Method: POST
- URL:
https://api.intacct.com/ia/xml/xmlgw.phtml - Watch out for: The key for USERINFO is LOGINID, not a numeric ID. Using a numeric RECORDNO will fail.
Request example
...<function controlid="2"><read>
<object>USERINFO</object>
<keys>jdoe</keys>
<fields>*</fields>
</read></function>...
Response example
<data><userinfo>
<LOGINID>jdoe</LOGINID>
<FIRSTNAME>Jane</FIRSTNAME>
<STATUS>active</STATUS>
</userinfo></data>
Query/List Users (Sage Intacct)
- Method: POST
- URL:
https://api.intacct.com/ia/xml/xmlgw.phtml - Watch out for: readByQuery returns a maximum of 1000 records per page; use
to paginate beyond that.
Request example
...<function controlid="3"><readByQuery>
<object>USERINFO</object>
<fields>LOGINID,FIRSTNAME,LASTNAME,EMAIL1,STATUS</fields>
<query>STATUS = 'active'</query>
<pagesize>100</pagesize>
</readByQuery></function>...
Response example
<data listtype="USERINFO" count="2" totalcount="2">
<userinfo><LOGINID>jdoe</LOGINID>...</userinfo>
<userinfo><LOGINID>asmith</LOGINID>...</userinfo>
</data>
Update User (Sage Intacct)
- Method: POST
- URL:
https://api.intacct.com/ia/xml/xmlgw.phtml - Watch out for: Only include fields you intend to change; omitted fields retain their current values. LOGINID cannot be changed after creation.
Request example
...<function controlid="4"><update><USERINFO>
<LOGINID>jdoe</LOGINID>
<STATUS>inactive</STATUS>
</USERINFO></update></function>...
Response example
<result><status>success</status>
<function>update</function>
<controlid>4</controlid>
</result>
Delete User (Sage Intacct)
- Method: POST
- URL:
https://api.intacct.com/ia/xml/xmlgw.phtml - Watch out for: Deleting a user is permanent. Sage recommends setting STATUS to 'inactive' instead of deleting to preserve audit trails.
Request example
...<function controlid="5"><delete>
<object>USERINFO</object>
<keys>jdoe</keys>
</delete></function>...
Response example
<result><status>success</status>
<function>delete</function>
<controlid>5</controlid>
</result>
List Users (Sage Business Cloud Accounting REST)
- Method: GET
- URL:
https://api.accounting.sage.com/v3.1/users - Watch out for: The Sage Business Cloud Accounting user-management endpoints are limited in scope; full user provisioning is primarily handled through the Sage account portal, not the API.
Request example
GET /v3.1/users?$page=1&$items_per_page=20 HTTP/1.1
Authorization: Bearer {access_token}
Response example
{
"$total": 5,
"$page": 1,
"$next": null,
"$back": null,
"$itemsPerPage": 20,
"$items": [{"id":"abc123","email":"jdoe@example.com"}]
}
Get Current User (Sage Business Cloud Accounting REST)
- Method: GET
- URL:
https://api.accounting.sage.com/v3.1/user - Watch out for: Returns the user associated with the OAuth token, not an arbitrary user. Cannot be used to inspect other users without their own token.
Request example
GET /v3.1/user HTTP/1.1
Authorization: Bearer {access_token}
Response example
{
"id": "abc123",
"first_name": "Jane",
"last_name": "Doe",
"email": "jdoe@example.com",
"created_at": "2023-01-15T10:00:00Z"
}
Assign Role to User (Sage Intacct)
- Method: POST
- URL:
https://api.intacct.com/ia/xml/xmlgw.phtml - Watch out for: Providing a ROLES block replaces all existing role assignments. Retrieve current roles first and include them in the update payload to avoid unintended removal.
Request example
...<function controlid="6"><update><USERINFO>
<LOGINID>jdoe</LOGINID>
<ROLES><ROLE><NAME>Accounts Payable</NAME></ROLE></ROLES>
</USERINFO></update></function>...
Response example
<result><status>success</status>
<function>update</function>
<controlid>6</controlid>
</result>
Rate limits, pagination, and events
Rate limits: Sage Intacct: no publicly documented per-minute rate limit; concurrent API session limits apply per company. Sage Business Cloud Accounting: rate limits are documented per application but specific numbers are not publicly disclosed in official docs.
Rate-limit headers: Unknown
Retry-After header: Unknown
Rate-limit notes: Sage Intacct recommends avoiding high-frequency polling and using batch XML requests. No official numeric rate-limit figures are published for either product.
Pagination method: offset
Default page size: 100
Max page size: 1000
Pagination pointer: pagesize / offset (Intacct XML:
and within ); Sage Accounting REST: $page and $items_per_page query params Webhooks available: No
Webhook notes: Sage Intacct does not offer native outbound webhooks for user-management events. Sage Business Cloud Accounting has a limited webhook/notification framework but user lifecycle events are not documented as supported triggers.
Alternative event strategy: Poll the USERINFO object via readByQuery filtering on WHENMODIFIED to detect changes, or use Sage Intacct's Platform Services to build custom event-driven logic.
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: Enterprise
- Endpoint: Not documented
Limitations:
- Sage Intacct does not expose a native SCIM 2.0 endpoint.
- SSO via SAML is supported (Okta, Entra ID) but automated SCIM provisioning requires a third-party connector or custom integration built on the XML API.
- Okta and Entra ID integrations for Sage Intacct use SAML SSO only; user provisioning is not handled via SCIM from the IdP.
- No official SCIM endpoint URL is published by Sage.
Common scenarios
Three scenarios cover the primary lifecycle operations.
To deactivate a departed employee: authenticate for a session token, read the USERINFO record by LOGINID to confirm current state, POST an update setting STATUS='inactive', then verify.
Never use the delete operation - it is irreversible and severs audit history linkage;
Sage explicitly recommends deactivation instead.
To bulk-list active users for an audit: POST a readByQuery on USERINFO filtered by STATUS='active' with pagesize=1000 and offset=0;
check the totalcount attribute in the response and paginate with offset increments of 1000 until the full set is retrieved.
To provision a new user with a role: POST a create USERINFO with LOGINID, USERTYPE, FIRSTNAME, LASTNAME, EMAIL1, and STATUS='active';
then issue a separate update call with the ROLES block, because role assignment in the create payload is not reliably processed across all API versions.
If SSO is required, set SSO_ENABLED=true and SSO_FEDERATED_SSONAME to the exact identifier the IdP sends in the SAML assertion - a mismatch here will silently break SSO login.
Deactivate a departed employee in Sage Intacct
- Authenticate: POST XML login block with sender credentials to obtain a session token.
- Read current user: POST readByQuery or read for USERINFO with LOGINID = target user to confirm current STATUS and roles.
- Update STATUS: POST update USERINFO with LOGINID and STATUS='inactive'.
- Verify: POST read USERINFO and confirm STATUS is 'inactive'.
Watch out for: Do not use the delete operation; deactivation preserves transaction history linked to the user. Inactive users cannot log in but their records remain intact.
Bulk-list all active users for an audit (Sage Intacct)
- Authenticate to obtain a session token.
- POST readByQuery on USERINFO with query STATUS = 'active', pagesize=1000, offset=0.
- Check totalcount in the response; if totalcount > 1000, repeat with offset=1000, 2000, etc. until all records are retrieved.
- Parse LOGINID, FIRSTNAME, LASTNAME, EMAIL1, USERTYPE, and ROLES from each record.
Watch out for: readByQuery caps at 1000 records per call. Large companies must paginate using the offset parameter. The totalcount attribute in the response indicates the full result set size.
Provision a new user with a role via Sage Intacct XML API
- Authenticate with sender ID and company credentials to get a session token.
- POST create USERINFO with required fields: LOGINID, USERTYPE, FIRSTNAME, LASTNAME, EMAIL1, STATUS='active'.
- In the same or a subsequent request, POST update USERINFO including the ROLES block with the desired role names.
- If SSO is required, POST update USERINFO setting SSO_ENABLED=true and SSO_FEDERATED_SSONAME to the user's IdP identifier.
Watch out for: ROLES in the create payload may not always be processed reliably in all API versions; a separate update call for role assignment is safer. SSO_FEDERATED_SSONAME must exactly match the identifier sent by the IdP in the SAML assertion.
Why building this yourself is a trap
The most common integration failure is treating the ROLES field as additive: the XML API replaces all existing role assignments with whatever is in the update payload. Always read current roles before writing, or you will silently strip access.
A second trap is the sender ID authorization requirement - a single sender ID must be individually whitelisted in every Sage Intacct company it targets; missing this returns a generic authorization error with no indication of the root cause.
Rate limits are not publicly documented for either product, but Sage Intacct recommends batch XML requests over high-frequency polling; concurrent session limits per company apply and are enforced without warning.
Finally, Sage Intacct has no native SCIM 2.0 endpoint: Okta and Entra ID integrations support SAML SSO only, and automated provisioning requires a custom integration built on the XML API or a third-party connector.
Automate Sage workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.