The Data Access API provides read-only access to Fusion reporting views. These views were designed for broad reporting across the Fusion platform, meaning they often contain a large number of columns and can span millions of rows depending on the dealership.
All views are accessed through a single GET endpoint. Unlike Fusion's purpose-built APIs, RDA views return everything by default — every column, every matching row — unless you tell them not to. That means the quality of your results depends entirely on how you structure your request.
When a dedicated API exists for the data you need, the API is generally the preferred method — APIs are optimized for specific use cases and include built-in business rules and validation. RDA is the right tool when you need read-only access to data that isn't available through an API, or when you need a broad reporting view across Fusion data.
Your requests run against the customer's shared SQL database — the same database that Fusion relies on for day-to-day dealership operations. A well-structured request returns fast and has minimal impact. A poorly structured one can affect database performance for every user at that dealership. Large initial data pulls are recommended to run outside of customer business hours or at a time that will be least impactful to performance.
select clause on every request — only ask for the columns you needfilter to narrow results — use AddDate or LastUpdate as a delta for incremental syncssort parameter — sorting is done on the database; sort in your app insteadAll RDA requests go through a single endpoint:
https://api.karmak.io/ops/DataAccess/Frw/{view}[?page][&pagesize][&filter][&select]
The view name is found in the URL section of each view's documentation page. Some view properties are version-specific — make sure you've selected the correct Fusion version for the customer.
RDA views can contain dozens of columns. The select parameter tells the API to return only the ones your application actually needs. This is the single biggest thing you can do to improve performance.
Do: Include a select clause on every request. Unless your application truly needs every column in a view, you should always specify only the ones you use.
Don't: Omit the select clause. Without it, the API returns every column in the view, which can increase query time, payload size, and database load.
select={columnname},{columnname},{columnname}
| Parameter | What it does |
|---|---|
select=UserName | returns only the UserName field |
select=UserName,FirstName,LastName | returns UserName, FirstName, and LastName |
Filters control which rows are returned. Without them, you're asking the API to scan and return every record in the view — which on a busy dealership could be hundreds of thousands of rows.
Do: Filter by date range for incremental syncs, by branch when you only need specific locations, or by any criteria that narrows results to what your app actually processes.
Don't: Send requests with no filter. Unfiltered requests on large views take longer to process and return significantly more data than most applications need.
AddDate and LastUpdate columns. These can be used as a delta to pull only new or recently changed records since your last sync. For example, filtering on LastUpdate[GT]2025-05-01T00:00:00 returns only records modified after that date. Store the timestamp of your last successful sync and use it as your next filter value — this can be significantly more efficient than pulling the full dataset every time.filter={columnname}[{operation}]{criteria}
| to separate values with the IN operator| Parameter | What it does |
|---|---|
filter=CustomerKey[EQ]123456 | Customer Key = 123456 |
filter=InvoiceID[LTE]555667,InvoiceStatus[EQ]Open | Invoice ID <= 555667 and status is Open |
filter=InvoiceDate[GT]01-01-2023,InvoiceStatus[IN]paid|posted | Invoice Date after 1/1/2023 and status is Paid or Posted |
| Code | Meaning |
|---|---|
EQ | equals |
LT | less than |
LTE | less than or equal to |
GT | greater than |
GTE | greater than or equal to |
NE | not equal to |
IN | in |
filter=invoiceID[EQ]NULL returns records where Invoice ID is null. filter=invoiceID[NE]NULL returns records where Invoice ID has data.| Format | Example |
|---|---|
| MM-DD-YYYY HH:MM:SS | 11-08-2023 08:00:00 |
| YYYY-MM-DD HH:MM:SS | 2023-11-08 08:00:00 |
| YYYY-MM-DDTHH:MM:SS | 2023-11-08T08:00:00 |
Use page and pagesize to retrieve data in manageable chunks. Page numbering starts at 1. Requesting a page beyond the available data returns an empty result.
Do: Make calls synchronously. Send a request, wait for the response, then send the next one. Use reasonable page sizes (100–500 records).
Don't: Send multiple page requests at the same time. Parallel calls stack concurrent queries on the shared SQL database and can cause timeouts for your integration and for dealership users.
page={pagenumber}&pagesize={pagesize}
| Parameter | What it does |
|---|---|
page=1&pagesize=100 | start at page 1, return 100 results |
page=12&pagesize=500 | start at page 12, return 500 results |
The sort parameter tells the database to order the result set before returning it. This adds processing overhead to every request and, on large views, can significantly slow down response times.
Do: Retrieve the data without sorting and sort it in your application after receipt. The default sort order is sufficient for consistent paging.
Don't: Use the sort parameter unless you have a specific technical reason that can't be solved client-side. Most integrations don't need server-side sorting.
If you do need to use sort:
sort={order}{columnname},{order}{columnname}
- for descending| Parameter | What it does |
|---|---|
sort=invoiceID | ascending by Invoice ID |
sort=-invoicestatus,-invoiceID | descending by Invoice Status, then descending by Invoice ID |
| Example | Result |
|---|---|
select=UserName&sort=UserID | fail |
select=UserName,FirstName,LastName&sort=UserID,AddDate | fail |
select=UserName,UserID&sort=UserID | pass |
select=UserName,UserID,LastName&sort=UserID,UserName | pass |
Aliasing lets you rename columns in the response. Useful when your application expects different field names than what the view returns.
select={columnname}:{newname},{columnname}:{newname}
select=UserName:User returns:
[
{ "User": "MyUser" },
{ "User": "MyUser2" }
]
select=UserName:User,UserNumber:Id,DOB:Birthday returns:
[
{
"User": "MyUser",
"ID": "1",
"Birthday": "03-02-1973"
},
{
"User": "MyUser2",
"ID": "2",
"Birthday": "01-21-1985"
}
]