Using the API
Environments
Our API and Dashboard are available in two environments:
| Name | Dashboard URL | API URL |
|---|---|---|
| Sandbox | https://app.s.unit.sh/ | https://api.s.unit.sh/ |
| Live | https://app.unit.co | https://api.unit.co/ |
The sandbox environment contains special API operations that allow you to easily test and simulate different activities, from incoming payments to card spend. You can find the full reference under the various Simulation pages.
Authentication
Unit's API uses OAuth 2.0 Bearer Token to authenticate requests. All API calls must include a bearer token.
An invalid, missing or expired token will result in HTTP 401 Unauthorized responses.
GET /accounts HTTP/1.1
Host: api.s.unit.sh
Authorization: Bearer v2.public.eyJyb2xlIjoib3JnIiwidX...
Tokens
Unit Clients can use 2 types of API tokens:
- Org API tokens are broad, system level API tokens, that are not restricted to a specific end customer.
- Customer Tokens are end-customer specific, and only allow access to resources associated with a specific customer.
When a token is created, it is assigned a set of Scopes The scopes define the resources that can be accessed using that token, and the access level (read / write) that will be allowed using that token.
Unit recommends using Customer Tokens as a default, for all end-customer related actions:
- Customer tokens deny access to all resources that aren't associated with the authenticated customer. If a customer token with access to sensitive scopes is compromised, the impact is restricted to the specific customer. If an org API token with access to sensitive scopes is compromised, the impact could be far greater.
- Customer tokens include built-in Two Factor Authentication (OTP) and expiry (customizable, up to 24 hours), so you don't have to implement it.
In order to retrieve decoded token information, send an HTTP GET request to the /identity endpoint with the Authorization header containing the token.
curl -X GET 'https://api.s.unit.sh/identity' \
-H "Authorization: Bearer ${TOKEN}"
Two Factor Authentication (2FA)
Unit requires that you take the customer through two factor authentication in a number of scenarios, detailed in the table below.
| Use case | Details |
|---|---|
| Applications | The customer's phone number must be verified using OTP (which is a form of 2FA) In order to submit an application. If you choose to use Unit's application form, we will execute the 2FA on your behalf. |
| Sensitive Scopes | The customer must be taken through 2FA at least once in the 24 hours prior to accessing a sensitive scope. We highly recommend using customer tokens for that purpose. |
| PCI Sensitive data | You are required to use a valid Unit customer token in order to access and execute actions that are covered by PCI compliance (card related data and actions, including activating the card, setting and changing the PIN, and revealing the card number and CVV2 for virtual cards). You cannot rely on your own two factor authentication and Org API tokens for that purpose, unless you are PCI level 1 compliant. |
If you would like to rely on your own two factor authentication for all non-PCI related sensitive actions, you may do so. In this scenario, you would use an Org API token with the relevant scopes to access the Unit API.
Acceptable two factor authentication methods include one time password (OTP) (through SMS or call), biometric authentication and other industry recognizable methods.
A successful two factor authentication is valid for up to 24 hours, and you responsible for enforcing the 24 hour expiry and re-authenticating the customer when needed.
Scopes
Scopes define the level of access a token will have to resources in Unit.
A list of all scopes within Unit:
Scopes that are related to fund movement are considered sensitive, and are in the table below. Scopes that require PCI compliance to access are highlighted in .
Any action that requires access to these scopes, must be protected by Two Factor Authentication. If you follow the best practice and use a Customer Token for such actions, Unit will execute the authentication for you. If you decide to use an Org Token, you will have to implement it yourself.
The org token can be used without 2FA for sensitive operations triggered from the server side.
| Resource | Read Scope | Write Scope | Accessible Using |
|---|---|---|---|
| Application | applications | Org API token | |
| Customer Token | customer-token | Org API token | |
| Customers | customers | Org API token, Customer Token | |
| Customer Tags | -- | Org API token, Customer Token | |
| Accounts | accounts | Org API token, Customer Token (exception: Close Account ) | |
| Account limit overrides | Bank Operations (Read-only) | Bank Operations | Org API token only |
| Cards | cards | Org API token, Customer Token | |
| Cards Sensitive | Customer Token | ||
| Transactions | transactions | Org API token, Customer Token | |
| Authorizations | authorizations | -- | Org API token, Customer Token |
| Statements | statements | -- | Org API token, Customer Token |
| Payments | payments | Org API token, Customer Token | |
| Payments to a counterparty | -- | Org API token, Customer Token | |
| Payments to a linked account | -- | Org API token, Customer Token | |
| Payments ACH Debit | -- | Org API token, Customer Token | |
| Payments ACH | -- | Org API token, Customer Token | |
| Payments Wire | -- | Org API token, Customer Token | |
| Counterparties | counterparties | Org API token, Customer Token | |
| Events | events | Org API token, Customer Token | |
| Webhooks | webhooks | Org API token | |
| Authorization Requests | authorization-requests | Org API token | |
| Batch Releases | batch-releases | Org API token | |
| Check Deposits | check-deposits | check-deposits-write | Org API token, Customer Token |
| Check Payments | check-payments | Org API token, Customer Token | |
| Account End-Of-Day | accounts | -- | Org API token, Customer Token |
| Received Payment | received-payments | Org API token | |
| Chargeback | chargebacks | Org API token | |
| Reward | rewards | Org API token | |
| Wire Drawdowns | wire-drawdowns | wire-drawdowns-write | Org API token, Customer Token |
By default, creating an Org API token through the Create Token Page on the Dashboard selects the recommended scopes for an Org API token.
SDKs
Unit, with the help of our developer community, maintains open source SDKs in multiple programming languages. The SDKs are available on Github, and encapsulate all resources and API endpoints.
OpenAPI Specification
OpenAPI is an industry standard for describing RESTful APIs, which can be used to provide easier use and integration with the API, the generation of client libraries (SDKs), testing, integration with various developer tools and more. An OpenAPI 3.0 specification for the Unit API is available here.
| Technology | Author |
|---|---|
| OpenAPI spec | Unit |
| Ruby | Unit |
| Java | Unit |
| Ruby | Community |
| Typescript | Community |
| Python | Community |
You may use the Unit OpenAPI specification along with Swagger or the OpenAPI generators to auto-generate Unit API client libraries for your language of choice.
Note that we do not guarantee that the generated SDKs will be fully compatible with our API, nor support all endpoints. We encourage members of the Unit SDKs community to share feedback, bug reports and pull requests with suggestions for improvements to help us identify and address any potential issues.
Reporting Issues
You may report any issues you find with the SDK by creating a Github issue (TypeScript issues, Python issues). As previously mentioned, the SDKs are open source, so if you have resolved an issue locally, please raise a PR and we will publish it, so that other members of the Unit developer community may benefit from it.
Postman Collection
You can interact immediately with the Unit API via Postman in two ways.
-
Make API calls yourself. To get started, import the Unit API Postman Collection into Postman. You can then send any request with the dummy data provided or customize it.
-
Populate your development environment with a dummy data set. You can import the Unit API Starter Collection into Postman, then run the full collection.
After making requests with Postman, you can see the API calls you made reflected in the Unit Dashboard as applications, customers, accounts, transactions, etc.
Both collections contain two variables:
| Key | Value |
|---|---|
token | Your API Token. You can create it from the API Tokens page in the Developer section of the Unit Dashboard. |
server_url | Initially set to the Unit Sandbox environment (https://api.s.unit.sh/). |
For more information, see the following Postman article: Importing Data into Postman.
About JSON:API
Unit's API is REST-based and follows the JSON:API specification.
JSON:API specifies how a client should request resources to be fetched or modified, and how a server should respond to those requests. Resources in Unit include applications, customers, cards, accounts, transactions and more.
JSON:API is designed to minimize both the number of requests and the amount of data transmitted between clients and servers. This efficiency is achieved without compromising readability, flexibility, or discoverability.
JSON:API requires the use of the JSON:API media type (application/vnd.api+json) for exchanging data.
Request and Response Structure
All JSON:API requests and responses are JSON documents.
A document MUST contain one of the following top-level members:
- data: the document's "primary data". Example: when creating an individual application resource, the primary data will contain the individual's personal information.
- errors: an array of error objects.
Primary data MUST be either:
- a single resource object for requests that target single resources, or
- an array of resource objects for requests that target resource collections.
{
"data": {
"type": "individualCustomer",
"id": "1",
"attributes": {
// ... this customer's attributes
},
"relationships": {
// ... this customer's relationships
}
}
}
{
"data": [
{
"type": "individualCustomer",
"id": "1",
"attributes": {
// ... this customer's attributes
},
"relationships": {
// ... this customer's relationships
}
}, {
"type": "businessCustomer",
"id": "2",
"attributes": {
// ... this customer's attributes
},
"relationships": {
// ... this customer's relationships
}
}
]
}
Resource Object
JSON:API documents may contain resource objects to represent objects in the business domain. Unit's resources include applications, customers, cards, accounts, transactions and more.
A resource object MUST contain both the id and the type members.
Exception: the id member is not required when the resource object originates at the client and represents a new resource to be created on the server.
In addition, a resource object MAY contain these members:
- attributes: an attributes object represents some of the resource's data (examples include the resource name, address, email, etc.)
- relationships: a relationship object describes the relationship between the current resource and other resources
{
"type": "individualCustomer",
"id": "53",
"attributes": {
"createdAt": "2020-05-12T19:41:04.123Z",
"fullName": {
"first": "Peter",
"last": "Parker"
},
"nationality": "US",
"ssn": "721074426",
"address": {
"street": "20 Ingram St",
"street2": null,
"city": "Forest Hills",
"state": "NY",
"postalCode": "11375",
"country": "US"
},
"dateOfBirth": "2001-08-15",
"email": "peter@oscorp.com",
"phone": {
"countryCode": "1",
"number": "5555555555"
}
},
"relationships": {
// ... relationships
}
}
Relationships
The relationships object describes the relationship between the current resource and other resources. Each member of the relationships object represents one reference.
In this example, we describe the relationship between a DepositAccount or CreditAccount and the customer it belongs to.
Relationship
A "relationship object" MUST contain a data member with one of the following:
nullfor empty to-one relationships.- an empty array (
[]) for empty to-many relationships. - a single resource identifier (
typeandid) for non-empty to-one relationships. - array of resource identifiers (
typeandid) for non-empty to-many relationships.
{
"type": "depositAccount",
"id": "50",
"attributes": {
// ...
},
"relationships": { // relationships object
"customer": { // relationship object
"data": { // resource linkage with single resource identifier
"type": "businessCustomer",
"id": "39"
}
}
}
}
Getting Related Resources
Get operations on certain resources (such as Card) contain an include query parameter that helps you get multiple related resources within the response. You may specify one or more relationships (comma-separated- see example). The response will then contain an included key with the related resources.
The ability to get related resources helps you turn multiple API calls into one. The result is cleaner code and no data integrity questions that usually arise when making multiple API calls at slightly different points in time.
curl -X GET 'https://api.s.unit.sh/cards/41?include=customer,account' \
-H "Authorization: Bearer ${TOKEN}"
{
"data": {
"type": "individualDebitCard",
"id": "41",
"attributes": {
"createdAt": "2020-11-30T16:00:52.919Z",
"last4Digits": "0261",
"expirationDate": "2023-11",
"status": "ClosedByCustomer"
},
"relationships": {
"customer": {
"data": {
"type": "customer",
"id": "10156"
}
},
"account": {
"data": {
"type": "account",
"id": "10075"
}
}
}
},
"included": [
{
"type": "depositAccount",
"id": "10075",
"attributes": {
"name": "April Oneil",
"createdAt": "2020-11-30T15:56:59.670Z",
"routingNumber": "812345678",
"accountNumber": "1000000075",
"depositProduct": "checking",
"balance": 144785,
"hold": 0,
"available": 144785,
"tags": {},
"currency": "USD"
},
"relationships": {
"customer": {
"data": {
"type": "customer",
"id": "10156"
}
}
}
},
{
"type": "individualCustomer",
"id": "10156",
"attributes": {
"createdAt": "2020-11-30T15:54:22.788Z",
"fullName": {
"first": "April",
"last": "Oneil"
},
"ssn": "110000002",
"address": {
"street": "20 Ingram St",
"city": "Forest Hills",
"state": "CA",
"postalCode": "11375",
"country": "US"
},
"dateOfBirth": "2001-08-10",
"email": "april@baxter.com",
"phone": {
"countryCode": "1",
"number": "5555555555"
},
"soleProprietorship": false,
"tags": {}
},
"relationships": {
"application": {
"data": {
"type": "application",
"id": "10186"
}
},
"org": {
"data": {
"type": "org",
"id": "1"
}
}
}
}
]
}
Errors
The Unit API uses standard HTTP Status Codes to communicate whether a request has been successfully processed or not. A request may stop processing as soon as a problem is encountered, or it may continue processing and encounter multiple errors. More than one schema validation issues will usually yield multiple errors, while server processing issues will yield a single error. In either case, the response will contain all available errors.
An "error object" MUST contain an HTTP status code member, and may also contain one or more of the following:
- code: Optional. A Unit-specific underscored code, uniquely identifying the error reported. A growing list of the currently available error codes can be found on the Unit Errors section of the docs.
- detail: Optional. A human readable description of the error providing additional information about the error.
- Meta: Optional. A meta object that contains name/value pairs related to the error.
- meta.supportId Unique error identifier to be used for further investigation.
- meta.existingIds Optional. Existing IDs of duplicate entries.
{
"errors": [
{
"code": "already_exists"
"detail": "Customer is already archived.",
"status": "409",
"meta": {
"supportId": "b4d744af-332a-e7hd-td3c-9bd79a21f35a"
}
}
]
}
JSON Schema
You can download an archive with JSON Schemas for the Unit API.
You can use one of the libraries that generate types from JSON schemas - see table below for examples of common language specific libraries.
| Language | Library |
|---|---|
| NodeJS / TypeScript | json-schema-to-typescript |
| Python | yacg (Yet Another Code Generation) |
| PHP | php-code-builder |
Required Fields
Unless specified otherwise, all the fields in the request payload are required. Some fields are only required under specific circumstances - these fields are pointed out throughout the documentation.
Idempotency
Some of our API operations support request idempotency, allowing you to call a sensitive operation multiple times and assume that its work will be done no more than once. You may use any string of up to 255 characters as an idempotency key (we recommend UUID version 4).
The guarantee of idempotency is crucial when an API call has failed without a clear reason and a retry is due. For example, if creating a payment does not succeed due to a network error, you can safely retry creating the payment, passing the same idempotency key and assume the payment will occur no more than once, regardless of the number of calls.
Idempotency keys are guaranteed effective for 48 hours from the time they're used successfully. After this time window, they will be recycled and existing keys will therefore be treated as new.
Idempotency keys are not shared between different API operations, so you could potentially use the same idempotency key for different types of operations, although we do not recommended it.
One exception here is debit card creation for which both physical card creation and virtual card creation are sharing the idempotency key.
Retries
API requests can fail for many reasons, from network components failures, API rate limits, timeouts or service incidents. As a best practice, we recommend implementing a request retrying mechanism with the following attributes:
- Only the requests that failed with the following HTTP status codes should be retried:
- 5xx (Server errors)
- 429 (Rate Limits)
- 408 (Timeouts)
- Retry should have an exponential backoff and/or jitter.
- Make sure to add idempotency key where applicable.
Rate Limits
Our rate limit is based on your IP address and is set to 1,000 requests per minute. The limit applies to each environment (sandbox and live) separately. If the limit is exceeded, responses will include an HTTP 429 status code along with a relevant message.
Timeouts
All of our APIs have timeouts to make sure we fail as soon as possible and allow you to retry the request. It is considered good practice to set the same request timeout for the clients as well. We have two types of timeouts:
- Short timeout - Most APIs will use the default timeout of 5 seconds
- Long timeout - Few APIs require longer timeouts, these use a timeout of 60-120 seconds
Please refer to the relevant API docs to determine the timeout for your request.
Full-Text Search
The List operation under certain resources (such as Application, Customer or Transaction) supports full-text search, to help you find the desired resources more easily.
In particular, you can use full-text search to quickly build better end-customer experiences. An example would be adding a search box that lets end-customers search for transactions by merchant name (e.g. 'starbucks') when browsing transactions under their account.
Full-Text search rules:
-
unquoted text: text without quote marks will be converted into words separated by 'And' operators. Example: 'john doe' will search for a resource with the value 'john' and the value 'doe'. -
OR: will be converted into words separated by the 'Or' operator. Example: 'john or doe' will search for a resource with either the value 'john' or the value 'doe'. -
-: will be converted into the 'Not' operator. Example: 'john -doe' will search for a resource with the value 'john' and without the value 'doe'.
Pagination
List operations on all resources (example: List Customers) return a list of resources.
To page through a long list, use the following two query parameters:
page[limit]: Limit the number of resources to be returned (between 1 and 1000). Defaults to 100 when no value is provided.page[offset]: Number of resources to skip. Defaults to 0 when no value is provided.
Organization Accounts
Organization accounts (also known as org accounts) are special-purpose accounts that Unit sets up to support your activities. Unlike deposit accounts, org accounts exist on the org level and are not under your customers. Since the accounts have a special purpose, they only support specific functions that are relevant to their use case.
Common types of org accounts include:
- Revenue account: the account that Unit automatically credits with your org's interchange, interest and payment revenues. Withdrawals from the Revenue account will be done to an account of your choice after it is linked with your revenue account. Contact Unit support to set up a link to your chosen account/s.
- Reserve account: the account that Unit automatically debits for a range of situations, including disputes and ACH returns. This account requires an initial balance to be funded, and monthly recalculation to determine the reserve amount required based on risk.
- Batch account: see Batch Payments
Your org accounts can be accessed from the Unit Dashboard.
Some types of organization accounts, such as batch accounts, are designed to be used for incoming and outgoing payments. Others, such as reserve accounts, offer limited payments functionality by design.
Data Integrations
Unit allows its clients access to their raw data, so that they can build their own reporting solutions and make informed business decisions. This integration provides a continuous data transfer into an AWS S3, Google Cloud Storage bucket or Azure Blob Storage. You can pull the data into your own data warehouse easily with existing cloud storage connectors, eliminating the need to build a sequence of API calls to obtain data. For more information visit the Date Export guide.
Deprecations
Unit will, from time to time, deprecate certain API endpoints and services. This does not mean that they are no longer available - deprecating an endpoint means that this is no longer the recommended way to implement the relevant functionality, and Unit will not make updates or changes to that endpoint. Deprecated endpoints may be retired at a later point in time - subject to a minimum of a six month notice period, like all breaking changes on Unit, unless they follow an urgent security or compliance change.