Sage Intacct REST – Connection Guide
Increase ROI and transform your organization with the first and only preferred provider of the AICPA for accounting and financial management software for companies of any size.
How to connect to Sage Intacct REST
To create a connection with Sage Intacct, you need to complete the following steps:
- Prerequisites
- Authorize Apideck
- Grant the required permissions
- Enable optional features
- Keeping the connection alive
Prerequisites
Before you can connect Sage Intacct to Apideck, you need:
- An active Sage Intacct company
- A user whose role has permissions for the data you intend to sync (see below). The connection acts as the user who completes the authorization, so that user's permissions become the connection's permissions.
- Admin access, if you need to change permissions or turn on optional features
1. Authorize Apideck
-
Start the connection from Apideck Vault and you will be redirected to Sage Intacct
-
Enter your Company ID, user ID and password
Your Sage company has to authorize the Client ID of the calling application — the value your integration provider gives you. An administrator adds it under Company → Setup → Company → Edit → Security → Authorized Client Applications. Signing in as an admin user during authorization may cover this automatically; if calls still return 403 afterwards, add the Client ID explicitly.
-
Review the requested access and click Accept
2. Grant the required permissions
The connection can only read or write what the authorizing user's role allows. If a
resource returns 403 or a write fails with "The user does not have permission for POST
operation on resource ...", the role is missing that subject.
Go to Company → Admin → Roles → the role of the authorizing user → Subscriptions → module → Permissions, then grant at least List/View (plus the write operations) on the modules you use:
Permissions are granted per operation, so read can succeed while a write on the same resource is refused. Most rows offer Add/Edit/Delete, but some use different verbs — Customer refunds, for example, uses Add/Post/Void.
| Module | Needed for |
|---|---|
| Accounts Receivable | customers, invoices, credit notes, payments, refunds |
| Accounts Payable | suppliers, bills, bill payments |
| General Ledger | ledger accounts, journal entries |
| Company | departments, locations, classes, employees, contacts, attachments, companies, subsidiaries, company info |
| Cash Management | bank accounts, bank feeds, expenses |
| Order Entry | quotes |
| Taxes | tax rates |
| Projects | projects |
| Inventory Control | items (invoice items) |
| Time & Expenses | expense reports, expense categories |
Every resource this connector serves appears above. If an endpoint returns 403 with no other
detail, the module in this table is the one to check first — Sage does not name the missing
permission in the error.
Order Entry is easy to miss because quotes are the capability this connector adds over the
XML-based Sage Intacct connector. Without it, listing quotes returns 403, and creating one
fails with "This Sage company has no active quote transaction definition" — which reads as a
configuration problem in your Sage company rather than a missing grant.
If permissions are assigned per-user rather than by role in your company, use Company → Admin → Users → the user → Permissions instead.
3. Enable optional features
Some resources are switched off by default in Sage Intacct. Until the feature is turned on, its permission subject does not appear in the permissions list — so if you cannot find a permission for something below, enable the feature first.
Customer refunds
Required for the Refunds resource. The order below matters — the permission does not exist until the feature is switched on.
- Go to Accounts Receivable → Setup → Configuration
- Scroll to the Customer refunds section and enable it
- Set the GL account refunds post to, the journal, and the summary frequency. All three are required before the page will save.
- Optionally enable Record paid refunds and Process refund payments in Accounts Payable — but see the caveat below before turning the second one on
- Now grant the Customer refunds permission on the authorizing user's role (Company → Admin → Roles → role → Subscriptions → Accounts Receivable → Permissions)
The refunds permission uses different operations to the rest of Accounts Receivable.
Most AR rows offer List / View / Add / Edit / Delete. Customer refunds offers
List / View / Add / Post / Void — Post and Void govern the lifecycle instead of
Edit and Delete. Tick all five if you intend to write refunds.
Permissions are granted per operation. Reading refunds and writing refunds are separate
grants, so GET /accounting/refunds can succeed while POST still fails with "The user
does not have permission for POST operation on resource
objects/accounts-receivable/customer-refund". If you see that, the role has read but not
Add.
A refund cannot be created on its own. Sage refunds something that already exists, so a create must reference a credit memo, customer advance, over-payment or negative invoice. A request without one is rejected with "No refund details were found in the request."
If you enable the Accounts Payable route, refunds settle through AP and every refunded customer must be linked to a vendor record. Without that link a refund fails with "Cannot find a linked vendor for this customer." Refunds paid by EFT do not need the link, so if you are not using AP settlement, leave that option off.
An empty list is not an error. Enabling the feature does not create data —
GET /accounting/refunds returns 200 with an empty array until a refund exists in Sage.
Quotes, if your company has more than one quote type
Sage stores quotes as order-entry documents, and every order-entry document belongs to a
transaction definition you create yourself (Order Entry → Setup → Transaction
Definitions). There is no universal "quote" type — one company calls it SALESQUOTES,
another Sales Quote-Inventory.
Reading quotes, updating them and deleting them all work with no setup: the connector reads the definition off the quote itself.
Creating a quote is the only case that can be ambiguous, because there is no existing record to read:
- One active quote definition — nothing to do, it is used automatically.
- More than one — set the one you want as Quote Transaction Definition on the
connection. Until you do,
POST /accounting/quotesis rejected with an error listing the definitions it found. It will not pick one for you: the definition controls the document's whole downstream workflow, so guessing could route quotes into the wrong process.
Tax on invoice and credit-note lines
Apideck does not send per-line tax on invoices or credit notes, because Sage only captures it when the company uses an Advanced Tax solution with multi-line tax enabled. Where that is not configured, Sage either rejects the request outright or — with Simple Tax — accepts it, returns success, and drops the tax silently.
If you need tax written on lines, set the company up under Taxes → Setup → Tax Solutions with an Advanced Tax solution that has multi-line tax switched on, then raise it with Apideck Support so we can enable the mapping against a company that supports it.
Sage's invoice has no header-level tax field at all, so a single aggregate tax figure cannot be written either way.
Multi-entity companies
One connection covers every entity. Authorize with a user at the top level and it reads and writes across all of them — you do not need a connection per entity.
Entities are targeted per record, through the location. In a multi-entity company, a
top-level location is an entity — USA1 is both entity 100 and location 100, the same
record — so setting a line's location_id to that location posts the line to that entity.
This is required, not optional: in a multi-entity company a write with no location is rejected
with "Location is empty. A valid Multi-entity location must be specified". Send location_id
on every line. List your options from Locations; the top-level ones are your entities, and
any sub-locations beneath them narrow the posting further within the same entity.
Sage applies this at the line, so the entity is a property of the posting rather than of the connection — and the document header's own entity field is usually left empty even on records written this way.
Because of that, the x-apideck-company-id header has no effect on this connector: there is
nothing per-request for it to scope. It is accepted and ignored rather than rejected, so do not
rely on it to narrow a request — use the line location instead.
Acting as a sub-entity rather than the top-level company. Sage offers two mechanisms for
this beyond the line location: the X-IA-API-Param-Entity header, which scopes a single request
to one entity, and entity_id / location_id passed on the refresh_token grant, which returns
an access token that is itself scoped to that entity. Both live on Sage's token and request layer
rather than in the unified fields this connector maps, so the line location above stays the route
for ordinary reads and writes.
4. Keeping the connection alive
Signing in to the Sage Intacct web UI with the same user can invalidate the API token.
Sage ties access tokens to a session and documents that a token becomes inactive when its
session no longer exists. If calls suddenly start failing with REST-2102 Token is not valid,
reconnect through Vault.
To avoid this, authorize the connection with a dedicated integration user that nobody signs in with interactively.
Revoking one token revokes every token for that user and company. Sage pools tokens per user and company pair, so revoking any access or refresh token also revokes all the others issued for the same pair. If the Sage user who authorized this connection has also authorized another integration on the same company, revoking either side's token breaks the other one too, with no warning until its next call fails. Giving each integration its own dedicated Sage user keeps them independent.
There is no token handling on your side. Apideck refreshes the Sage access token for you
off the refresh token, which Sage issues because the authorization request asks for
offline_access. What you may see instead is the connection turning invalid in Vault if a
refresh stops working — that is the signal to reconnect.
Sage documents neither a refresh-token expiry nor whether a refresh token is replaced when it is used, so there is no published lifetime to schedule around. Treat re-authorization as a normal operational step: watch for the connection going invalid in Vault and reconnect through it.
Things worth knowing
These are Sage Intacct behaviours rather than Apideck limitations, but they surface through the API and are easy to mistake for bugs:
- Records are identified by an internal key. The
idApideck returns is Sage's record key (used in its URLs). The human-readable number you see in the Sage UI — customer number, account number — is returned asdisplay_id. - Expense types require a valid GL account.
- Income statement accounts must "close to" another account before they can be edited.
- Deleting an employee does not delete its contact record. Employees require a contact, which Apideck creates for you from the employee's name, email, phone and address; that contact remains in Sage after the employee is removed.
- Employee
display_namemust be unique, because it becomes the name of the contact record the employee references. - Line items on list responses cost an extra query. Sage's query service cannot return child collections directly, so on list operations (bills, invoices, credit notes, quotes, journal entries, expense reports, expenses, payments, bill payments) this connector issues one additional batched query per page and attaches the lines to each record. Line items are present either way — this only affects latency, not completeness.
- Some bills can fail to load with a
hasForm1099serializer error. This is a defect on Sage's own side, not invalid data on your record — Sage's get-by-id endpoint rejects a value it stored itself, for every bill belonging to a 1099-configured vendor. This connector detects the error and transparently recovers the record through the query service instead, so in practice you should not see it; if you do, it means the automatic recovery failed to find the record.
Moving from the Sage Intacct (XML) connector
Both connectors talk to the same Sage company, so you can run them side by side while you move and cut over per resource. They are separate connections — migrating means authorizing this one, not converting the old one.
What you gain by moving
- Customer refunds — this connector only. Sage exposes refunds through the REST API, and the XML gateway's object model does not carry them.
- Quote creation — the XML connector can update and delete quotes but not create them.
- Item and tracking categories on credit-memo lines — on the XML connector those are mapped on invoices only, so credit memos lose them.
- OAuth rather than a Sender ID plus stored company/user credentials.
What you lose, and it is not a backlog item
- Financial reports — balance sheet, profit and loss, aged debtors and account hierarchies. Sage's REST reporting endpoints generate downloadable files asynchronously instead of returning queryable data, so this connector cannot serve them at all. If you depend on them, keep the XML connection for reporting and use this one for everything else.
What carries over unchanged
- Attachments — supported on both connectors. Here they cover invoices, bills, expenses, expense reports and quotes; on the XML connector, invoices and bills only.
What is simply not mapped yet (the REST API supports all of it, so ask Apideck Support if you need it): checking/savings account types, GL account groups.
Identifiers do not carry over. Both connectors use Sage's internal record key as id, but
verify against a couple of records before repointing anything — the XML connector has a history
of ambiguity between the record number and the human-readable id, and a mismatch here silently
links the wrong records.
Behaviour that changes on write. Line-level tax is not sent by this connector unless your company runs Advanced Tax with multi-line tax enabled, and journal entry numbers are assigned by Sage rather than settable. Both are covered above.
Not available through this connector
Financial reports (balance sheet, profit and loss, aged debtors, account hierarchies) cannot be synced — see "What you lose" under Moving from the Sage Intacct (XML) connector above for why and for the workaround.