Introduction
Welcome to the documentation for the Expensify Integration Server. This is designed to give you all the information you need to integrate with Expensify. You will find information on how to programmatically download expense report data for analysis or insertion into your accounting package, provision accounts for new hires, and much more.
While the API is a self-serve tool, we have compiled some customer FAQs in ExpensifyHelp.
Authentication
To use the API, you will need to generate API credentials.
- Create an Expensify account at https://www.expensify.com/
- Go to https://www.expensify.com/tools/integrations/
- A pair of credentials:
partnerUserID
andpartnerUserSecret
will be generated and shown on the page.
Request format
API call format
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={...}'
Every request to the Expensify API follows the same pattern: a JSON payload that identifies the job to execute is passed as a parameter called requestJobDescription
. Additionally, other parameters may be needed based on the type of job.
Every request has to be made against the endpoint https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations
.
requestJobDescription
format
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"...",
"credentials":{
"partnerUserID":"_REPLACE_",
"partnerUserSecret":"_REPLACE_"
},
"inputSettings":{
...
}
}'
For every request, the requestJobDescription
JSON parameter will need to contain the following data:
Parameter | Type | Description |
---|---|---|
type | String | The type of job to execute |
credentials | JSON object | An object containing two key/values used to authenticate you: partnerUserID and partnerUserSecret . |
inputSettings |
JSON Object | Additional information about the job to execute |
Rate limits
To keep our platform stable and handle high traffic, Expensify limits how many API requests you can send:
- Up to 5 requests every 10 seconds
- Up to 20 requests every 60 seconds
Sending more requests than allowed may result in an error with status code 429
.
Export
Report Exporter
The following examples assume the template is stored in the file 'expensify_template.ftl'
- Export reports by ID, to a CSV file
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"file",
"credentials":{
"partnerUserID":"_REPLACE_",
"partnerUserSecret":"_REPLACE_"
},
"onReceive":{
"immediateResponse":["returnRandomFileName"]
},
"inputSettings":{
"type":"combinedReportData",
"filters":{
"reportIDList": "R00bCluvcO4T,R006AseGxMka"
}
},
"outputSettings":{
"fileExtension":"csv"
}
}' \
--data-urlencode 'template@expensify_template.ftl'
- Export at most 10 Approved and Reimbursed reports generated between 2016-01-01 and 2016-02-01 to an xlsx file named
myExport.xlsx
. The exported reports are then marked as exported with the label "Expensify Export" (markAsExported
action), and an email with a link to the output is sent. Reports that have already been marked with the label "Expensify Export" are ignored (markedAsExported
filter)
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"file",
"credentials":{
"partnerUserID":"_REPLACE_",
"partnerUserSecret":"_REPLACE_"
},
"onReceive":{
"immediateResponse":["returnRandomFileName"]
},
"inputSettings":{
"type":"combinedReportData",
"reportState":"APPROVED,REIMBURSED",
"limit":"10",
"filters":{
"startDate":"2016-01-01",
"endDate":"2016-02-01",
"markedAsExported":"Expensify Export"
}
},
"outputSettings":{
"fileExtension":"xlsx",
"fileBasename":"myExport"
},
"onFinish":[
{"actionName":"markAsExported","label":"Expensify Export"},
{"actionName":"email","recipients":"manager@domain.com,finances@domain.com", "message":"Report is ready."}
]
}' \
--data-urlencode 'template@expensify_template.ftl'
- expensify_template.ftl sample. See the export template format reference for more information about how to write export templates.
<#if addHeader == true>
Merchant,Original Amount,Category,Report number,Expense number<#lt>
</#if>
<#assign reportNumber = 1>
<#assign expenseNumber = 1>
<#list reports as report>
<#list report.transactionList as expense>
${expense.merchant},<#t>
<#-- note: expense.amount prints the original amount only -->
${expense.amount},<#t>
${expense.category},<#t>
${reportNumber},<#t>
${expenseNumber}<#lt>
<#assign expenseNumber = expenseNumber + 1>
</#list>
<#assign reportNumber = reportNumber + 1>
</#list>
Export expense or report data in a configurable format for analysis or insertion into your accounting package, either by specifying a list of report IDs, or a date range up to one year. See the export template format reference for more information about how to write export templates.
requestJobDescription
format
Name | Format | Valid values | Description |
---|---|---|---|
type | String | file | |
onReceive | JSON object | {"immediateResponse":["returnRandomFileName"]} |
Returns the name of the generated report. Only this export mode is supported at the moment. |
inputSettings | JSON object | See inputSettings | Settings used to filter the reports that are exported. |
outputSettings | JSON object | See outputSettings | Settings for the generated file. |
Optional elements | |||
test | String | true, false | If set to true, actions defined in onFinish will not be executed. |
onFinish | JSON array | See onFinish | Actions performed at the end of the export. |
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | combinedReportData | Specifies all Expensify reports will be combined into a single file. |
filters | JSON object | See inputSettings filters | |
Optional elements | |||
reportState | String | One or more of "OPEN" , "SUBMITTED" , "APPROVED" , "REIMBURSED" , "ARCHIVED" .When using multiple statuses, separate them by a comma, e.g. "APPROVED,REIMBURSED" Note: These values respectively match the statuses "Open", "Processing", "Approved", "Reimbursed" and "Closed" on the website |
Only the reports matching the specified status(es) will be exported. |
limit | String | Any integer, as a string | Maximum number of reports to export. |
employeeEmail | String | A valid email address Note: * The usage of this parameter is restricted to certain domains * If this parameter is used, reports in the OPEN status cannot be exported |
The reports will be exported from that account. |
inputSettings.filters
Name | Format | Valid values | Description |
---|---|---|---|
reportIDList | String, Required if startDate or approvedAfter are not specified |
Comma-separated list of report IDs to be exported. | |
policyIDList | String, Optional |
Comma-separated list of policy IDs the exported reports must be under. | |
startDate | Date, Required if reportIDList or approvedAfter are not specified |
yyyy-mm-dd formatted date | Filters out all reports submitted or created before the given date, whichever occurred last (inclusive). |
endDate | Date, Conditionally required, if either startDate or approvedAfter is more than one year ago |
yyyy-mm-dd formatted date | Filters out all reports submitted or created after the given date, whichever occurred last (inclusive). The total date range cannot exceed one year. |
approvedAfter | Date, Required if reportIDList or startDate are not specified |
yyyy-mm-dd formatted date | Filters out all reports approved before, or on that date. This filter is only used against reports that have been approved. |
markedAsExported | String, Optional |
Any string | Filters out reports that have already been exported with that label out. |
outputSettings
Name | Format | Valid values | Description |
---|---|---|---|
fileExtension | String | One or multiple of "csv", "xls", "xlsx", "txt", "pdf", "json", "xml" | Specifies the format of the generated report. Note: if the "pdf" option is chosen, one PDF file will be generated for each report exported. |
Optional elements | |||
fileBasename | String | Any valid file base name | The name of the generated file(s) will start with this value, and a random part will be added to make each filename globally unique. If not specified, the default value export is used. |
includeFullPageReceiptsPdf | Boolean | true , false |
Specifies whether generated PDFs should include full page receipts. This parameter is used only if fileExtension contains pdf . |
onFinish
(Optional)
This section can be used to describe actions that need to be performed at the end of the export.
Action Name | Description |
---|---|
Send an email linking to the generated report to a provided list of recipients. | |
markAsExported | Mark the exported reports as “Exported” in Expensify. |
sftpUpload | upload the generated file(s) to an SFTP server. |
Name | Format | Valid values | Description |
---|---|---|---|
email action |
|||
recipients | String | Comma-separated list of valid email addresses | People to email at the end of the export. |
message | String | Plain text or Freemarker message | Content of the message. If using Freemarker, the filenames list can be used to get the names of all files that have been generated. |
markAsExported action |
|||
label | String | Any string value | The exported reports will be marked as exported with this label. |
sftpUpload action |
|||
sftpData | JSON object | See below | |
sftpUpload.sftpData action |
|||
host | String | The SFTP host to connect to. You can upload to a specific folder by setting the homedir (home directory) of the SFTP user to that folder. You cannot specify a specific folder any other way. |
|
login | String | The username to use for SFTP authentication. | |
password | String | The password to use during authentication. | |
port | Integer | The port to connect to on the SFTP server. |
Template parameter
The template
parameter is used to format the Expensify data as you wish. It is based on the Freemarker language's syntax.
See the export template format reference for more information about how to write export templates.
Reconciliation
- Export unreported transactions on all feeds between 1/1/2016 and 10/10/2016 to a CSV file.
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"reconciliation",
"credentials":{
"partnerUserID":"_REPLACE_",
"partnerUserSecret":"_REPLACE_"
},
"inputSettings":{
"startDate":"2016-01-01",
"endDate":"2016-10-10",
"domain":"example.com",
"feed":"export_all_feeds",
"type":"Unreported",
"async": false
},
"outputSettings":{
"fileExtension":"csv"
}
}' \
--data-urlencode 'template@expensify_template.ftl'
Response
- A success response message is comprised of a
"responseCode":200
, and the filename of the report that got created. You can use the Downloader job to download the report.
{
"filename":"is_reconciliation_5429137734434770049.csv",
"responseMessage":"OK",
"responseCode":200
}
- Error
{
"responseMessage":"Error encountered while trying to write reconcilation report to file.",
"responseCode":500
}
Export card transaction data in a configurable format for a given feed in a specified time range.
requestJobDescription
format
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "reconciliation" | |
inputSettings | JSON object | See inputSettings | Settings used to filter the reports that are exported. |
Optional elements | |||
outputSettings | JSON object | See outputSettings | Settings for the generated file. |
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
startDate | String | yyyy-mm-dd formatted date | The beginning date for which we will include expenses in the generated report. |
endDate | String | yyyy-mm-dd formatted date | The end date for which we will include expenses in the generated report. |
domain | String | A valid domain, e.g. "example.com" | Specifies the domain for which the reconciliation report will be run. Note: Only credentials generated for accounts that are domain admins on the provided domain will work. |
type | String | "Unreported","All" | Specifies whether to run the report for only unreported card expenses, or for all card expenses. |
async | Boolean | true , false |
Specifies whether or not to run this command synchronously or asynchronously. Note: For the moment, only synchronous commands (false ) are supported. |
Optional elements | |||
feed | String | Any name for a card feed, or export_all_feeds |
Only the cards matching the specified feed will be exported. |
outputSettings
(Optional)
Name | Format | Valid values | Description |
---|---|---|---|
fileExtension | String | One of "csv", "txt", "json", "xml" | Specifies the format of the generated report. "csv" is the default. |
onFinish
(Optional)
This section can be used to describe actions that need to be performed once the reconciliation report is generated.
Action Name | Description |
---|---|
Send an email linking to the generated report to a provided list of recipients. |
Name | Format | Valid values | Description |
---|---|---|---|
email action |
recipients | String | Comma-separated list of valid email addresses |
Template parameter
- Template sample. See the reconciliation template reference for more information about how to write export templates.
<#-- Header Line -->
<#if addHeader>
Original Merchant,<#t>
Posted date,<#t>
Sales date,<#t>
Modified Sales date,<#t>
Original Amount,<#t>
Modified Amount,<#lt>
</#if>
<#list cards as card, reports>
<#list reports as report>
<#list report.transactionList as expense>
${expense.originalMerchant},<#t>
${expense.posted},<#t>
${expense.originalCreated},<#t>
${expense.modifiedCreated},<#t>
${(-expense.originalAmount/100)?string("0.00")},<#t>
${expense.amountModified?then((-expense.originalAmount/100)?string("0.00"), "")},<#lt>
</#list>
</#list>
</#list>
- Note: Reconciliation templates follow a slightly different format than Export Templates. The basic iterative skeleton of the template is:
<#list cards as card, reports>
<#-- Properties to print per card -->
<#list reports as report>
<#-- Properties to print per report -->
<#list report.transactionList as expense>
<#-- Properties to print per expense -->
</#list>
</#list>
</#list>
- Template sample for a JSON array output.
[<#lt>
<#list cards as card, reports>
<#list reports as report>
<#list report.transactionList as expense>
{<#lt>
"Original Merchant": "${expense.originalMerchant}",<#lt>
"Posted date": "${expense.posted}",<#lt>
"Sales date": "${expense.originalCreated}",<#lt>
"Modified Salesdate": "${expense.modifiedCreated}",<#lt>
"Original Amount": ${(-expense.originalAmount/100)?string("0.00")},<#lt>
"Modified Amount": ${expense.amountModified?then((-expense.originalAmount/100)?string("0.00"), "")}<#lt>
}<#sep>,</#sep><#lt>
</#list>
</#list>
</#list>
]
- Note: To output a
.json
file, one would change thefileExtension
parameter ofoutputSettings
to "json".
The template
parameter is used to format the Expensify data as you wish. It is based on the Freemarker language's syntax.
See the reconciliation template reference for more information about how to write export templates.
Downloader
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"download",
"credentials":{
"partnerUserID":"_REPLACE_",
"partnerUserSecret":"_REPLACE_"
},
"fileName":"myFile.csv",
"fileSystem":"integrationServer"
}'
This job lets you download reports that were generated with the Report Exporter job.
Name | Format | Description |
---|---|---|
fileName | String | The name of a file generated from the exporter job. |
Optional elements | ||
fileSystem | String | Either reconciliation or integrationServer . Use reconciliation to download reports generated from the Reconciliation job, and use integrationServer to download reports generated by the Report Exporter job. integrationServer is the default. |
Create
Report creator
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type": "create",
"credentials": {
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "report",
"policyID": "0123456789ABCDEF",
"report": {
"title": "Name of the report",
"fields":{
"reason_of_trip": "Business trip",
"employees": "3"
}
},
"employeeEmail": "user@domain.com",
"expenses": [
{
"date": "yyyy-mm-dd",
"currency": "USD",
"merchant": "Name of merchant",
"amount": 1234
},
{
"date": "yyyy-mm-dd",
"currency": "CAD",
"merchant": "Name of merchant",
"amount": 2211
}
]
}
}'
Response
- A success response message is comprised of a
responseCode
200
, the name of the generated report, and its ID on Expensify.
{
"responseCode": 200,
"reportName": "Name of the report",
"reportID": "R006AseGxMka"
}
- Error
{
"responseMessage": "Not authorized to authenticate as user user@domain.com",
"responseCode": 500
}
Lets you create a report, with transactions, in a user’s account. Before you can do this, you must reach out to concierge@expensify.com to enable this functionality for your domain. You must be a domain and policy admin. If you continue to receive the error "Not authorized to authenticate as user", this has not yet been enabled for you.
requestJobDescription
format
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "report" | Specifies to the job that it has to create a report. |
employeeEmail | String | A valid email address | The report will be created in that account. |
report | JSON Object | See report. | |
expenses | JSON Array | See expenses. | |
policyID | String | Any valid Expensify policy ID, owned or shared by the user | The report will be created in that policy. |
inputSettings.report
Name | Format | Valid values | Description |
---|---|---|---|
title | String | The title of the report that will be created. | |
Optional elements | |||
fields | JSON Object | A series of JSON objects whose key is the name of the report field to modify, and the value is the value to set. The key needs to have all non-alphanumerical characters replaced with underscores (_ ). |
Values for custom fields on the specified policyID . |
inputSettings.expenses
Name | Format | Valid values | Description |
---|---|---|---|
merchant | String | The title of the report that will be created. | |
currency | String | Three-letter currency code of the transaction. | The currency in which the transaction was made. |
date | Date | yyyy-mm-dd formatted date | The date the expense was made. |
amount | Integer | The amount of the transaction, in cents. |
Expense creator
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"create",
"credentials":{
"partnerUserID":"_REPLACE_",
"partnerUserSecret":"_REPLACE_"
},
"inputSettings":{
"type":"expenses",
"employeeEmail":"user@domain.com",
"transactionList": [
{
"created": "2016-01-01",
"currency": "USD",
"merchant": "Name of merchant 1",
"amount": 1234
},
{
"created": "2016-01-21",
"currency": "EUR",
"merchant": "Name of merchant 2",
"amount": 2211,
"policyID": "E40D9B8DF456E233",
"tax": {
"rateID":"id_TAX_OPTION_16"
}
},
{
"created": "2016-01-31",
"currency": "CAD",
"merchant": "Name of merchant 3",
"amount": 2211,
"reportID": "R006AseGxMka",
"tax": {
"rateID":"id_TAX_OPTION_16",
"amount":600
}
}
]
}
}'
Response
- A success response message is comprised of a
responseCode
200
, and the list of transactions that were created. Each transaction also has a uniquetransactionID
.
{
"responseCode" : 200,
"transactionList" : [
{
"amount" : 1234,
"merchant" : "Name Of Merchant 1",
"created" : "2016-01-01",
"transactionID" : "6720309558248016",
"currency" : "USD"
},
{
"amount" : 2211,
"merchant" : "Name Of Merchant 2",
"created" : "2016-01-31",
"transactionID" : "6720309558248017",
"currency" : "CAD"
}
]
}
- Error
{
"responseMessage" : "Malformed date '16-01-01'. Expected format is yyyy-MM-dd",
"responseCode" : 410
}
Allows you to create expenses in a user’s account.
requestJobDescription
format
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "expenses" | Specifies to the job that it has to create expenses. |
employeeEmail | String | A valid email address | The expenses will be created in this account. Note: This parameter is restricted and requires advanced permissions. Reach out to our Customer Community for more information. |
transactionList | JSON array | See below | List of expense objects. |
expense
objects
Name | Format | Description |
---|---|---|
merchant | String | The name of the expense's merchant. |
created | String | The date of the expense (format yyyy-mm-dd). |
amount | Integer | The amount of the expense, in cents. |
currency | String | The three-letter currency code of the expense. |
Optional elements | ||
externalID | String | A unique, custom string that you specify - this will help identify the expense after being exported. |
category | String | The name of the category to assign to the expense |
tag | String | The name of the tag to assign to the expense |
billable | boolean | Whether to mark the expense as billable or not |
reimbursable | boolean | Whether to mark the expense as reimbursable or not |
comment | String | An expense comment. |
reportID | String | The ID of the report you want to attach the expense to. |
policyID | String | The ID of the policy the tax belongs to. |
tax | JSONObject | A tax object |
tax
objects
Name | Format | Valid values | Description |
---|---|---|---|
rateID | String | The tax rateID, as defined in the policy. To retrieve the tax information from the policy, refer to the Policy Getter job. | |
Optional elements | |||
amount | Integer | The tax amount paid on the expense. Specify it when only a sub-part of the expense was taxed. |
Policy creator
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type": "create",
"credentials": {
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "policy",
"policyName": "My New Policy"
}
}'
Response
- A success response message is comprised of a
responseCode
200
, and the ID of the policy that got created.
{
"responseCode": 200,
"policyID": "0123456789ABCDEF",
"policyName": "My New Policy"
}
- Error
{
"responseMessage": "Required parameter 'policyName' is missing",
"responseCode": 500
}
Lets you create a policy.
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "policy" | Specifies to the job that it has to create a policy. |
policyName | String | The name of the policy to create. | |
Optional elements | |||
plan | String | "team", "corporate" | Specifies the plan of the policy. If not specified, the new policy will be created under the team plan. |
Expense rules creator
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type": "create",
"credentials": {
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "expenseRules",
"policyID": "0123456789ABCDEF",
"employeeEmail": "employee@domain.com",
"actions": {
"tag": "Tag Name"
}
}
}'
Lets you create expense rules for a given employee on a given policy.
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | expenseRules |
Specifies to the job that it has to create an expense rule. |
employeeEmail | String | The email address of the policy member that should receive the expense rule. | |
policyID | String | A valid Expensify policy ID. | |
actions | JSON Object | Supported keys:tag , defaultBillable |
Read/Get
Policy getter
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"get",
"credentials":{
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings":{
"type":"policy",
"fields": ["tax"],
"policyIDList": ["0123456789ABCDEF","DEADBEEF01234567","BA5EBA11BA5EBA11"],
"userEmail":"employee@youraccessibledomain.com"
}
}'
Response
- A success response message is comprised of a
responseCode
200
, and apolicyInfo
object containing information that was requested for the provided policies.
{
"responseCode": 200,
"policyInfo": {
"4C6722D4BD2BD941": {
"reportFields": [{
"values": [],
"name": "title",
"type": "formula"
}, {
"values": ["Class 1", "Class 2", "Class 2:Sub class 2"],
"name": "Classes",
"type": "dropdown"
}, {
"values": ["Donatello", "Leonardo", "Michelangelo", "Rafael"],
"name": "Customers/Jobs",
"type": "dropdown"
}],
"categories": [{
"name": "Entertainment",
"enabled": true
}, {
"name": "Transportation",
"enabled": true
}, {
"name": "Phone",
"enabled": true
}, {
"name": "Fuel/Mileage",
"enabled": true
}, {
"name": "Lodging",
"enabled": true
}, {
"name": "Meals",
"enabled": true
}, {
"name": "Other",
"enabled": false
}],
"tags": [{
"glCode": "",
"name": "Enterprise",
"enabled": true
}, {
"glCode": "",
"name": "Enterprise:Jean-Luc Picard",
"enabled": true
}, {
"glCode": "",
"name": "Enterprise:Lt. Commander Data",
"enabled": true
}, {
"glCode": "",
"name": "Enterprise:William Riker",
"enabled": true
}],
"tax": {
"default": "4",
"rates": [{
"rate": 0,
"name": "EC Goods Zero-rated",
"rateID": "5"
}, {
"rate": 0,
"name": "EC Services Standard",
"rateID": "4"
}, {
"rate": 20,
"name": "Standard",
"rateID": "2"
}, {
"rate": 5,
"name": "Reduced",
"rateID": "9"
}],
"name": "Tax"
}
},
"3F329EA1C3809E6C": {
"categories": [{
"name": "Phone Costs",
"areCommentsRequired": false,
"enabled": false
}, {
"name": "Legal",
"areCommentsRequired": false,
"enabled": false
}, {
"name": "Agency Expense",
"areCommentsRequired": false,
"enabled": false
}],
"reportFields": [{
"values": [],
"name": "title",
"type": "formula"
}],
"tags": [{
"name": "Tags",
"tags": []
}],
"tax": {},
"employees": [{
"email": "admin@domain.com",
"role": "admin",
"submitsTo": "user@domain.com"
}, {
"email": "user@domain.com",
"role": "user",
"submitsTo": "admin@domain.com",
"employeeID": "Emp1",
"customField2": "custom information",
}]
}
}
}
- Error
{
"responseMessage": "Required parameter 'policyIDList' is missing",
"responseCode": 410
}
Lets you get specific information about listed policies.
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "policy" | Specifies to the job that it has to get information specific to policies. |
policyIDList | JSON Array | The IDs of the policies to get information for. | |
fields | JSON Array | "categories", "reportFields", "tags", "tax", "employees" | Specifies the fields of the policy to gather information for. |
Optional elements | |||
userEmail | String | Specifies the user to gather the policy data for. You must have been granted third-party access by that user/company domain beforehand. |
Policy list getter
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"get",
"credentials":{
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings":{
"type":"policyList",
"adminOnly":true,
"userEmail":"employee@youraccessibledomain.com"
}
}'
Response
- A success response message is comprised of a
responseCode
200
, and apolicyList
array containing information that was requested.
{
"policyList": [{
"outputCurrency": "USD",
"owner": "admin@acmecorp.com",
"role": "user",
"name": "Acme Corp USA Policy",
"id": "DEADBEEF12345678",
"type": "corporate"
}, {
"outputCurrency": "EUR",
"owner": "admin@acmecorp.com",
"role": "auditor",
"name": "Acme Corp France Policy",
"id": "BA5EBA1187654321",
"type": "corporate"
}, {
"outputCurrency": "USD",
"owner": "hr@acmecorp.com",
"role": "admin",
"name": "ACME Corp Candidate Policy",
"id": "F005BA11000099999",
"type": "corporate"
}],
"responseCode": 200
}
- Error
{
"responseMessage":"Argument 'type' is missing or malformed",
"responseCode":410
}
Lets you get a list of policies with some relevant information about them. Optionally, you may retrieve policies for another user on a domain you have been granted access to.
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "policyList" | Specifies to the job that it has to get a policy summary list. |
Optional elements | |||
adminOnly | Boolean | true, false | Whether or not to only get policies for which the user is an admin for. |
userEmail | String | Specifies the user to gather the policy list for. You must have been granted third-party access by that user/company domain beforehand |
Domain cards getter
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"get",
"credentials":{
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "domainCardList",
"domain": "domain.tld"
}
}'
Response
- A success response message is comprised of a
responseCode
200
, and adomainCardList
array containing the information that was requested.
{
"domainCardList": [
{
"bank": "citibank.com",
"cardID": 5312342,
"cardName": "John Doe - 1979",
"cardNumber": "1234XXXXXXXX1979",
"created": "2018-01-01 12:34:56",
"email": "john.doe@domain.com",
"externalEmployeeID": "1234567",
"lastImport": "2018-07-03 23:45:01",
"lastImportResult": 200,
"reimbursable": false,
"scrapeMinDate": ""
},
{
"bank": "gl1025",
"cardID": 6234183,
"cardName": "Corporate card",
"cardNumber": "2345XXXXXXXX6789",
"created": "2018-06-01 00:11:22",
"email": "employee@domain.tld",
"externalEmployeeID": "5678901",
"lastImport": "",
"lastImportResult": 200,
"reimbursable": false,
"scrapeMinDate": "2018-01-01 12:00:00"
}
],
"responseCode": 200
}
- Error
{
"responseMessage":"Domain name is missing or malformed",
"responseCode":410
}
Lets you get the list of credit cards that are assigned at the domain level.
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "domainCardList" | Specifies to the job that it has to get the list of domain credit cards. |
inputSettings.domain | String | The name of the domain to get the cards for. |
Update
Policy updater
- Categories, tags and report fields
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type": "update",
"credentials": {
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "policy",
"policyID": "0123456789ABCDEF"
},
"categories": {
"action": "merge",
"data": [
{
"name": "Category 1",
"enabled": true,
"payrollCode": "Payroll Code 1",
"glCode": "GL Code 1",
"commentHint": "Comment hint 1",
"areCommentsRequired": true,
"maxExpenseAmount": 2500
},
{
"name": "Category 2",
"enabled": false
}
]
},
"tags": {
"data": [
{
"name": "Tag",
"tags": [
{
"name": "Tag 1",
"glCode": "Tag 1 GL Code"
},
{
"name": "Tag 2",
"enabled": false
}
]
}
]
},
"reportFields": {
"action": "merge",
"data": [
{
"name": "Report field 1",
"type": "dropdown",
"values": [
"value 1",
"value 2",
"value 3"
]
}
]
}
}'
- Independent multi-level tags, in JSON
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type": "update",
"credentials": {
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "policy",
"policyID": "0123456789ABCDEF"
},
"tags": {
"data": [
{
"name": "Tag Level 1",
"setRequired": true,
"tags": [
{
"name": "Tag 1",
"glCode": "Tag 1 GL Code"
},
{
"name": "Tag 2",
"glCode": "Tag 2 GL Code"
}
]
},
{
"name": "Tag Level 2",
"setRequired": false,
"tags": [
{
"name": "Tag 3",
"glCode": "Tag 3 GL Code"
},
{
"name": "Tag 4",
"glCode": "Tag 4 GL Code"
}
]
}
]
}
}'
- Report Fields with the values as objects rather than strings:
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type": "update",
"credentials": {
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "policy",
"policyIDList": ["F07C5A1A53D4198B", "81A4013E273DF7A1"]
},
"reportFields": {
"action": "merge",
"data": [
{
"name": "Report field 1",
"type": "dropdown",
"values": [
{
"name": "value 1",
"externalID": "1"
},
{
"name": "value 2",
"enabled": false
},
{
"name": "value 3",
"externalID": "3",
"enabled": true
}
]
}
]
}
}'
- Dependent multi-level tags, with GL Codes and tag level names. These must be passed via CSV.
Tag file - In this example, we have the following data in a file called
tags.csv
.
State,State GL,Region,Region GL,City,City GL
California,100,North,20,San Francisco,1
California,100,North,20,Oakland,2
California,100,South,30,Los Angeles,3
California,100,South,30,San Diego,4
Texas,200,East,40,Dallas,5
Texas,200,East,40,Houston,6
Texas,200,South,50,San Antonio,7
Request
curl -X POST "https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations" \
-d 'requestJobDescription={
"type": "update",
"credentials": {
"partnerUserID":"...",
"partnerUserSecret":"..."
},
"inputSettings": {
"type": "policy",
"policyID": "0123456789ABCDEF"
},
"tags": {
"action": "replace",
"source":"file",
"config": {
"dependency":true,
"glCodes":true,
"header":true,
"setRequired":true,
"fileType":"csv"
}
}
}' \
--data-urlencode 'file@tags.csv'
Response
- Success
{
"responseCode": 200
}
- Error
{
"responseMessage": "'categories' object malformed",
"responseCode": 410
}
Error code Description 404 Policy not found 410 Validation error 500 Generic error
Lets you independently manage categories, tags and report fields on a policy.
requestJobDescription
Name | Format | Valid values | Description |
---|---|---|---|
Optional elements | |||
categories | JSON object | See categories below |
Replace or update the existing categories of the policy with the ones provided. |
tags | JSON object | See the dedicated Update tags section below | Replace the existing tags of the policy with the ones provided. |
reportFields | JSON object | See reportFields below |
Replace or update the existing report fields of the policy with the ones provided. |
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "policy" | Specifies to the job that it has to update a policy. |
policyID | String | Any valid Expensify policy ID, owned or shared with the user with admin permissions. | The ID of the policy to update. |
Optional elements | |||
policyIDList | JSON Array | Instead of providing a policyID , you can provide an array of policyIDs to update all polices at once with the same information. |
categories
Name | Format | Valid values | Description |
---|---|---|---|
action | String | "merge", "replace" | Specifies how the categories will be updated. - "replace" removes all existing categories and replaces them with the specified list - "merge" keeps existing categories and updates/adds the ones specified. |
data | JSON array | See below |
categories.data
objects
Name | Format | Description |
---|---|---|
name | String | The name of the category. |
enabled | Boolean | Whether the category is enabled on Expensify. |
Optional elements | ||
glCode | String | The GL Code associated to the category. |
payrollCode | String | The Payroll Code associated to the category. |
areCommentsRequired | Boolean | Whether comments are required for expenses under that category. |
commentHint | String | The hint value for the comment for expenses under that category. |
maxExpenseAmount | Integer | The maximum amount (in cents) for expenses under that category. |
reportFields
Name | Format | Valid values | Description |
---|---|---|---|
action | String | "merge", "replace" | Specifies how the report fields will be updated. - "replace" removes all existing report fields and replaces them with the specified list - "merge" keeps existing report fields and updates/adds the ones specified. |
data | JSON array | See below |
reportFields.data
objects
Name | Format | Valid values | Description |
---|---|---|---|
name | String | The name of the report field. | |
type | String | "text", "dropdown", "date" | The type of the report field. |
values | JSON array | Strings, JSONObjects - See below | Only if type is "dropdown" The values of the dropdown. Type must be uniform across the entire array. For more information on supplying JSONObjects see reportFields.data.values objects section below. |
Optional elements | |||
defaultValue | String | The default value of the report field. Only used for types "text" and "dropdown" |
reportFields.data.values
objects
Name | Format | Valid values | Description |
---|---|---|---|
value | String | The name of the report field value. | |
Optional elements | |||
enabled | Boolean | true , false |
Whether the report field value is enabled or not. Default value is true . |
externalID | String | The externalID associated with the report field value. |
Update tags
Tags can be specified in two ways:
- Directly in the JSON job description
- As extra parameters of the request (via a
csv
file)
Tag levels dependency
For multi-level tagging, Expensify has the notion of tag level dependency. This means each tag level is dependent on the parent tag level above it. For more information and examples about multi-tagging, please refer to our help site.
Passing tag data in JSON (independent levels only)
tags
Name | Format | Valid values | Description |
---|---|---|---|
data | JSON array | See below | |
source | String | "inline" | Specifies that the tags are directly passed in the JSON payload. |
tags.data
objects
Multiple objects can be specified. Each one corresponds to a level in multi-level tagging.
Name | Format | Valid values | Description |
---|---|---|---|
name | String | The name of the tag level. Only use with multi-level tagging. | |
setRequired | Boolean | true , false |
Whether users must specify a tag for that level, when coding expenses. This is set to false by default. |
tags | JSON array | See below | The tags for that level. |
tags.data.tags
objects
Name | Format | Description |
---|---|---|
name | String | The name of the tag. |
Optional elements | ||
enabled | Boolean | Whether the tag is enabled or not. Default value is true . |
glCode | String | The GL Code associated to the tag. |
Passing tag data from plain text as additional request parameters (dependent or independent tag levels)
The tag data must be passed in a parameter called file
in the request.
The tags
object must contain the following information:
Name | Format | Valid values |
---|---|---|
source | String | "file" |
config | JSON Object | See below |
tags.config
Name | Format | Valid values | Description |
---|---|---|---|
dependency | Boolean | true, false | Whether the tag levels are dependent. |
setRequired | Boolean or JSON Array | e.g. true or [true, false] |
If dependency is true , then a single boolean is expected, as dependent tag lists cannot be marked as required individually. If dependency is false , an array of booleans should be used. |
glCodes | Boolean | true, false | Whether adjacent columns in the tag file(s) contain GL Codes. |
header | Boolean | true, false | Whether the first line of the file contains the names of the tag levels. |
setRequired | Boolean | true, false | If set to true , users will be required to tag each expense under that category. |
fileType | String | "cvs" or "tsv" | Format of the tag data. |
Advanced Employee Updater
Lets you add, update or remove policy members. See the dedicated documentation.
Employee updater (deprecated)
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-H 'Expect:' \
-F 'requestJobDescription={
"type": "update",
"credentials": {
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "employees",
"policyID":"0123456789ABCDEF",
"fileType": "csv"
}
}' \
-F 'data=@employeeData.csv'
Employee data samples - employeeData.csv
- Basic information
EmployeeEmail,ManagerEmail,Admin
user1@domain.com,manager1@domain.com,false
user2@domain.com,manager1@domain.com,true
manager2@domain.com,manager1@domain.com,true
- All supported fields
EmployeeEmail,ManagerEmail,Admin,ForwardManagerEmail,EmployeeUserId,EmployeePayrollId
user1@domain.com,manager1@domain.com,false,cfo@domain.com,User1ID,User1PayrollID
user2@domain.com,manager1@domain.com,true,cfo@domain.com,,User2PayrollID
manager2@domain.com,manager1@domain.com,true,,Manager1ID,
Response
- A success response message is comprised of a
responseCode
200, and the total number of employees after the update.
{
"responseCode": 200,
"nbEmployees": 42
}
- Error
{
"responseMessage": "Column EmployeeEmail not found in CSV header",
"responseCode": 500
}
Lets you manage employees on an Expensify policy. Use this to configure or provision accounts for new hires, as well as update existing employee data.
The employee data must be passed in the request parameter data
.
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "employees" | Specifies to the job that it has to create or update employees. |
fileType | String | "csv" | The format of the file that contains the employee data. Only CSV is supported at this point. |
policyID | String | Any valid Expensify policy ID, owned or shared with the user. | The policy to add the employees to. |
data
request argument
CSV file containing the employee data to update. The first line of the file lists the columns that will exist. The order of the columns does not matter.
Name | Format | Valid values | Description |
---|---|---|---|
Required CSV columns | |||
EmployeeEmail | String | Any valid email address | The email address of the employee to update or create. |
ManagerEmail | String | Any valid email address | The email address the employee's manager (corresponds to the column Submits To on Expensify). |
Admin | Boolean | true, false | Determines whether that user has administrator privileges. |
Optional CSV columns | |||
EmployeeUserId | String | The User ID of the employee. | |
EmployeePayrollId | String | The Payroll ID of the employee. | |
ForwardManagerEmail | String | Any valid email address or an empty value | To whom reports will be sent to after the manager clicks 'Approve and Forward'. |
If optional attributes are not provided or left blank, the corresponding value will be removed for existing employees, and left blank for new employees.
Expense rules updater
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type": "update",
"credentials": {
"partnerUserID": "_REPLACE_",
"partnerUserSecret": "_REPLACE_"
},
"inputSettings": {
"type": "expenseRules",
"policyID": "0123456789ABCDEF",
"employeeEmail": "employee@domain.com",
"ruleID": 0,
"actions": {
"tag": "Tag Name"
}
}
}'
Lets you update a preexisting expense rule for a given employee on a given policy.
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | expenseRules |
Specifies to the job that it has to create an expense rule. |
employeeEmail | String | The email address of the policy member that should receive the expense rule. | |
policyID | String | A valid Expensify policy ID. | |
ruleID | Integer | The ID of the rule you want to update. | |
actions | JSON Object | Supported keys:tag , defaultBillable |
Report status updater
curl -X POST 'https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations' \
-d 'requestJobDescription={
"type":"update",
"credentials":{
"partnerUserID":"_REPLACE_",
"partnerUserSecret":"_REPLACE_",
},
"inputSettings":{
"type":"reportStatus",
"status" : "REIMBURSED",
"filters":{
"reportIDList": "R006AseGxMka,R00bCluvcO4T"
}
}
}'
Response
Error code Description 200 Success 207 Partial success: some of the reports failed to update. Their IDs are contained in the list failedReports
.410 Validation error 500 Generic error
- Success
{
"responseCode" : 200,
"reportIDs" : [
"R006AseGxMka",
"R00bCluvcO4T"
]
}
- Partial success
skippedReports
corresponds to a list of reports that could not be updated because they are in an invalid status.failedReports
corresponds to a list of reports that failed to be updated for another reason.
{
"responseCode" : 207,
"reportIDs" : [
"R00bCluvcO4T"
],
"skippedReports" : [
{
"reason" : "Report is in status 'Open'",
"reportID" : "R006AseGxMka"
}
],
"failedReports": [
{
"reason" : "Internal error",
"reportID" : "R002bGmt16ac"
}
]
}
- Validation error
{
"responseMessage" : "Status 'APPROVED' is not supported",
"responseCode" : 410
}
Lets you update the status of a report.
Note: at the moment, the only supported action is to mark Approved reports as Reimbursed.
inputSettings
Name | Format | Valid values | Description |
---|---|---|---|
type | String | "reportStatus" | Specifies to the job that it has to update the status of a list of reports. |
status | String | "REIMBURSED" | The status to change the reports to. At the moment, only Reimbursed is supported. Only reports in the Approved status can be updated to Reimbursed . All other reports will be ignored. |
filters | JSON object | See inputSettings filters |
inputSettings.filters
Name | Format | Valid values | Description |
---|---|---|---|
reportIDList | String, Optional |
Comma-separated list of report IDs to update. | |
startDate | Date, Required if reportIDList is not specified |
yyyy-mm-dd formatted date | Filters out all reports submitted or created before the given date, whichever occurred last (inclusive). |
endDate | Date, Optional |
yyyy-mm-dd formatted date | Filters out all reports submitted or created after the given date, whichever occurred last (inclusive). |
title: Templates for Reconciliation
language_tabs: - freemarker
search: true
Templates for Reconciliation
Introduction
Templates for reconciliation do not follow the same format as templates for the report exporter. The syntax rules are the same, as they both are based on Freemarker. However the data that you can access and how you access it are very different.
For more information beyond this documentation, please reach out to our Customer Community. Enjoy!
Basic format
Basic reconciliation template skeleton
<#-- Header Line -->
<#if addHeader>
<#-- Print header information here -->
</#if>
<#list cards as card, reports>
<#-- Print information on a per card basis here -->
<#list reports as report>
<#-- Print information on a per report basis here -->
<#list report.transactionList as expense>
<#-- Print information on a per expense basis here -->
</#list>
</#list>
</#list>
<#if addHeader>
<#-- Print footer information here -->
</#if>
Reconciliation templates hold a map of cards to reports (cards
) as their basic reference data structure. Reports contain transactions, held in the report's transactionList
. Any transaction that is not reported, but still from a card, will be placed on a report with an id of 0
in that card's set of reports.
In the archetypical example to the right, we iterate over each entry of the cards
map. For each card
, we iterate over the reports
mapped to that card. For each report
we iterate over each expense
that belongs to the report. Again, any expenses on a card that are unreported will show up under the report with id=0
. At any point during each iteration we can print information on a per-card, per-report, or per-expense basis.
Object Reference
Default reconciliation template - When you run a reconciliation report in Expensify via Loading Dock in Domain Control, this is the template that we use to generate your reconciliation report:
<#-- Functions -->
<#function quoteCsv string>
<#if isCsv && string?contains(",") && !string?starts_with("\"")>
<#return "\"" + string?replace("\"", "\\\"") + "\"">
</#if>
<#return string>
</#function>
<#function unescapeHtml string>
<#return string?replace("<", "<")?replace(">", ">")?replace("&", "&")?replace(""", "\"")?replace("'", "'")>
</#function>
<#-- Header Line -->
<#if addHeader>
Original Merchant,<#t>
Modified Merchant,<#t>
Posted date,<#t>
Sales date,<#t>
Modified Sales date,<#t>
Original Amount,<#t>
Modified Amount,<#t>
Currency,Split,<#t>
Category,<#t>
Tag,<#t>
Email,<#t>
Card name,<#t>
Expense status,<#t>
Report name,<#t>
Report status,<#t>
Submitted to,<#t>
Report URL,<#t>
Comment,<#t>
External ID,<#t>
Report ID<#lt>
</#if>
<#list cards as card, reports>
<#list reports as report>
<#list report.transactionList as transaction>
<#-- Assign an expense status based off of the report ID -->
<#if transaction.reportID lt 0>
<#assign status = "deleted">
<#elseif transaction.reportID gt 0>
<#assign status = "reported">
<#else>
<#assign status = "unreported">
</#if>
<#-- Do not print the modified created if it is the same as the original -->
<#if transaction.originalCreated == transaction.modifiedCreated>
<#assign modifiedCreated = "">
<#else>
<#assign modifiedCreated = transaction.modifiedCreated>
</#if>
<#-- Only print the reportID if it greater than 0 -->
<#if report.ID gt 0>
<#assign reportID = report.ID?c>
<#else>
<#assign reportID = "">
</#if>
${quoteCsv(unescapeHtml(transaction.originalMerchant))},<#t>
${quoteCsv(unescapeHtml(transaction.modifiedMerchant))},<#t>
${transaction.posted},<#t>
${transaction.originalCreated},<#t>
${modifiedCreated},<#t>
${(-transaction.originalAmount/100)?string("0.##")},<#t>
${transaction.amountModified?then((-transaction.modifiedAmount/100)?string("0.##"), "")},<#t>
${transaction.currency},<#t>
${transaction.split?then("YES","NO")},<#t>
${quoteCsv(unescapeHtml(transaction.category))},<#t>
${quoteCsv(unescapeHtml(transaction.tag))},<#t>
${card.owner},<#t>
${quoteCsv(unescapeHtml(card.name))},<#t>
${status},<#t>
${quoteCsv(unescapeHtml(report.name))},<#t>
${report.status!""},<#t>
${report.managerEmail},<#t>
${report.url},<#t>
${quoteCsv(unescapeHtml(transaction.comment))},<#t>
${quoteCsv(unescapeHtml(transaction.externalID))},<#t>
${reportID}<#lt>
</#list>
</#list>
</#list>
Card level (card)
Name | Description |
---|---|
bank | The bank or the bank feed of the card (Example: "vcf") |
ID | The ID of the card |
name | The name of the card, as seen in Expensify |
owner | The email address of the Expensify account that owns the card, or that the card is assigned to. |
Report level (report)
Name | Description |
---|---|
base62ID | The Base-62 ID of the report. This is the ID you see on the Expensify website. |
currency | The currency of the report. |
getApproved() | The approved date of the report, as a string (format yyyy-MM-dd hh:mm:ss ), or null if the report wasn't submitted. |
getSubmitted() | The submitted date of the report, as a string (format yyyy-MM-dd hh:mm:ss ), or null if the report wasn't submitted. |
hasAttachment() | Whether the report contains any attachment. |
hasBeenApproved() | Whether or not the report has been approved. |
hasEverBeenExportedTo(template_name) | Whether or not the report has been exported to the template or integration name provided. |
ID | The Base-10 representation of report's ID |
isACHReimbursed() | Whether the report has been reimbursed via ACH |
isClosed() | Whether or not the report is approved. |
isOpen() | Whether or not the report is in the OPEN state |
isReimbursed() | Whether or not the report is reimbursed. |
isReimbursementComplete() | Whether the report reimbursement is complete |
isSubmitted() | Whether or not the report is in the SUBMITTED state |
managerEmail | The report manager's email |
name | The name of the report (The report title in Expensify) |
policyID | The policy ID of the report |
submitterEmail | The email address of the person that created the report. |
submitterID | The account ID of the creator of the report |
state | The state of the report (Example: AUTOREIMBURSED , BILLING , MANUALREIMBURSED , OPEN , SUBMITTED ) |
status | The status of the report (Example: "Open", "Processing", "Approved", "Reimbursed", or "Archived") |
total | The report's total, in cents |
transactionList | The list of expenses on the report. See the Expense level reference below for more information on printing information about Expenses. |
url | The url of the report |
Transaction level (expense)
Name | Description |
---|---|
amount | The amount of the expense, in cents |
bank | The bank of the expense |
base62ReportID | The Base-62 ID of the expense's report ID. |
billable | Whether or not the expense is billable |
cardID | The ID of the card for the expense |
category | The category of the expense. |
comment | The comment on the expense. |
convertedAmount | The converted amount of the expense, in cents |
created | The expense's created date, in format yyyy-MM-dd |
currency | The currency of the expense |
currencyConversionRate | The conversion rate of the expense. |
externalID | The External ID of the expense. |
ID | The ID of the expense |
isAmountModified() | Whether or not the expense has a numerical modified amount present. |
isTagged() | Whether or not the expense has a tag |
originalAmount | The original (non-modified) amount of the expense, in its original currency. |
originalCreated | The expense's original created date, in format yyyy-MM-dd |
originalCurrency | The expense's original currency |
originalCurrencyAmount | The amount of the expense, in cents, in its original currency |
originalMerchant | The original merchant name of the Expense |
maskedPAN | The masked account number of the card for the transaction. |
merchant | The merchant of the expense |
modifiedAmount | The modified amount of the expense, will be 0 if the amount of the expense has not been modified, or if it has been modified to 0. |
modifiedCreated | The expense's modified created date, in format yyyy-MM-dd |
modifiedMerchant | The modified merchant of the Expense |
posted | The Expense's posted date, in format yyyy-MM-dd |
receiptID | The Receipt ID of the expense |
receiptURL | The URL for the receipt attached to the expense. |
reimbursable | Whether or not the expense is reimbursable |
reportID | The Base-10 representation of the expense's report ID. |
split | Whether or not the transaction originated from a split expense action. |
tag | The tag of the expense |
taxAmount | The tax amount on the expense. |
taxExternalID | The externalID of the tax on the expense. |
taxRate | The tax rate on the expense. |
Imports
You can import extra information using import statements like so:
<!-- use _REPLACE_ -->
The bundles currently accessible right now are:
<!-- use cardOwnerData -->
<!-- use reportPolicyData -->
<!-- use categoryGLCodeMap -->
<!-- use repordFieldData[reportFieldName1, reportFieldName2] -->
In addition to all the data in the cards
map, you can use import statements in your template to bring in extra data.
Accessible data packages are:
cardOwnerData
: Employee information about the set of card owners.reportPolicyData
: Policy data for all the reports in the reconciliation report.categoryGLCodeMap
: Map of category names to their GL codes.reportFieldsMap
: Map of reportIDs to their report fields under a given report field name.
Card Owner Data
You can access your Employee Data under the
cardOwnerData
object:
<!-- use cardOwnerData -->
...
<#assign individualEmployeeObject = cardOwnerData[card.owner]!{}>
<#assign individualEmployeeData = individualEmployeeObject.mapData!{}>
EmployeeID: ${individualEmployeeObject.employeeID}
First name: ${individualEmployeeData.firstName}
Last name: ${individualEmployeeData.lastName}
Some Custom Field: ${individualEmployeeData["customFieldName1"]}
This is for companies that have enterprise employee import set up. With this enabled you can bring in your custom employee information to be used in your reconciliation report.
All custom employee information is stored in a map: cardOwnerData
. The key-value pairs in the map are the custom field names mapped to their values.
Report Policy Data
You can access your relevant Policy Data under the
reportPolicyData
object:
<!-- use reportPolicyData -->
...
<#assign policy = reportPolicyData[report.policyID]!{}>
${policy.name!""}
${policy.approver!""}
You can load information about the relevant policies of reports included in your reconciliation report. The policy information will be stored in a map: reportPolicyData
. The map will be keyed by the policyID - which can be accessed by referencing report.policyID
. The value will contain an object with relevant policy information:
Name | Description |
---|---|
approver | The final approver of the policy, if set. |
name | The name of the policy. |
owner | The owner of the policy. |
outputCurrency | The default currency of the policy. |
technicalContact | The technical contact of the policy. |
Category GL Codes
You can access GL Codes for Categories under the
categoryGLCodeMap
object:
<!-- use categoryGLCodeMap -->
...
<#assign categoryGlCode = categoryGLCodeMap[expense.category]!"">
${expense.category} : ${categoryGlCode}
You can access the GL codes of expense categories. They will be stored in a map: categoryGLCodeMap
. The map will be keyed by the category name, which is accessed normally through expense.category
. The value will be the GL code for that category name.
Report Field Data
You need to include the name of each Report Field you want to bring in via the import like so:
<!-- use repordFieldData[reportFieldName1, reportFieldName2] -->
Then, you can access the report field per report via:
<#assign reportID = report.ID?c>
reportFieldData.reportFieldName1[reportID]
You can access the report fields for reports. The import statement works a bit differently from the regular report information. You need to specify each report field that you want to bring in directly in the import. The reportFieldData
will contain a map, with each report field name as a key pointing to a map of reportIDs to report field values on those reports.