//------------------------------------------------------------------------------------ //npm install --save axios moment dotenv const axios = require("axios"); const moment = require("moment"); require('dotenv').config() //------------------------------------------------------------------------------------ /* BEFORE RUNNING THIS EXAMPLE: * Set CONNECTFI_CLIENTID, CONNECTFI_PASSWORD, and CONNECTFI_BASE_URL in a .env file (Speak to a support representative to be issued client credentials and URL after receiving access to the sandbox.) * Set UNIQUE_REFERENCE_ID to a unique identifier. */ const CONNECTFI_CLIENTID = process.env.CONNECTFI_CLIENTID; const CONNECTFI_PASSWORD = process.env.CONNECTFI_PASSWORD; const CONNECTFI_BASE_URL = process.env.CONNECTFI_BASE_URL; const UNIQUE_REFERENCE_ID = "exampleRef1002"; //Update this value so that it is a unique ID before running //------------------------------------------------------------------------------------ //Get Authorization Token /* All other requests must have a valid authorization token in the request headers, so your first request in any workflow should be to /auth/get-token in order to receive an authorization token. A valid token should be included in the headers of all subsequent requests. */ async function getAuthToken() { const data = { "user": { "login": `${CONNECTFI_CLIENTID}`, "password": `${CONNECTFI_PASSWORD}` } }; const config = { method: 'POST', url: `${CONNECTFI_BASE_URL}/auth/get-token`, headers: { 'Content-Type': "application/json" }, data }; let result; try { result = await axios.request(config); if (result.status === 200) { return Promise.resolve(result.data.data); } } catch (err) { console.log({ errCode: err.code, responseStatus: err.response && err.response.status, data: err.response && JSON.stringify(err.response.data) }); } } //------------------------------------------------------------------------------------ //Send Payment /* First, send an ACH transfer through a POST request to /transfer-to/ach/create. ACH transfers are processed in batches and transferred to the ODFI (Originating Depository Financial Institution) via SFTP. As soon as our banking partner sends confirmation that the ACH transfer request has been received, you will receive a webhook showing the transfer status has been updated. */ async function sendACHPayment(authToken) { const data = { "reference": UNIQUE_REFERENCE_ID, //reference must be unique "effectiveEntryDate": `${moment(new Date()).add(1, "day").format("YYYY-MM-DD")}`, //dated for next day "standardEntryClassCode": "CCD", "individualName": "John Smith", "routingNumber": "053207766", "DFIAccountNumber": "123456789", "accountType": "Checking", "transactionType": "Debit", "amount": 1.01, "currency": "USD", "companyEntryDescription": "PAYMENT", "webhookUrl": `https://your_webhook_url/${UNIQUE_REFERENCE_ID}` }; const config = { method: 'POST', url: `${CONNECTFI_BASE_URL}/transfer-to/ach/create`, headers: { 'Content-Type': "application/json", 'x-connectfi-token': authToken //previously obtained authorization token is required }, data }; let result; try { result = await axios.request(config); if (result.status === 200) { return Promise.resolve(result.data.data); } } catch (err) { console.log({ errCode: err.code, responseStatus: err.response && err.response.status, data: err.response && JSON.stringify(err.response.data) }); } } //------------------------------------------------------------------------------------ //Query /* If you have not received a webhook response with an expected status change within the expected time period, you may then query the current status of up to 20 ACH transfers at a time using a /transfer-to/ach/query request. It is recommended that you run a /transfer-to/ach/query request only once or twice per day. The conditions under which a /transfer-to/ach/query should be made are as follows: * A status change was expected to have already occurred (For example, an ACH transfer request was sent. It is now >24 hours later and a status change to "Complete" or "Declined" was expected to have already occurred.) * An expected webhook response has not been received for the transfer. This is a rare occurrence and would indicate that something unforeseen has happened. * Do not send multiple queries for the same transaction within a 12 hour period. If a query confirms that the status of an ACH transfer has not moved when expected, contact customer support with the cFiTransactionId, current status, expected status, and date that the ACH transfer was created. * If you have more than one ACH transfer to query, do not send multiple queries with one transfer at a time. The queries should be sent in batches of 20 cFiTransactionIds/reference IDs per request. If you have less than 20 transfers to query, they can all be queried in a single request. */ async function query(authToken, cFiTransactionId) { const data = { "cFiTransactionIds": [cFiTransactionId] }; const config = { method: 'POST', url: `${CONNECTFI_BASE_URL}/transfer-to/ach/query`, headers: { 'Content-Type': "application/json", 'x-connectfi-token': authToken //previously obtained authorization token is required }, data }; let result; try { result = await axios.request(config); if (result.status === 200) { return Promise.resolve(result.data.data); } } catch (err) { console.log({ errCode: err.code, responseStatus: err.response && err.response.status, data: err.response && JSON.stringify(err.response.data) }); } } //------------------------------------------------------------------------------------ //List /* It is also possible to list up to 1000 ACH transfers at a time using search criteria with a /transfer-to/ach/list request. Search criteria may include a specific cFiTransaction or reference ID, a date range, a status value, or a combination of these search criteria. Use case examples for a /transfer-to/ach/list request include but are not limited to the following. * Listing all ACH transfers that still have an "Initiated" status. * Listing all transactions that have a "Declined" status with a date range of "2023-05-10T12:00:30.000Z" to "2023-05-11T12:00:00.000Z". * Listing all transactions that have a "Completed" status in batches of 150. (You can use the "numberOfRecords" property and the "skipRecords" property to list up to 1000 transfers at a time or to skip a certain number of transfers.) */ async function list(authToken) { const data = { "dateCreateFrom": `${new Date(moment(new Date()).add(-1, "hour")).toISOString()}`, "dateCreateTo": `${new Date(moment(new Date()).add(1, "hour")).toISOString()}`, "status": "Initiated", "numberOfRecords": 5, "skipRecords": 0 }; const config = { method: 'POST', url: `${CONNECTFI_BASE_URL}/transfer-to/ach/list`, headers: { 'Content-Type': "application/json", 'x-connectfi-token': authToken //previously obtained authorization token is required }, data }; let result; try { result = await axios.request(config); if (result.status === 200) { return Promise.resolve(result.data.data); } } catch (err) { console.log({ errCode: err.code, responseStatus: err.response && err.response.status, data: err.response && JSON.stringify(err.response.data) }); } } //------------------------------------------------------------------------------------ //Run the walkthrough async function achWalkthrough() { //Get Authorization Token console.log(`Start /auth/get-token example.\n`); const authObject = await getAuthToken(); let authToken = undefined; if (authObject) { console.log(`Successfully obtained authorization: ${JSON.stringify(authObject)}\n`); authToken = authObject.token; console.log(`Authorization token: ${authToken}\n`); } else { console.log(`Error getting authorization token\n`) } console.log(`End /auth/get-token example.\n`); //Send Payment console.log(`Start /transfer-to/ach/create example.\n`); let ccdACHPayment; if (authToken) { ccdACHPayment = await sendACHPayment(authToken); } else { console.log(`Authorization token is required. Payment not sent.\n`) } if (ccdACHPayment) { console.log(`Successfully created an ACH payment with SEC type CCD: ${JSON.stringify(ccdACHPayment)}\n`); } console.log(`End /transfer-to/ach/create example.\n`); //Query console.log(`Start /transfer-to/ach/query example.\n`); let queryResult; if (authToken && ccdACHPayment && ccdACHPayment.cFiTransactionId) { queryResult = await query(authToken, ccdACHPayment.cFiTransactionId); } else { console.log(`Authorization token and cFiTransactionId are required. Query failed.\n`) } if (queryResult) { console.log(`Successfully queried ACH payment: ${JSON.stringify(queryResult)}\n`); } console.log(`End /transfer-to/ach/query example.\n`); //List console.log(`Start /transfer-to/ach/list example.\n`); let listResult; if (authToken) { listResult = await list(authToken); } else { console.log(`Authorization token is required. List not retrieved.\n`) } if (listResult) { console.log(`Successfully retrieved list of ACH payments matching filter: ${JSON.stringify(listResult)}\n`); } console.log(`End /transfer-to/ach/list example.\n`); } if (process.env.CONNECTFI_CLIENTID && process.env.CONNECTFI_PASSWORD && process.env.CONNECTFI_BASE_URL) { achWalkthrough(); } else { console.log("Before running the walkthrough, set the required .env variables."); }