API Access
The Digital Onboarding API relies on OAuth2
for authentication. It is highly recommended that you read the spec and
familiarize yourself with it. The API should always be used via HTTPS. Any
attempts to use it via HTTP means that you may have compromised your
client_secret
or access_token
.
With the exception of the token creation end point, all API endpoints require an access_token in order to be used. The access_token is passed via the
Authorization
header. For example, if your token wasabcdef
, you would need to include the headerAuthorization: Bearer abcdef
.
Tokens expire on a regular basis so you will need to account for that in the
way you use the API. If your token has expired you will receive an
HTTP/1.1 401 Unauthorized
with a body of {"error": "invalid_token"}
.
You should store tokens for reuse until they expire. Rather than retrieving
tokens at set intervals, you should build token retrieval into how
you access the API. This will prevent future changes to token expiration from
requiring you to make any updates to your code.
An example of a proper API usage work flow:
Most OAuth2 libraries will help abstract this process for you by automating retries and providing you with an updated token if one was acquired during the transaction. Alternatively you can store the token expiration along with the token and check whether it has expired before using it. Either way, it is best to only request new tokens when needed as opposed to requesting them via a scheduled task.
The API root for all requests is
Grant Access Token
POST
/oauth2/token
The client_id
and client_secret
may be passed via
Basic Auth or along with the
grant_type
in the POST
body. Attempts to pass them via the query string
will result in them immediately being revoked.
Body
field | description |
---|---|
grant_type | A valid OAuth2 grant type. For API use this should always be client_credentials |
client_id | Obtained from the Digital Onboarding admin interface |
client_secret | Obtained from the Digital Onboarding admin interface |
Response
field | type | description |
---|---|---|
access_token | String | The temporary token to use while accessing the rest of the API |
expires_in | Number | The number of seconds until this token expires |
token_type | String | The type of OAuth2 token generated |
Contacts
A contact
will always take this shape and support these fields when being
sent to or returned from the API. All fields are optional, however, use of unique_id
is strongly recommended.
field | type | description |
---|---|---|
unique_id | String | A unique ID is for cross-referencing contacts in your system. See unique ids for more details. |
name_title | String | The contact's title |
name_first | String | The contact's first name |
name_last | String | The contact's last name |
name_suffix | String | The contact's suffix |
address | String | The contact's address |
address2 | String | The second line of the contact's address |
city | String | The contact's city |
state | String | The contact's state |
county | String | The contact's county |
country | String | The contact's country |
post_code | String | The contact's postal code (or zip code) |
timezone | String | The contact's timezone |
email | String | The contact's email address |
phone_home | String | The contact's home phone number |
phone_mobile | String | The contact's mobile phone number |
phone_work | String | The contact's work phone number |
email_verified | Boolean | Whether the contact has proven they have access to the email address |
email_opted_in | Boolean | Whether the contact is opted in to emails |
email_authorized | Boolean | Whether the contact is allowed to use the email address on file to authenticate and see sensitive data |
sms_verified | Boolean | Whether the contact has proven they have access to the mobile phone number |
sms_opted_in | Boolean | Whether the contact is opted in to sms messages |
sms_authorized | Boolean | Whether the contact is allowed to use the mobile phone number on file to authenticate and see sensitive data |
unsubscribe_email | Boolean | Whether the contact is unsubscribed from emails Deprecated This field will be removed in the future. Please use email_opted_in which is the inverse of this field. |
unsubscribe_sms | Boolean | Whether the contact is unsubscribed from sms messages Deprecated This field will be removed in the future. Please use sms_opted_in which is the inverse of this field. |
meta_public | Object | Any contact-related data that you want to use in personalizations. Data stored in this object is readable by anyone inspecting page content in a journey which means this field is not appropriate for storing sensitive data. See meta_public behaviors for more details. |
meta_private | Object | Private contact-related data for use in personalizations and integrations. In order to utilize this information for personalizations, the contact must validate their identity when viewing the journey/page. If the contact does not validate their identity, this information is not exposed by the system. See meta_private behaviors for more details. |
Additionally contact objects will contain these fields when being returned from the API. These fields are controlled by our system and should be considered readonly.
field | type | description |
---|---|---|
id | String | A UUID that uniquely identifies the contact in our system. This value can be ignored if you are using the unique_id to identify contacts. |
inserted_at | String | An ISO 8601 formatted UTC date showing when the contact was added to our system. |
updated_at | String | An ISO 8601 formatted UTC date showing when the contact was last updated in our system. |
Tying the above together, here is a sample POST payload to create a new contact
{
"email_authorized": true,
"email_opted_in": true,
"email_verified": true,
"sms_authorized": true,
"sms_opted_in": true,
"sms_verified": true,
"unique_id": "johndoe1",
"name_first": "John",
"name_last": "Doe",
"timezone": "America/New_York",
"birthdate": "1999-01-01",
"email": "john+doe@gmail.com",
"phone_home": "2125551212",
"phone_mobile": "2125551212",
"phone_work": "2125551212",
"meta_public": {
"account_level": "platinum"
},
"meta_private": {
"group": "secret"
}
}
If successful, a HTTP 201 result will be returned with the following payload:
{
"address": null,
"address2": null,
"birthdate": "1999-01-01",
"city": null,
"country": null,
"county": null,
"email": "john+doe@gmail.com",
"email_authorized": true,
"email_opted_in": true,
"email_verified": true,
"id": "4dd184e6-ab96-4a73-b406-fa1392f6ae3c",
"inserted_at": "2021-06-01T03:30:26.056688Z",
"meta_public": {
"account_level": "platinum"
},
"name_first": "John",
"name_last": "Doe",
"name_suffix": null,
"name_title": null,
"phone_home": "12125551212",
"phone_mobile": "12125551212",
"phone_work": "12125551212",
"post_code": null,
"sms_authorized": true,
"sms_opted_in": true,
"sms_verified": true,
"state": null,
"timezone": "America/New_York",
"unique_id": "johndoe1",
"unsubscribe_email": false,
"unsubscribe_sms": false,
"updated_at": "2021-06-01T03:30:26.056688Z"
}
Note that meta_private is not returned upon creation.
Unique IDs
If a record with a new unique_id
or a record without a unique_id
is posted,
a new contact will be created. The value of unique_id
defaults to email
,
so if a record is posted without a unique_id
, but with an email
, it will be
treated as if the record's unique_id
was set to the same value as email
.
If no unique_id
or email
is supplied, we will generate a new UUIDv4 for the
field.
If a record is supplied with a unique_id
that already exists in the system
then the contact's data will be updated.
It is important to note that when the system uses a contact’s
unique_id
, attempting to update the contact’s email address later via SFTP, will not change theunique_id
of that contact to the newYou may only modify unique IDs within the browser, not via csv or SFTP uploads. Attempting to update a contact's
unique_id
via batch or SFTP upload, with a non-existent ID will also result in the creation of a new contact. It is therefore strongly advised that you define theunique_id
you would like when creating a new contact, in order to avoid manually updating each contact thereafter.
meta_public
and meta_private
fields
Our meta_public
and meta_private
fields accept deeply nested objects. However, they are flattened upon arrival and will always be read as flattened structures. It means you can think of them as simple key-value stores with a few extra benefits. Consider the following example.
{
"car": {
"make": "Honda",
"model": "Civic"
}
}
{
"car.make": "Honda",
"car.model": "Civic"
}
Because the data was flattened as it entered the system it means all of the data is still usable in automatic targeting functionality by using dot notation.
It also means that you can use dot notation in personalizations to access deeply nested data.
Arrays in deeply nested data will also be flattened using their indices as keys. In the above example if
car
had been an array of objects the new addresses forHonda
andCivic
would have beencar.0.make
andcar.0.model
respectively.
If you only use these fields as key-value stores this doesn't affect your usage. However, if you choose to use deeply nested data in these fields it means you should keep the following in mind during your development.
- Deeply nested data passed into these fields will not be in the same format on subsequent
GET
requests. - To reference data in arrays when using features like personalizations and targeting, you will need to provide an index
Communication Opt-ins
Digital Onboarding uses 2 fields to track the full state of a contact's opt-in status. In order to receive marketing emails and sms from the platform an email address or mobile phone number must be both verified and opted in.
An address is considered verified if the contact has clicked a link sent to that address to verify they have access to it. Having this process ensures you are compliant with messaging guidelines, communicating with real people, and protects your sender reputation.
Objective Completion
For more information on objective completion, see completing objectives.
Retrieve
GET
/v1/contacts
Use this endpoint to retrieve existing contacts. You may pass the following parameters to the querystring:
field | type | description |
---|---|---|
limit | Number | The number of rows to return in a single batch. Default limit is 20, maximum 100. |
offset | Number | The offset number of rows to begin from when returning. Used in conjunction with 'limit' for pagination. |
search | String | A substring to search contacts for. The search term will be searched within all contact fields. |
sort_column | String | The column name to sort on when returning rows. |
sort_direction | String | The direction to sort, when used in conjunction with sort_column . Value can be asc or desc |
Create
POST
/v1/contacts
Use this end point to create or update an existing contact. If you supply a
previously unused unique_id
the API will create a new contact (see
Unique IDs to understand how the value of unique_id
is
determined). The post body should be a valid contact object.
Any fields submitted which are unrecognized will be ignored and no error returned.
Update/Upsert
PUT
/v1/contacts/:id
PATCH
/v1/contacts/:id
Use this end point to update an existing contact. The post body should be a valid contact object.
Body
See contact object.
Response
See contact object.
Create or Update a Batch
POST
/v1/contacts
The same endpoint that is used for single contact upserts can also handle batches of contacts. The API distinguishes intent based on the shape of the post body.
Body
field | description |
---|---|
contacts | An array of valid contact objects |
The response from this request will specify which contacts were created and which ones were updated.
Response
field | description |
---|---|
new_contacts | An array of contact objects that were created as a result of the request |
existing_contacts | An array of contact objects that were updated as a result of the request |
Accounts
An account
will always take this shape and support these fields when being
sent to or returned from the API. These are the top level fields that are most
common, and support native type casting for easier targeting. However, any other
fields can be stored in meta_private
or meta_public
for utilization in
targeting or personalizations.
field | type | description |
---|---|---|
account_number | String | required A unique ID for the account. |
contact.unique_id | String | required [1] The contact's unique_id with which to associate the account. |
product.code | String | required The product code associated with the account |
product.type [2] | String | required [2] The product's type, must be one of the following values: checking , savings , loan , lease , investment |
product.name [2] | String | The product's name |
product.description [2] | String | The product's description |
contact.role | String | The contact's role with this account, i.e. primary or joint |
micr | String | The account number that shows on a check's MICR line. If present, MICR is used before account number for the direct deposit widget. |
routing_number | String | The account's routing number. If present, this routing number is used for the direct deposit widget before falling back to the team's routing number. |
opened_date | Date | An ISO8601 formatted UTC date for when the account was opened |
closed_date | Date | An ISO8601 formatted UTC date for when the account was closed |
nickname | String | An account specific nickname |
balance | Decimal | The account's balance |
number_transactions_last_30_days | Integer | Number of transactions within the last 30 days |
total_amount_last_30_days | Decimal | Total amount of all transactions within the last 30 days |
status_code | String | The account's status code |
adverse_status | String | The account's adverse status code(s) |
channel_opened | String | The channel through which the account was opened |
closed_reason | String | The reason for which the account was closed |
credit_card_activation | Date | An ISO8601 formatted UTC date for when the associated credit card was activated |
last_mobile_pay_transaction | Date | An ISO8601 formatted UTC date for when the latest mobile pay transaction was made |
last_statement_balance | Decimal | The balance on the most recent statement |
last_transaction_amount | Decimal | The amount of the most recent transaction |
last_transaction_date | Date | An ISO8601 formatted UTC date for when the most recent transaction was made |
apy | Decimal | The account's APY |
charge_off | String | The account's charge off code |
payment_due_date | Date | An ISO8601 formatted UTC date for when the next payment is due |
in_person_deposit_check_date | Date | An ISO8601 formatted UTC date for when the most recent in-person check was deposited |
payment_frequency | String | If applicable, the account's payment frequency |
payment_method | String | If applicable, the account's payment method |
loan_payment | Decimal | If applicable, the loan's loan payment amount |
loan_payoff_date | Date | If applicable, an ISO8601 formatted UTC date for the loan's payoff date |
loan_principal | Decimal | If applicable, the loan's principal |
loan_term | String | If applicable, the loan's term |
maturity_date | Date | If applicable, an ISO8601 formatted UTC date for the loan's maturity date |
last_debit_card_transaction | Date | An ISO8601 formatted UTC date for the most recent debit card transaction |
last_mobile_pay_amount | Decimal | The amount of the most recent mobile pay transaction |
remote_deposit_last_30_days | Date | An ISO8601 formatted UTC date intended to represent the most resent remote deposit transaction if within the last 30 days |
meta_public | Object | Any account-related data that you want to use in personalizations or targeting. Data stored in this object is readable by anyone inspecting page content in a journey which means this field is not appropriate for storing sensitive data. See meta_public behaviors for more details. |
meta_private | Object | Private account-related data for use in personalizations or targeting. In order to utilize this information for personalizations, the contact must validate their identity when viewing the journey/page. If the contact does not validate their identity, this information is not exposed by the system. See meta_private behaviors for more details. |
Additionally account objects will contain these fields when being returned from the API. These fields are controlled by our system and should be considered readonly.
field | type | description |
---|---|---|
id | String | A UUID that uniquely identifies the account in our system. This value can be ignored, internally we generally use the account_number to cross-reference accounts. |
inserted_at | String | An ISO 8601 formatted UTC date showing when the account was added to our system. |
updated_at | String | An ISO 8601 formatted UTC date showing when the account was last updated in our system. |
contact.unique_id
[1] While technically not required in a batch upload, most account features cannot be utilized until the account is associated with a contact. The accounts will successfully be added to our system, and a later batch can contain this mapping alone and will only update this field.
Also note the same account_number
can occur in a batch with different
contact.unique_id
s, and that single account record will be associated with
both contacts (with the role specified as above).
[2] product attributes
When creating/updating accounts via the API, SFTP, or the batch upload Admin UI,
product attributes are accepted in the above format if the product doesn't
exist. If the account item has a product.code
that doesn't exist in the
system, it will create a product with that code, as well as with the items
provided from the above table. If the product.code
already does exist, we will
NOT update the product, the provided attrs will be ignored.
Create or Update a Batch
POST
/v1/batches
To create a batch of account imports via the API, you can submit a request to
v1/batches
with a type
of accounts
. This same endpoint is leveraged by our
SFTP service, our web admin, and our integrations.
Body
field | description |
---|---|
type | required must be account |
records | An array of valid account objects |
batch_id | Used for diagnostics, leave blank and we will assign a UUID for this batch. |
Getting a list of accounts for a contact
POST
/v1/contacts/:contact_id/accounts
You can get a list of very limited account information for a contact. Most attributes are inaccessible via the API for security purposes, and exist only for utilization in targeting and personalizations. The attributes here also represent the attributes that are available in personalizations without authenticating.
The response of this endpoint is a shape of "contact accounts," representing the relationship a contact has with accounts (many-to-many). This relationship currently only has a "role."
[
{
"role": "primary",
"account": {
"id": "744151d1-8552-4987-8f0c-56013f5dbfcd",
"nickname": "Smith Family Checking",
"meta_public": {
"welcome_note": "Welcome!"
},
"product": {
"id": "5dd3d574-20aa-42f8-be96-61bc36c8ab09",
"type": "checking",
"code": "C100",
"name": "Family Checking",
"description": "",
"services": [{
"id": "3f808601-cd32-42ac-86eb-8be72eb5691d",
"name": "eStatements"
}, {
"id": "e9b53b5b-31de-415e-bb78-7e0880296de0",
"name": "Direct Deposit"
}]
}
}
}
]
Journeys
Journey endpoints accept these fields when sending journey
objects.
field | description |
---|---|
owner_id | The id of the user who should be set as the owner of the journey |
contact | A valid contact object |
source | The source of this journey's association with the Campaign. System-generated values include api , admin-console , automatic-targeting , and direct . Custom values may be passed at creation for source tracking |
Create a Journey from a Template
POST
/v1/templates/:template_id/journeys
This endpoint is for creating a specific journey for a single contact.
Body
See journey object
Response
field | description |
---|---|
id | The id of the journey that was created |
slug | The custom path for the journey that was created |
template_id | The id of the template to use for creating a journey (note this param is specified in the request path) |
web_client_url | The full url for the journey that was created |
Retrieve journeys associated with a specific contact
GET
/v1/journeys
Parameters
field | description |
---|---|
contact_id | The UUID of the contact to be queried |
Response This endpoint returns an array of JSON objects in the following form:
field | description |
---|---|
analytics_cache | An object containing keys describing the status of the journey's progress. See below for additional detail |
completion_verified_at | An ISO8601 formatted UTC date marking when this journey was manually set as completed, or null |
contact | A contact object. See contact object for additional detail |
id | This journey_id |
inserted_at | An ISO8601 formatted UTC date marking when this journey was created |
reward_dispensed_at | AN ISO8601 formatted UTC date marking when this journey's reward was dispensed |
slug | This journey's unique slug |
source | The source of this journey's association with the Campaign. System-generated values include api , admin-console , automatic-targeting , and direct . Custom values may be passed at creation for source tracking |
template | A template object for the campaign template associated with this journey. See template objects for additional detail |
template_id | The campaign template associated with this journey |
updated_at | An ISO8601 formatted UTC date marking when this journey was last updated |
Note that meta_private information will not be returned in any contact object unless you have provided an OAuth2 Header as described at the beginning of this document.
Analytics Cache
An object returned above which contains the following structure
field | description |
---|---|
is_completed | A boolean describing whether this journey has at least one journey_completed action |
is_completely_viewed | a boolean describing whether all pages (at the time of caching) have at least one page_viewed action |
last_viewed | An ISO8601 formatted UTC date containing the most recent page_viewed action's timestamp |
pages_completed | An array of page_id s that have at least one page_completed action |
pages_viewed | An array of page_id s that have at least one page_viwed action |
Update a Journey's progress for a given Campaign
PUT
/v1/templates/:template_id/journeys/:journey_id
This endpoint sets progress for a particular Journey on a Campaign.
Body
Accepts an application/json object with either of these values:
Set Completion for this Journey
{
"is_completion_confirmed": true
}
Set Reward Dispensed for this Journey
{
"is_reward_dispensed": true
}
Response
field | description |
---|---|
completion_verified_at | The date this journey's completion was logged, in ISO8601 format |
id | This journey_id |
inserted_at | The date this journey was created, in ISO8601 format |
reward_dispensed_at | The date this reward was marked as dispensed in ISO8601 format, or null if it has not been marked as dispensed |
slug | The custom path for the journey that was created |
source | The source of this journey's association with the Campaign. System-generated values include api , admin-console , automatic-targeting , and direct . Custom values may be passed at creation for source tracking |
template_id | The template_id for this Campaign |
updated_at | The date this journey's record was last updated, in ISO8601 format |
Templates
Template endpoints will return these fields when describing template
objects.
field | description |
---|---|
id | The id of the template for use when creating journeys |
name | The name of the template |
Get a list of templates
GET
/v1/templates
This endpoint returns a list of templates available in your team.
Response
field | description |
---|---|
templates | An array of template objects |
Objectives
field | description |
---|---|
key | Key to be used in CSV/Contacts Upload when referring to this objective |
name | User friendly name |
id | Digital Onboarding id |
team_id | The team this belongs to. This will be null if the objective is global and not created by your team. |
Get a list of objectives
GET
/v1/objectives
Retrieves all of the current objectives that exist for your team.
Response
field | description |
---|---|
objectives | An array of objective objects |