Passthrough Requests
Using Agave API's authenticated passthrough request, you can make requests directly to the Source Systems. Passthrough requests allow you to a Source System's endpoints before Agave API supports them in a unified way.
We support passthrough requests in 4 ways:
- JSON Request, for most requests where the Source System has native JSON API endpoints,
- File Download Request, for downloading files,
- Multipart Upload Request, for uploading files, and
- Other Request Types, for Source Systems that do not offer native JSON API endpoints.
1. JSON Requests
API Endpoint
https://api.agaveapi.com/passthrough
For the full specification, see Passthrough (JSON).
Request Header
As with other API requests, you need to include an API-Version
, Client-Id
, Client-Secret
, and Account-Token
. To learn more, see Headers.
Request Body
The request body should be in JSON format with the following parameters:
Key | Type | Description | Example | Required |
---|---|---|---|---|
method | String | The method for the request to the source system. | "GET" | Required |
path | String | The path for the request to the source system. | "/rest/v1.0/projects" | Required |
data | JSON | The data for the request body or query parameters. | { "company_id": 31936 } | Optional |
Example Requests
Get Projects in Procore
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: procore_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "GET",
"path": "/rest/v1.0/projects",
"data": {
"company_id": {companyId}
}
}'
Get Classes in QuickBooks Online
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: quickbooks_online_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "GET",
"path": "/v3/company/{companyId}/query?",
"data": {
"query": "select * from Class"
}
}'
Get Documents Updated Since June 2022 in Aconex
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: aconex_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "GET",
"path": "/api/projects/{projectId}/register/integrity",
"data": {
"everythingsince" : "2022-06-01T02:00:00.000Z"
}
}'
Post an Item in QuickBooks Online
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: quickbooks_online_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "POST",
"path": "/v3/company/4620816365204621010/item?minorversion=4",
"data": {
"Name": "New Concrete",
"Type": "Service",
"PurchaseCost": 1,
"IncomeAccountRef": {
"value": "48",
"name": "Fountains and Garden Lighting"
}
}
}'
Step-by-step Guide
Before starting, you need to reference the API docs for the endpoint you want to use in the Source System.
Example API docs:
Step 1: Identify Method
Identify the method of the request you are trying to make.
Common values:
Method | Description |
---|---|
DELETE | Deletes the specified resource. |
GET | Requests a representation of the specified resource. Should only retrieve data. |
PATCH | Applies partial modifications to a resource. |
POST | Submits an entity to the specified resource. |
PUT | Replaces all current representations of the target resource with the request payload. |
Step 2: Identify Host URL
Find the host URL for the request. You can typically find this in the overview section of API docs.
Examples:
- Aconex:
https://{{domain}}.aconex.com
- Procore:
https://api.procore.com
- QuickBooks Online:
https://quickbooks.api.intuit.com
Step 3: Identify Full URL
Identify the full path of the request you are trying to make.
Examples:
- Aconex get users:
https://{{domain}}.aconex.com/api/user
- Procore get projects:
https://api.procore.com/rest/v1.0/projects
- QuickBooks Online post a new item:
https://quickbooks.api.intuit.com/v3/company/4620816365204621010/item?minorversion=4
Step 4: Add Path
Truncate the host URL (step 2) from the full URL (step 3). That is the path of the request.
Examples:
- Aconex get users:
/api/user
- Procore get projects:
/rest/v1.0/projects
- QuickBooks Online post a new item:
/v3/company/4620816365204621010/item?minorversion=4
Step 5: Add Data Object
Prepare a JSON object to pass in query parameters or a request body.
Examples:
- Aconex get users: no data object needed
- Procore get projects for a specific company:
{ "company_id": 31936 }
- QuickBooks Online post a new item:
{
"Name": "New Concrete",
"Type": "Service",
"PurchaseCost": 1,
"IncomeAccountRef": {
"value": "48",
"name": "Fountains and Garden Lighting"
}
}
Step 6: Get Account Token
To make a request on behalf of a Source System, you will need an Account Token.
Step 7: Make Request
With the method, path, and data parameters filled out, you can make a passthrough request to Agave API:
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: account_token_from_step_6' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "method_from_step1",
"path": "path_from_step4",
"data": { ... }
}'
2. File Download Requests
The structure of this endpoint is identical to JSON Request, but the output is a binary file.
API Endpoint
https://api.agaveapi.com/passthrough-download
For full specification, see Passthrough (File Download).
Example Requests
Download RFI as PDF in Procore
curl --request POST https://api.agaveapi.com/passthrough-download \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: account_token_from_step_6' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "GET",
"path": "/rest/v1.0/projects/{project_id}/rfis/{rfi_id}.pdf"
}'
Download RFI Attachment in Aconex
curl --request POST https://api.agaveapi.com/passthrough-download \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: account_token_from_step_6' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "GET",
"path": "/api/projects/{project_id}/mail/{rfi_id}/attachments/{attachment_id}"
}'
Download Invoice PDF in QuickBooks Online
curl --request POST https://api.agaveapi.com/passthrough-download \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: account_token_from_step_6' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "GET",
"path": "/v3/company/{company_id}/invoice/{invoice_id}/pdf"
}'
3. Multipart Upload Requests
The main reason you would use a multipart passthrough request is so you can upload files in the request body.
API Endpoint
https://api.agaveapi.com/passthrough-multipart
For the full specification, see Passthrough (Multipart).
Request Header
In addition to API-Version
, Client-Id
, Client-Secret
, and Account-Token
, the common Headers you always include, you also need to pass in the path and method of your request.
Header | Description | Example | Required |
---|---|---|---|
Passthrough-Method | The method for the request to the source system. | "POST" | Required |
Passthrough-Path | The path for the request to the source system with query parameters | "rest/v1.0/images?project_id=66738" | Required |
Request Body
The content type of the request body should be in multipart/form-data
. Then, you can follow the documentation on the API you are trying to hit.
Example Requests
Upload a New Image to Procore
curl --request POST 'https://api.agaveapi.com/passthrough-multipart' \
--header 'Api-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: procore_account_token' \
--header 'Passthrough-Path: rest/v1.0/images?project_id=66738' \
--header 'Passthrough-Method: POST' \
--form 'image[data]=@"/path/test.png"'
Upload a New Schedule to Procore
curl --request POST 'https://api.agaveapi.com/passthrough-multipart' \
--header 'Api-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: procore_account_token' \
--header 'Passthrough-Path: rest/v1.0/schedule_integration?project_id=66736' \
--header 'Passthrough-Method: PUT' \
--form 'schedule_integration[file]=@"/path/test.mpp"'
Step-by-step Guide
Before starting, you need to reference the API docs for the endpoint you want to use in the Source System.
Example API docs:
Step 1: Identify Method
Identify the method of the request you are trying to make.
Common values for multipart request:
Method | Description |
---|---|
PATCH | Applies partial modifications to a resource. |
POST | Submits an entity to the specified resource. |
PUT | Replaces all current representations of the target resource with the request payload. |
Step 2: Identify Host URL
Find the host URL for the request. You can typically find this in the overview section of API docs.
Examples:
- Procore:
https://api.procore.com
Step 3: Identify Full URL
Identify the full path of the request you are trying to make, along with the query parameters it requires.
Examples:
- Procore upload schedule:
https://api.procore.com/rest/v1.0/schedule_integration?project_id=123
Step 4: Add Path
Truncate the host URL (step 2) from the full URL (step 3). That is the path of the request.
Examples:
- Procore upload schedule:
/rest/v1.0/schedule_integration?project_id=123
Step 5: Construct Multipart Request Body
Locate the file you want to upload and construct the request body
Examples:
- Procore upload schedule:
'schedule_integration[file]=@"/path/test.mpp"'
Step 6: Get Account Token
To make a request on behalf of a Source System, you will need an Account Token.
Step 7: Make Request
With the method, path, and data parameters filled out, you can make a multipart passthrough request to Agave API:
curl --request POST 'https://api.agaveapi.com/passthrough-multipart' \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Passthrough-Method: method_from_step1' \
--header 'Passthrough-Path: path_from_step4' \
--header 'Account-Token: account_token_from_step_6' \
--form 'form_data_from_step5'
4. Other Request Types
The following explains how to structure passthrough requests to a Source System that does not offer native JSON API endpoints (e.g. QuickBooks Desktop, Viewpoint Vista). Note, the response body for these requests will always be in JSON.
API Endpoint
https://api.agaveapi.com/passthrough
For the full specification, see Passthrough (JSON).
Request Header
As with other API requests, you need to include an API-Version
, Client-Id
, Client-Secret
, and Account-Token
. To learn more, see Headers.
Request Body
Unlike JSON and multi-part passhthrough requests, the request body will depend on the Source System.
QuickBooks Desktop
Since QuickBooks Desktop does not have native JSON APIs, you will need to use its native XML operations to make requests.
Check out QuickBooks Desktop's API Reference to see a list of XML operations that are supported.
These operations can be fine in the XMLOps
tab for each data object.
If you are unable to find the endpoint you need, please contact us at support@agaveapi.com and we should be able to assist.
For example, the below request retrieves a list of Classes in a customer's QuickBooks Desktop account using the Class Query XML Operation:
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: quickbooks_desktop_account_token' \
--header 'Content-Type: text/xml' \
--data-raw '
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<ClassQueryRq>
</ClassQueryRq>
</QBXMLMsgsRq>
</QBXML>
'
As with all Agave API passthrough requests, the response will be in JSON:
{
"body": [
{
"ListID": "12345-123456789",
"TimeCreated": "2022-01-01T00:00:00-00:00",
"TimeModified": "2022-01-01T00:00:00-00:00",
"EditSequence": "12345678",
"Name": "Revenue - Job Related",
"FullName": "Revenue - Job Related",
"IsActive": "true",
"Sublevel": "0"
}
}
Sage Intacct
Since Sage Intacct does not have native JSON APIs, you will need to use its native XML request format.
Check out Sage Intacct's API Reference to see a list of XML requests that are supported. If you are unable to find the endpoint you need, please contact us at support@agaveapi.com and we should be able to assist.
For example, the below request retrieves a list of Project Statuses in a customer's Sage Intacct account using the Project Status XML Request:
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: quickbooks_desktop_account_token' \
--header 'Content-Type: application/json' \
--data-raw '
<readByQuery>
<object>PROJECTSTATUS</object>
<fields>*</fields>
<query></query>
<pagesize>100</pagesize>
</readByQuery>
'
As with all Agave API passthrough requests, the response will be in JSON:
{
"body": {
"@attributes": {
"listtype": "projectstatus",
"count": "1",
"totalcount": "1",
"numremaining": "0",
"resultId": ""
},
"projectstatus": [
{
"NAME": "Unstarted",
"DESCRIPTION": "Unstarted",
"PREVENTTIMESHEET": "false",
"PREVENTEXPENSE": "false",
"PREVENTAPPO": "false",
"PREVENTGENINVOICE": "false",
"STATUS": "active",
"RECORDNO": "1",
"WHENCREATED": "01/01/2022 00:00:00",
"WHENMODIFIED": "01/01/2022 00:00:00",
"CREATEDBY": "1",
"MODIFIEDBY": "1",
"MEGAENTITYKEY": "1",
"MEGAENTITYID": "GC",
"MEGAENTITYNAME": "AnyContractors Inc."
}
]
}
}
Foundation, Sage 100 Contractor, Sage 300 CRE, Viewpoint Spectrum, and Viewpoint Vista
Since Foundation, Sage 100 Contractor, Viewpoint Spectrum, and Viewpoint Vista do not have native APIs and are backed by SQL databases, you will need to use a different request syntax to return results for a data object.
Agave API only supports read operations for passthrough requests for Foundation, Sage 100 Contractor, Viewpoint Spectrum, and Viewpoint Vista. If you are interested in Agave API supporting write passthrough requests, please contact us at support@agaveapi.com.
The request body should be in JSON format with the following parameters:
Key | Type | Description | Example | Required |
---|---|---|---|---|
table | String | This is the underlying backing table name in the Source System. | "HQCO" | Yes |
operation | String | This is the operation to perform on the table. It can be one of COUNT , DEFINITION , SCHEMA , SELECT , SELECT DISTINCT , SHOW TABLES , LIST PERMISSIONS , or LIST ROLES . | "SELECT" | Yes |
filters | Array of Objects | These are filters that can be applied to return a subset of results from the table. Note, Valid filter operators include: = , != , <> , <=> , < , <= , > , >= , LIKE , NOT LIKE , ILIKE , and NOT ILIKE . | [{"field": "Category","operator": "=","value": "1"}] | No |
limit | Integer | This is the number of results to return in the request. | 10 | No |
offset | Integer | This is the the position of the results returned in the request. | 0 | No |
order_by | Array of Objects | This is one or more column to order the results returned in the request. Note, direction can be "ASC" or "DESC". | "[{"field": "HQCO", "dir": "ASC"}] | No |
fields | Array of Strings | This is an array you can pass to specify which fields to return in the request. | ["HQCO", "NAME] | No |
Get Results for a Table
Using the SELECT
operation in a passthrough request to Viewpoint Vista returns a list of results for a specific object:
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: viewpoint_vista_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"table": "HQCO",
"operation": "SELECT",
"limit": 10,
"offset": 0,
"order_by": [
{
"field": "HQCo",
"dir": "DESC"
}
],
"fields": [
"HQCo",
"Name",
"Address"
]
}'
The response generated is one result with the values for each column specified in the fields
array:
{
"body": [
{
"HQCo": "1",
"Name": "AnyContractors Inc",
"Address": "123 Main Street"
}
],
"content_type": "application/json",
"headers": [],
"status": 200
}
Filter Results in a Table
Using the filters
key in a passthrough request to Viewpoint Vista returns a list of results that meet the criteria of one or more filters:
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: viewpoint_vista_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"table": "APVM",
"operation": "SELECT",
"filters":
[
{
"field": "Vendor",
"operator": "=",
"value": "3"
}
]
}'
The response generated is one result with the values for each column specified in the fields
array:
{
"body": [
{
"VendorGroup": "12345",
"Vendor": "3",
"Name": "AnyCompany Inc.",
...
}
],
"content_type": "application/json",
"headers": [],
"status": 200
}
Get Schema for a Table
Using the SCHEMA
operation in a passthrough request to Viewpoint Vista returns the table schema for a specific object (in the below example, an end-user's Viewpoint Vista Company).
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: viewpoint_vista_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"table": "HQCO",
"operation": "SCHEMA"
}'
The response generated is the schema for each column in the table, returned in a JSON format:
{
"body": [
{
"default_constraints_name": null,
"column_name": "HQCo",
"data_type": "string",
"is_identity": "0",
"data_length": "1",
"numeric_precision": "3",
"numeric_scale": "0",
"is_nullable": "NO",
"column_default": null,
"foreign_key": "HQCo"
},
...
]
}
Get the Definition of a Stored Procedure
Using the DEFINITION
operation in a passthrough request returns the definition of a Stored Procedure or Function.
For example, here is a request returning the definition of the sp_insert_update_jobs
stored procedure in a Foundation database:
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: foundation_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"table": "sp_insert_update_jobs",
"operation": "DEFINITION"
}'
The response generated has a definition
property:
{
"body": {
"name": "sp_insert_update_jobs",
"definition": "\r\nCREATE procedure sp_insert_update_jobs ......"
},
"content_type": "application/json",
"headers": [],
"status": 200
}
Get Totals for a Table
Using the COUNT
operation in a passthrough request to Viewpoint Vista returns the total number of rows in the table.
For example, here is a request returning the total number of Companies in an end-user's Viewpoint Vista instance:
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: viewpoint_vista_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"table": "HQCO",
"operation": "COUNT"
}'
The response generated is the count
of rows:
{
"body": {
"count": 5
},
"content_type": "application/json",
"headers": [],
"status": 200
}
Return all Table Names
You can return a list of all tables in a Foundation, Sage 100 Contractor, or Viewpoint Spectrum database by passing SHOW TABLES
as a value for operation
.
For example, here is a request returning a list of tables for Foundation:
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: foundation_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"operation": "SHOW TABLES"
}'
The response generated is a list of tables
{
"body": [
{
"TABLE_CATALOG": "{Database Name}",
"TABLE_SCHEMA": "dbo",
"TABLE_NAME": "{Table Name}",
"TABLE_TYPE": "VIEW"
},
{
"TABLE_CATALOG": "{Database Name}",
"TABLE_SCHEMA": "dbo",
"TABLE_NAME": "{Table Name}",
"TABLE_TYPE": "BASE TABLE"
},
// ...
]
}
To see a list of tables available in a Viewpoint Vista database, input vDDFH
as the value for table
in a request with SELECT
as the operation.
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: viewpoint_vista_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"operation": "SELECT",
"table": "vDDFH
}'
The response generated is a list of tables
{
"body": [
{
"Form": "AP1099Download",
"Title": "AP 1099 Download",
// ...
},
// ...
]
}
List Current User's Permissions
Using the LIST PERMISSIONS
operation in a passthrough request returns current user's permissions on all tables (or only the requested table).
curl --request POST https://api.agaveapi.com/passthrough \
--header 'API-Version: 2021-11-21' \
--header 'Client-Id: your_client_id' \
--header 'Client-Secret: your_client_secret' \
--header 'Account-Token: foundation_account_token' \
--header 'Content-Type: application/json' \
--data-raw '{
"table": "jobs", // Optional
"operation": "LIST PERMISSIONS"
}'
The response generated has a definition
property:
{
"body": {
"table_name": "jobs",
"table_type": "table",
"permissions": {
"SELECT ALL": true,
"UPDATE ALL": true,
"REFERENCES ALL": true,
"INSERT": true,
"DELETE": true,
"EXECUTE": false,
"SELECT ANY": true,
"UPDATE ANY": true,
"REFERENCES ANY": true
},
// ... more tables
},
"content_type": "application/json",
"headers": [],
"status": 200
}