//------------------------------------------------------------------------------------ //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 an .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 = "exampleRef1007"; //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 a Wire /* Send a wire transfer through a POST request to /transfer-to/wire. Wire transfers are processed same-day and funds typically are transferred within a few hours. As soon as our banking partner sends confirmation that the wire transfer request has been received, you will receive a webhook showing the transfer status has updated to "Complete". */ async function sendWire(authToken) { const data = { "amount": 16.53, "currency": "USD", "endUserAccount": "1234567890123456", "reference": UNIQUE_REFERENCE_ID, "originator": { "commonName": "John Doe", "legalName": "John Doe", "address": { "addressLine1": "999 Main Street", "addressLine2": "Ste. A", "city": "San Francisco", "state": "CA", "postalCode": "12345", "country": "US" } }, "beneficiary": { "bankName": "Unicorn Bank", "bankABANumber": "122244184", "accountNumber": "1234567890123456", "name": "John Smith", "address": { "addressLine1": "1346 Pleasant Ave", "addressLine2": "Apt A123", "city": "Salt Lake City", "state": "UT", "postalCode": "12345", "country": "US" } }, "narrative": "Invoice #123 for May", "memos": [ "For spare parts per contract #123", "Delivered Salt Lake City UT 12345" ], "webhookURL": `https://your_webhook_url/${UNIQUE_REFERENCE_ID}` }; const config = { method: 'POST', url: `${CONNECTFI_BASE_URL}/transfer-to/wire`, 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 query the current status of up to 20 wire transfers at a time using a /transfer-to/wire/query request. It is recommended that you run a /transfer-to/wire/query request only once or twice per day. The conditions under which a /transfer-to/wire/query should be made are as follows: * A status change was expected to have already occurred (For example, a wire was sent. It is now 12 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 a wire transfer has not moved when expected, contact customer support with the cFiTransactionId, current status, expected status, and date that the wire transfer was created. * If you have more than one wire 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. Note: When testing, wire transfers in the sandbox environment will not move status unless triggered. See "Testing Wires in the Sandbox" in the API documentation for a description of how to trigger error messages and status changes for wires when in a testing environment. */ async function query(authToken, cFiTransactionId) { const data = { "cFiTransactionIds": [cFiTransactionId] }; const config = { method: 'POST', url: `${CONNECTFI_BASE_URL}/transfer-to/wire/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 possible to list up to 1000 wire transfers at a time using search criteria with a /transfer-to/wire/list request. Search criteria may include a date range, a status value, or a combination of these search criteria. Use case examples for a /transfer-to/wire/list request include but are not limited to the following. * Listing all wire transfers that still have a "Sent" 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, status, numRecords, numToSkip) { const data = { "dateCreateFrom": `${new Date(moment(new Date()).add(-1, "hour")).toISOString()}`, "dateCreateTo": `${new Date(moment(new Date()).add(1, "hour")).toISOString()}`, "status": status, "numberOfRecords": numRecords, "skipRecords": numToSkip }; const config = { method: 'POST', url: `${CONNECTFI_BASE_URL}/transfer-to/wire/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 wiresWalkthrough() { //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 a Wire console.log(`Start /transfer-to/wire example.\n`); let sendWireResult; if (authToken) { sendWireResult = await sendWire(authToken); } else { console.log(`Authorization token is required.\n`) } if (sendWireResult) { console.log(`Successfully created wire: ${JSON.stringify(sendWireResult)}\n`); } console.log(`End /transfer-to/wire example.\n`); //Query console.log(`Start /transfer-to/wire/query.\n`); let wireQueryResult; if (authToken && sendWireResult && sendWireResult.cFiTransactionId) { wireQueryResult = await query(authToken, sendWireResult.cFiTransactionId); } else { console.log(`Authorization token and cFiTransactionId are required.\n`) } if (wireQueryResult) { console.log(`Successfully queried wires: ${JSON.stringify(wireQueryResult)}\n`); } console.log(`End /transfer-to/wire/query.\n`); //List console.log(`Start transfer-to/wire/list example.\n`); let listWiresResult; if (authToken) { listWiresResult = await list(authToken, "Sent", 5, 0); } else { console.log(`Authorization token is required.\n`) } if (listWiresResult) { console.log(`Successfully retrieved list of wires matching criteria: ${JSON.stringify(listWiresResult)}\n`); } console.log(`End transfer-to/wire/list example.\n`); } if (process.env.CONNECTFI_CLIENTID && process.env.CONNECTFI_PASSWORD && process.env.CONNECTFI_BASE_URL) { wiresWalkthrough(); } else { console.log("Before running the walkthrough, set the required .env variables."); }