Skip to main content

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:

  1. JSON Request, for most requests where the Source System has native JSON API endpoints,
  2. File Download Request, for downloading files,
  3. Multipart Upload Request, for uploading files, and
  4. 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:

KeyTypeDescriptionExampleRequired
methodStringThe method for the request to the source system."GET"Required
pathStringThe path for the request to the source system."/rest/v1.0/projects"Required
dataJSONThe 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:

  1. Aconex
  2. Procore
  3. QuickBooks Online

Step 1: Identify Method

Identify the method of the request you are trying to make.

Common values:

MethodDescription
DELETEDeletes the specified resource.
GETRequests a representation of the specified resource. Should only retrieve data.
PATCHApplies partial modifications to a resource.
POSTSubmits an entity to the specified resource.
PUTReplaces 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:

  1. Aconex: https://{{domain}}.aconex.com
  2. Procore: https://api.procore.com
  3. 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:

  1. Aconex get users: https://{{domain}}.aconex.com/api/user
  2. Procore get projects: https://api.procore.com/rest/v1.0/projects
  3. 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:

  1. Aconex get users: /api/user
  2. Procore get projects: /rest/v1.0/projects
  3. 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:

  1. Aconex get users: no data object needed
  2. Procore get projects for a specific company: { "company_id": 31936 }
  3. 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.

HeaderDescriptionExampleRequired
Passthrough-MethodThe method for the request to the source system."POST"Required
Passthrough-PathThe 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:

  1. Procore

Step 1: Identify Method

Identify the method of the request you are trying to make.

Common values for multipart request:

MethodDescription
PATCHApplies partial modifications to a resource.
POSTSubmits an entity to the specified resource.
PUTReplaces 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:

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

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

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

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

info

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.

info

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.

info

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:

KeyTypeDescriptionExampleRequired
tableStringThis is the underlying backing table name in the Source System."HQCO"Yes
operationStringThis 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
filtersArray of ObjectsThese 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
limitIntegerThis is the number of results to return in the request.10No
offsetIntegerThis is the the position of the results returned in the request.0No
order_byArray of ObjectsThis 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
fieldsArray of StringsThis 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
}