> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.upwardli.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.upwardli.com/_mcp/server.

# Credit Builder Card API-First Documentation

> **Info**
>
> **Please note:**  If your company is integrating our Card product using only our APIs, you’re in the right spot!

## Overview

Upward provides a seamless and secure way for businesses to enable a credit building card to their end users. End users can incorporate credit building into their daily activities by loading money to their FDIC insured DDA account and then swiping their card at any location where Mastercard is accepted. Upward’s platform customers are able to monetize the card through interchange, deposit interest, and expedited external payments.

---

# Introduction

Welcome to the Credit Builder Card! Our documentation will walk you through the basics (authentication, request structure) to using and creating the financial products associated with the Credit Builder Card (accounts, cards, payments, etc.).

The introduction covers basic concepts you should be familiar with in order to make the most out of the Upward card issuance and management platform.

---

## How the Credit Builder Card Works

![Credit Builder Card Diagram](/_fern-img/e79028e2259f1170c9324172b0d06303c679a1fe3a0e372e502a76d4f8501fef.webp)

* The card’s available credit is equal to:
  * the available funds that the user maintains in a linked deposit account, plus
  * any verified incoming payments to the user, such as payments due for wages or gig work
* The user may obtain a physical, digital card or both. The user makes purchases anywhere Mastercard is accepted.
* As the user makes purchases on the card, an equal amount of funds in the linked deposit account are put on hold, and the card’s available credit decreases in an equal amount.
* The cardholder may opt in to automatic payments to pay off balances as they incur charges, but must pay the card’s balance in full on the payment due date.
* If the balance is not paid on time and the DDA balance is at zero the card will freeze until the user has made a payment.
* By default, there are no fees to use the card and the user is charged 0% APR.

---

## Implementation Options

Upward offers three ways to integrate the credit builder card into your website or mobile app for your credit program.

* **Use Credit Builder Card APIs**. When integrating credit builder cards into your own website or app, this option offers flexibility in designing a unique user experience including the credit services and financial products you wish to offer. This option provides a secure, PCI-compliant, customizable experience for purchasing and providing basic banking services (i.g statements, transaction, history, card management, etc).
* **Use our Embedded Integration.** The embedded flow is a drop-in module that enables you to seamlessly offer a credit builder card within your app or web page. It allows individuals to easily access their credit and credit builder card details securely without redirecting away from your app or website.
* **Leverage an Upward Hosted App**. If you do not want to build and host a credit account and banking experience, Upward can handle the product build and push to your app store instance. This approach offers less flexibility and, while easier to implement, it requires higher platform fees.

---

# Environments

**There are two types of environments for the Upward Credit Suite:**

1. **Sandbox**\
   You can test out your integration and explore common usage patterns in our sandbox environment. This environment is fully isolated and will not perform any “live” financial transactions.

You can request sandbox access once you have a signed contract.

> **Info**
>
> **Important:** The Sandbox environment is fully secure, but you
> should not store any real consumer data here.

2. **Production**\
   Once you have completed sandbox testing and submitted your test plans, you will be provisioned production access keys. These details will be shared with you via a secure sharing mechanism. All transactions in our production environment are live financial activity.

## Getting Started

Regardless of which method you choose for integration you will always need to follow our authentication methods.

### Authentication

Upward’s API uses OAuth 2.0 to authenticate requests. All API calls must include a token. These authentication tokens are used for machine to machine communication.

> **Info**
>
> **Note:** An invalid, missing or expired token will result in an
> \{invalid\_token} response

## URLs

> **Info**
>
> Environment URL Sandbox Authentication [https://auth-sandbox.upwardli.com/auth/token](https://auth-sandbox.upwardli.com/auth/token)
>
> Production Authentication [https://auth.upwardli.com/auth/token](https://auth.upwardli.com/auth/token)

## Tokens

Upward has the concept of three different tokens:

* **Customer Onboarding Tokens**: are system level and assigned to a specific organization that allows you to onboard new users. Once a user is onboarded you would use the customer token to access their specific information.
* **Customer Access Tokens:** are specific to an end user also known as consumers in our product and only provide data specific to that consumer. These tokens are used to secure our embedded components.
* **Partner API Tokens:** are highly secure tokens that are used to integrate your backend platform with Upward’s APIs. These tokens **SHOULD NOT BE USED OUTSIDE OF DIRECT API CALLS BETWEEN YOUR SYSTEM AND UPWARD.**

When a token is created, it is assigned a set of Scopes. The scopes define the resources that can be accessed using the token, and the access level (read/write) that will be allowed using that token.

> **Info**
>
> **NOTE ON TOKEN EXPIRATION**:
> Partner API Tokens **expire after 10 hours** **have elapsed since creation**, and Customer Access Tokens expire after 1 hour
>
> If a new token is not requested then it will result in a 403 screen.

## Scopes

Scopes define the access level of a token.

**A list of all scopes within Upward:**

| Scope                        | Token Type            | Use                                                                        |
| ---------------------------- | --------------------- | -------------------------------------------------------------------------- |
| `api:read`                   | Partner API Token     | Used to perform read actions on the platform                               |
| `api:write`                  | Partner API Token     | Used to perform full CRUD operations on the platform                       |
| `ui:client-onboarding`       | Partner API Token     | Used for the client onboarding component                                   |
| `api:card-management:read`   | Customer Access Token | Used to populate all card-management pages, card image                     |
| `api:card-management:write`  | Customer Access Token | Perform card management actions (pin change, freeze/unfreeze, lost/stolen) |
| `api:consumer-profile:read`  | Customer Access Token | Used to populate all profile pages (dispute, statements)                   |
| `api:consumer-profile:write` | Customer Access Token | Used for account closing                                                   |
| `api:credit-goals:read`      | Customer Access Token | Used to populate credit goals page                                         |
| `api:purchase:write`         | Customer Access Token | Create an ACH transfer in and out of an individual’s account               |
| `api:purchase:read`          | Customer Access Token | Retrieve an ACH transaction history for an individual                      |
| `api:statements:read`        | Customer Access Token | Retrieve statements directly                                               |
| `api:accounts:read`          | Customer Access Token | Get bank accounts                                                          |
| `api:accounts:write`         | Customer Access Token | Create bank accounts                                                       |
| `api:simulated-card:write`   | Customer Access Token | Simulate funding/auth/settlement                                           |

## Requesting Tokens Using The API

The Upward API uses OAuth 2.0 for authentication and authorization. Before you can use the API, you must obtain an access token using the client\_id and client\_secret provided to you. Once a token has been obtained, it must be passed in the Authorization header of each request to the API.

## Customer Onboarding Token Request

To request a token send a POST to our auth server containing your client ID and client secret values.

POST [https://auth-sandbox.upwardli.com/auth/token/](https://auth-sandbox.upwardli.com/auth/token/)

```json
{
  "header": "content-type: application/json",
  "grant_type": "client_credentials",
  "client_id": "[your id here]",
  "client_secret": "[your secret here]",
  "scope": "ui:client-onboarding"
}
```

Here’s a cURL example for the token request:

```json
POST https://auth-sandbox.upwardli.com/auth/token/ \

    --header 'Content-Type: application/json' \
    --data \
'{
    "grant_type":"client_credentials",
    "client_id":"[api client key]",
    "client_secret":"[api client secret]",
    "scope":"api:read api:write ui:client-onboarding"
}'

curl --location 'https://auth-sandbox.upwardli.com/auth/token/' \
--header 'Content-Type: application/json' \
--data '{
    "grant_type": "client_credentials",
    "client_id": "XXXXXX",
    "client_secret": "XXXXXX",
    "scope":"api:read api:write ui:client-onboarding"
}'
```

Here’s what a successful response looks like:

```json
{
  "access_token": "xxxxx",
  "expires_in": 86400,
  "token_type": "Bearer",
  "scope": "api:read api:write ui:client-onboarding"
}
```

## Exchanging Partner API Token for a Customer Token

Once a valid token has been obtained using the Authentication API, a limited scope token can be obtained using the token exchange API. This token can be used to make requests for a specific consumer, and is safe to send to the client application/web browser as needed.

To request a token exchange send a POST to our auth server containing the access\_token and requested scope.

> **Info**
>
> This token expires after 1 hour and will need to be exchanged for a new token for the customer to continue to have access.

**Notes:**

* The audience must be for the correct Environment.
  * Sandbox: `https://auth-sandbox.upwardli.com`
  * Production: `https://auth.upwardli.com`
* The upward\_consumer\_id is the Upward id that you get from the Consumer API or the `consumer.created` webhook.
* The new access token is a significantly longer string than the original access token.

POST [https://auth-sandbox.upwardli.com/auth/token/exchange/](https://auth-sandbox.upwardli.com/auth/token/exchange/)

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
    "grant_type":"urn:ietf:params:oauth:grant-type:token-exchange",
    "subject_token_type":"urn:ietf:params:oauth:token-type:access_token",
    "subject_token":"[access_token]",
    "audience":"https://auth-sandbox.upwardli.com",
    "scope":"<See scopes table> consumer:[upward_consumer_id]"
}
```

Here’s what a successful response looks like:

```json
{
  "token_type": "Bearer",
  "expires_in": 3600,
  "access_token": "[scoped access token]",
  "scope": "<Scope(s)>",
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token"
}
```

---

## Onboarding a New User

A consumer is the individual end user that you are creating a credit product. Consumers are limited to individuals using a valid SSN or ITIN, or single-member LLCs (coming soon).

A Consumer record is automatically created once an application is started and Upward will manage the ongoing regulatory requirements tied to application notice, approval and denial notifications to the end user.

Consumer onboarding is a fully asynchronous process due to the KYC and Banking integrations, which are themselves asynchronous. Our design goal for customers interacting with the Onboarding component is to capture data in realtime, and then process asynchronously. This will reduce elapsed consumer interaction time and improve the customer experience.

> **Info**
>
> NOTE: we recommend listening to [webhooks](/concepts/webhooks/introduction). to be notified of the status of each consumer as they make their way through the application and approval process. You will have access to the consumers financial products once they have been fully onboarded and approved.

All consumers are created as part of our onboarding. Regardless of the integration method you’ll need to use our embedded iframe to offer our application flow. We do allow you to customize the UI of the application but to ensure consistent and fair lending practices we own the specific language and disclosures surrounding the application process.

---

### Authentication & Loading the Onboarding Embedded Flow

Authentication

***Tip: Your API Key and Secret will be shared with you by your Upward client team.***

The first step in integrating your product is to configure authentication. All Upward components and APIs require Oauth tokens for access.

### Creating the Consumer Record

POST `https://api-sandbox.upwardli.com/v2/consumers/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{
  "id": "{consumer_id}",
  "pcid": "{pcid}",
  "first_name": "John",
  "last_name": "Doe",
  "email": "john.doe@email.com",
  "phone_number": "425-555-1212",
  "date_of_birth": "1999-10-06",
  "tax_identifier": "123-45-6789",
  "address_line1": "121 Big Creek",
  "address_city": "Tuscaloosa",
  "address_state": "AL",
  "address_zip": "35405"
}
```

Response

```json
{
  "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
  "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
  "first_name": "John",
  "last_name": "Doe",
  "email": "john.doe@email.com",
  "is_active": true,
  "kyc_status": "Complete",
  "phone_number": "425-555-1212",
  "date_of_birth": "1999-10-06",
  "tax_id_type": "SSN",
  "tax_identifier": "***-**-6789",
  "address_line1": "121 Big Creek",
  "address_line2": null,
  "address_city": "Tuscaloosa",
  "address_state": "AL",
  "address_zip": "354050000"
}
```

Upward sends out a consumer.created webhook message to your server. The
Upward Servers will send a webhook message to you with the following general schema,
indicating that the consumer record was created on our side.

```json
{
  "id": "ea04f0a8-b005-47cd-ba33-b02a00c0c426",
  "created_at": "2023-06-23T07:41:50.45-04:00",
  "event_name": "consumer.created",
  "partner_id": "2f221c90-b82d-4e12-9bfd-ae8301097de3",
  "resources": ["https://api-sandbox.upwardli.com/v2/consumers/{consumer_id}"],
  "last_attempted_at": "2023-06-23T07:41:50.45-04:00"
}
```

**You Link the Upward ID to your Local Object.** Upon receiving the webhook message, you will parse it for the eventName property and determine that this message means that a new consumer was created. You can then call the url in the resources property to get information about that consumer.

Example of output via API - assuming the consumer stopped before complete KYC and that you did not pre-fill any data for that user.

> **Info**
>
> NOTE: At the time of creation, the user has not completed KYC, so their
> personal data has not been captured and will be null in the response body.

## **Onboarding Flow UI Specifics**

Our onboarding endpoints expose hooks into the custom onboarding workflows created for your consumers. Each step/section can be completed individually and in any order. API-based Consumer onboarding can begin once the consumer object has been created.

The details below outline the standard flow of onboarding a consumer:

1. Get Started
2. Verify the Consumer’s Identity (KYC)
3. \[optional] Provide product decision details
4. \[optional] Provide Underwriting decisioning
5. Accept Terms
6. Submit Loan

Additionally, we support adding per-consumer metadata to each onboarding object. Metadata is also how you set the consumer’s autopay election — see the section entitled: *“Managing Metadata on the Onboarding Object”* below.

### Step 1: Get Started

To start the onboarding workflow for a user, you post a message containing the `pcid` of the consumer and an `onboarding_template_id` value of `card_onboarding`. The API will return a partially hydrated onboarding object containing the consumer’s current onboarding state.

POST `https://api-sandbox.upwardli.com/v2/onboarding/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{
  "pcid": "{consumer pcid}",
  "onboarding_template_id": "card_onboarding"
}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": null
    },
    "e_sign": {
        "agreement_accepted": null,
        "agreement_accepted_date": null
    },
    "product": {
        "product_id": null
    },
    "underwriting": {
      "result": null,
      "data": null
    },
    "previous_step": {
        "slug": "get_started",
    },
    "current_step": {
        "slug": "verify_identity",
    }
}
```

### Step 2: Verify the Consumer’s Identity (KYC)

Each consumer will see an entry screen that will highlight the value props and also include the appropriate disclaimers for the product.

POST `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}/verify_identity`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": null,
        "agreement_accepted_date": null
    },
    "product": {
        "product_id": null
    },
    "underwriting": {
      "result": null,
      "data": null
    },
    "previous_step": {
        "slug": "get_started",
    },
    "current_step": {
        "slug": "accept_terms",
    }
}
```

### Step 3: Provide product decision details

The is optional step allows you to provide external data for decisioning for consumer underwriting.

POST `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}/select-product`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{
  "product_id": "{product_id}"
}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": null,
        "agreement_accepted_date": null
    },
    "product": {
        "product_id": "95630f7a-dc51-4c61-914b-14c26b99968c"
    },
    "underwriting": {
      "result": "pass",
      "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2\}"
    },
    "previous_step": {
        "slug": "get_started",
    },
    "current_step": {
        "slug": "accept_terms",
    }
}
```

### Step 4: \[optional] Provide Underwriting decisioning

The is optional step allows you to provide external data for decisioning for consumer underwriting.

POST `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}/perform-underwriting`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{
  "result": "pass|fail",
  "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2}"
}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": null,
        "agreement_accepted_date": null
    },
    "product": {
        "product_id": null
    },
    "underwriting": {
      "result": "pass",
      "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2\}"
    },
    "previous_step": {
        "slug": "get_started",
    },
    "current_step": {
        "slug": "accept_terms",
    }
}
```

### Step 5: Accept Terms

Once a user has accepted the terms of their loan + card agreements, you can update their onboarding workflow to reflect the date/time that the agreements were accepted.

POST `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}/accept-terms/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{
  "agreement_accepted": true,
  "agreement_accepted_date": "2025-05-11T14:47:56.152870Z"
}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": true,
		    "agreement_accepted_date": "2025-05-11T14:47:56.152870Z"
    },
    "product": {
        "product_id": "95630f7a-dc51-4c61-914b-14c26b99968c"
    },
    "underwriting": {
      "result": "pass",
      "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2\}"
    },
    "previous_step": {
        "slug": "get_started",
    },
    "current_step": {
        "slug": "accept_terms",
    }
}
```

### Step 6: Submit Loan

Once a user has accepted the terms of their loan + card agreements, you are ready to submit their loan data. This step will also begin to provision their cards and any associated loans and bank accounts

**After onboarding completion**

* The consumer bank account and card may not be open at this point while we are completing the onboarding with the bank. Once the accounts and card are provisioned you will receive a webhook message called PaymentCard.Created
* If a user doesn’t order a physical to start they can order under card management. A partner can order on behalf of a user by calling the card.order API

> **Info**
>
> This step begins card provisioning. If you are setting the consumer’s autopay
> election through onboarding metadata, send it **before** this call — see
> *“Managing Metadata on the Onboarding Object”* below.

POST `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}/submit-loan/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": true,
		    "agreement_accepted_date": "2025-05-11T14:47:56.152870Z"
    },
    "product": {
        "product_id": "95630f7a-dc51-4c61-914b-14c26b99968c"
    },
    "underwriting": {
      "result": "pass",
      "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2\}"
    },
    "previous_steps": [
        {
            "slug": "perform_underwriting"
        },
        {
            "slug": "select_product"
        },
        {
            "slug": "accept_terms"
        },
        {
            "slug": "verify_identity"
        },
        {
            "slug": "get_started"
        }
    ],
    "current_steps": null
}
```

### Managing Metadata on the Onboarding Object

You can add/update metadata on the onboarding object as a set of key/value pairs.

**Example: Adding Metadata**

POST `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}/metadata/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{
  "metadata": {
    "key_1": "value_1",
    "key_2": "value_2",
    "key_3": "value_3"
  }
}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": true,
		    "agreement_accepted_date": "2025-05-11T14:47:56.152870Z"
    },
    "product": {
        "product_id": "95630f7a-dc51-4c61-914b-14c26b99968c"
    },
    "underwriting": {
      "result": "pass",
      "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2\}"
    },
    "metadata": {
	    "key_1": "value_1",
	    "key_2": "value_2",
	    "key_3": "value_3",
    },
    "previous_step": {
        "slug": "get_started",
    },
    "current_step": {
        "slug": "accept_terms",
    }
}
```

**Example: Updating Metadata**

PUT `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}/metadata/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{
  "metadata": {
    "key_1": "new_value",
    "key_4": "value_4"
  }
}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": true,
		    "agreement_accepted_date": "2025-05-11T14:47:56.152870Z"
    },
    "product": {
        "product_id": "95630f7a-dc51-4c61-914b-14c26b99968c"
    },
    "underwriting": {
      "result": "pass",
      "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2\}"
    },
    "metadata": {
	    "key_1": "new_value",
	    "key_2": "value_2",
	    "key_3": "value_3",
	    "key_4": "value_4",
    },
    "previous_step": {
        "slug": "get_started",
    },
    "current_step": {
        "slug": "accept_terms",
    }
}
```

#### Reserved Key: `autopay_enabled`

Most metadata keys are free-form — we store them and hand them back untouched. `autopay_enabled` is the exception. It is a **reserved key** that sets whether the consumer’s card automatically pays down its outstanding balance on the nightly payoff cycle.

| Property    | Value                                                                   |
| ----------- | ----------------------------------------------------------------------- |
| **Key**     | `autopay_enabled`                                                       |
| **Type**    | Boolean — `true` or `false`                                             |
| **Default** | `true` — autopay is on unless you turn it off                           |
| **Send it** | After the product has been selected, and before **Step 6: Submit Loan** |

The value must be a JSON boolean. A quoted string such as `"false"` is stored as an ordinary metadata value and **will not** change the autopay setting. The key itself is matched case-insensitively, so an integration already sending a different casing keeps working.

> **Info**
>
> Autopay must be **off** for a consumer if you intend to pay the card down
> yourself through the repayments API — see the
> [Card Repayments guide](/guides/card-repayments). Setting
> `autopay_enabled: false` during onboarding is how an API-first partner opts in
> to that model from day one.

**Example: Setting the autopay election**

POST `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}/metadata/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{
  "metadata": {
    "autopay_enabled": false
  }
}
```

You can send it alongside your own keys in the same call:

```json
{
  "metadata": {
    "autopay_enabled": false,
    "referral_code": "UPWARD2024",
    "source": "mobile_app"
  }
}
```

The response is the full onboarding object, with the key echoed back in `metadata`.

> **Info**
>
> **Timing.** The election is recorded against the consumer’s loan application, which is created when the product is selected. If you have a single card product configured, that happens automatically once **Step 1: Get Started** completes. If you have more than one, it happens when you call **Step 3: Provide product decision details**. Sending `autopay_enabled` before the product is selected returns `200` but records nothing — so send it at or after Step 3 and before Step 6.

> **Info**
>
> **Send it before the card is provisioned.** Card provisioning begins at **Step 6: Submit Loan**. Once the consumer’s card is active, the metadata endpoint stops accepting the election and returns `409`. From that point on, use `PUT /v2/payment-cards/{payment_card_id}/autopay` instead.

**Response once the card is already active**

`409 Conflict`

```json
{
    "detail": "Autopay can no longer be set via onboarding metadata once the payment card is active. Use PUT /v2/payment-cards/6a822b8a-0423-4ae7-bad6-02e09adab632/autopay instead."
}
```

The `detail` message carries the consumer’s `payment_card_id`, so you can retry against the card endpoint directly.

> **Info**
>
> **TIP:** The `metadata` object on the onboarding response echoes the value you sent — it is not a live read of the card’s autopay setting. After the card is provisioned, read `autopay_enabled` from the payment card record for the current state.

### Getting Information on an In-Progress Onboarding

Once a user has accepted the terms of their loan + card agreements, you are ready to submit their loan data. This step will also begin to provision their cards and any associated loans and bank accounts

**After onboarding completion**

* The consumer bank account and card may not be open at this point while we are completing the onboarding with the bank. Once the accounts and card are provisioned you will receive a webhook message called PaymentCard.Created
* If a user doesn’t order a physical to start they can order under card management. A partner can order on behalf of a user by calling the card.order API

POST `https://api-sandbox.upwardli.com/v2/onboarding/{onboarding_id}`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Body

```json
{}
```

Response

```json
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
		    "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
		    "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
		    "first_name": "John",
		    "last_name": "Doe",
		    "email": "john.doe@email.com",
		    "is_active": true,
		    "kyc_status": "Complete",
		    "phone_number": "425-555-1212",
		    "date_of_birth": "1999-10-06",
		    "tax_id_type": "SSN",
		    "tax_identifier": "***-**-6789",
		    "address_line1": "121 Big Creek",
		    "address_line2": null,
		    "address_city": "Tuscaloosa",
		    "address_state": "AL",
		    "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": true,
		    "agreement_accepted_date": "2025-05-11T14:47:56.152870Z"
    },
    "product": {
        "product_id": "95630f7a-dc51-4c61-914b-14c26b99968c"
    },
    "underwriting": {
      "result": "pass",
      "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2\}"
    },
    "previous_steps": [
        {
            "slug": "perform_underwriting"
        },
        {
            "slug": "select_product"
        },
        {
            "slug": "accept_terms"
        },
        {
            "slug": "verify_identity"
        },
        {
            "slug": "get_started"
        }
    ],
    "current_steps": null
}
```

### Working with the Persona Control

This section describes best practices for integrating the Persona embedded controls within your existing onboarding flow.

> **Info**
>
> You can pre-fill data for your consumer to reduce onboarding friction. If you
> want to pre-fill data for your consumer see the section entitled: *“KYC Data
> Pre-Fill”* below.

![KYC Details](/_fern-img/c75aaed43ce053a50e50a0d06c2f14eb021928ba28429808769975aa5e9bcf1b.webp)

**Consumer Completes the KYC step(s)**

Once the user has successfully completed KYC, then we will send a further webhook with an event\_name of consumer.updated

```json
{
  "id": "ea04f0a8-b005-47cd-ba33-b02a00c0c426",
  "created_at": "2023-06-23T07:41:50.45-04:00",
  "event_name": "consumer.updated",
  "partner_id": "2f221c90-b82d-4e12-9bfd-ae8301097de3",
  "resources": ["https://api-sandbox.upwardli.com/v2/consumers/{consumer_id}"],
  "last_attempted_at": "2023-06-23T07:41:50.45-04:00"
}
```

When you retrieve the updated consumer record related to this webhook, you will see that the kyc\_status value has changed to `"kyc_status": "Complete"`, indicating that this consumer has successfully completed the KYC step. In some cases, we will need to complete a manual review of the information provided by the consumer.

This webhook will also allow you to see the KYC information that was provided by the consumer when completing this step. We do not provided the full tax\_identifier.

> **Info**
>
> NOTE: KYC completed does not mean the consumer has completed onboarding or
> that a card product has been provisioned.

```json
{
  "id": "{consumer_id}",
  "pcid": "{pcid}",
  "first_name": "John",
  "last_name": "Doe",
  "email": "john.doe@gmail.com",
  "is_active": true,
  "kyc_status": "Complete",
  "phone_number": "+12065559034",
  "date_of_birth": "2000-01-01",
  "tax_id_type": "SSN",
  "tax_identifier": "***-**-1234",
  "address_line1": "100 Main Street",
  "address_line2": null,
  "address_city": "Tuscaloosa",
  "address_state": "AL",
  "address_zip": "354050000"
}
```

> **Info**
>
> **TIP:** If you do not receive the webhook you can call the Consumer endpoint to retrieve the consumer details.
>
> GET [https://api-sandbox.upwardli.com/v2/consumer/\{id}](https://api-sandbox.upwardli.com/v2/consumer/\{id})

**Optional: KYC Data Pre-Fill**

Before loading the embedded component, you can pre populate data for a consumer by calling the api: POST: [https://api-sandbox.upwardli.com/v2/consumer/](https://api-sandbox.upwardli.com/v2/consumer/) and providing the following fields:

![Pre-filled KYC](/_fern-img/b3de44997b47d6e1f85f74cc9c8687e6334858e1da373d93d6dfa351a5a6cffc.webp)

**Edge Cases / Unhappy path:**

1. If a user does not complete KYC, then you will only receive the consumer.created message
2. If a user fails KYC, then we will send a consumer.updated webhook, with a kyc\_status value of Failed. We will not open a credit line for any users who do not pass KYC.

### Example of a Complete Onboarding Object

```javascript
{
    "id": "6a822b8a-0423-4ae7-bad6-02e09adab632",
    "consumer": {
        "id": "bce4e19c-69fe-4af0-8ff7-6652f7265018",
        "pcid": "8d397680-deb1-44fe-a6fa-7454e8843fb7",
        "first_name": "John",
        "last_name": "Doe",
        "email": "john.doe@mailinator.com",
        "is_active": true,
        "kyc_status": "Complete",
        "phone_number": "425-555-1212",
        "date_of_birth": "1999-10-06",
        "tax_id_type": "SSN",
        "tax_identifier": "***-**-8455",
        "address_line1": "121 Big Creek",
        "address_line2": null,
        "address_city": "Tuscaloosa",
        "address_state": "AL",
        "address_zip": "354050000"
    },
    "kyc": {
        "inquiry_template_id": null
        "inquiry_ids": [
            "inq_be55e136-2ca9-4f20-b262-4a1004f27e2e",
            "inq_bd77c402-b95b-4d58-8104-9652a25bc1e9"
        ]
    },
    "e_sign": {
        "agreement_accepted": null,
        "agreement_accepted_date": null
    },
    "product": {
        "product_id": "95630f7a-dc51-4c61-914b-14c26b99968c"
    },
    "underwriting": {
      "result": "pass",
      "data": "{\"key_1\":\"value_1\",\"key_2\":\"value_2\}"
    },
    "previous_step": {
        "slug": "get_started",
    },
    "current_step": {
        "slug": "accept_terms",
    }
}
```

# Post Onboarding API Interactions

Once a consumer is onboarded you have two option to display consumer account and card details.

1. **Embedded widget** - we display the UI for you in our hosted components, you have control over the look and feel but not the layout.
2. **API** - you query our platform for the raw data and have full control of how you display it in your own UI (beyond what is listed in the box below)

> **Info**
>
> For PCI reasons you will also need to use our embedded widget for Card Display
> and Card Management such as PIN reset, Freeze / Unfreeze, and Lost / Stolen
> options.

## Card Management

The card management widget is intended to give consumers the ability to view their card, update actions tied to their card (transaction history, PIN set, ATM locator, freeze a card). A consumer will also be able to view their credit score, see statements, make payments and initiate transfers.

## **Card Management via API**

When using our API method post onboarding you will be able to pull specific information regarding card details, transfers, credit insights and other actions directly into your app or website. The only two areas where you will need to use our standalone embedded widgets are (1) card image and (2) card details (i.e PIN set, freeze card, etc).

**Authentication**

You will need to authenticate to get access to the APIs you will use the URL below and the a **Partner API Token** with the applicable API url.

**Important Parameters**

| Parameter     | Value             | Notes                                                                                               |
| ------------- | ----------------- | --------------------------------------------------------------------------------------------------- |
| access\*token | Partner API token |                                                                                                     |
| redirect\_url | URL               | \*(optional)\_ The URL to redirect the web component to once the consumer has completed onboarding. |
| api\_url      | URL               | See API table below                                                                                 |

### **Card Image**

This entry spot will provide a PCI compliant way to display the card image and transaction details for the user. A user will be able to add their card details to their Apple or Google mobile wallet manually. In-app push provisioning will be available in 2H 2025.

> **Info**
>
> [https://component-embedded-sandbox.upwardli.com/card-image?access\_token=\{userscopetoken}](https://component-embedded-sandbox.upwardli.com/card-image?access_token=\{userscopetoken})

![Card Image](/_fern-img/01a375f5beece6f92f76a9187ae04a5a42a3653a089850912844f1cfbb5487c2.webp)

## **Related API Table**

Below is a list of the API calls used to populate the **Card Management** embedded component.

| API             | URL                                                                                                                                                                        |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Payment Card    | [https://api-sandbox.upwardli.com/v2/consumers/\{consumer\_id}/payment-cards/](https://api-sandbox.upwardli.com/v2/consumers/\{consumer_id}/payment-cards/)                |
| Accounts        | [https://api-sandbox.upwardli.com/v2/consumers/\{consumer\_id}/accounts/](https://api-sandbox.upwardli.com/v2/consumers/\{consumer_id}/accounts/)                          |
| Credit Insights | [https://api-sandbox.upwardli.com/v2/credit-insights/\{consumer\_id}/summary/](https://api-sandbox.upwardli.com/v2/credit-insights/\{consumer_id}/summary/)                |
| Transactions    | [https://api-sandbox.upwardli.com/v2/payment-cards/\{payment\_card\_id}/transactions/](https://api-sandbox.upwardli.com/v2/payment-cards/\{payment_card_id}/transactions/) |
| ACH Payments    | [https://api-sandbox.upwardli.com/v2/payments/ach/](https://api-sandbox.upwardli.com/v2/payments/ach/)                                                                     |
| ATM Locator     | [https://www.allpointnetwork.com/locator](https://www.allpointnetwork.com/locator)                                                                                         |

### **Example: Payment Card**

GET `https://api-sandbox.upwardli.com/v2/consumers/{consumer_id}/payment-cards/`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Response

```javascript
{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": "4a2472ea-75d9-4448-a4f4-e081a324e176",
            "consumer_id": "00000000-0000-0000-0000-000000000003",
            "status": "active",
            "emboss_hold": true,
            "available_balance": 197.02,
            "account_number": "1234567890",
            "routing_number": "021214891",
            "created_at": "2025-02-05T22:57:31.749142Z"
        }
    ]
}
```

## Partner + Product Endpoint

### Get Partner Details

GET `https://api-sandbox.upwardli.com/v2/partners/`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Response

```json
{
  "partner_id": "98ecf2e2-3cb8-4101-8532-9dbcdd87d0f9",
  "name": "Grow",
  "customer_service_number": null,
  "customer_service_email": null,
  "default_consumer_locale": "en_US"
}
```

### Get Partner Product Details

GET `https://api-sandbox.upwardli.com/v2/partners/{partner_id}/products`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Response

```json
{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "faaf9d7f-2fb3-4559-8741-f3700f52a76c",
      "key": "SecuredCardGrow1",
      "product_type": "subscription",
      "description": "Grow Option 1"
    },
    {
      "id": "e7c3dcdc-5e99-45b6-9437-26a31154aa0e",
      "key": "SecuredCardGrow2",
      "product_type": "subscription",
      "description": "Grow Option 2"
    }
  ]
}
```

### **Example: Accounts**

GET `https://api-sandbox.upwardli.com/v2/consumers/{consumer_id}/accounts/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Response

```json
{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "083959d1-8282-4512-a52e-5630a5af042f",
      "consumer_id": "00000000-0000-0000-0000-000000000003",
      "bank_name": "Upward Financial Inc",
      "balance": 0,
      "account_name": "Upward Credit Builder",
      "account_number": "******7890",
      "account_type": "Secured Card",
      "account_routing_number": "*****4891",
      "is_primary": false
    },
    {
      "id": "bbd3005f-b6b0-40fe-975e-34bae4b20a5c",
      "consumer_id": "00000000-0000-0000-0000-000000000003",
      "bank_name": ".",
      "balance": 0,
      "account_name": "Account Name",
      "account_number": "******6789",
      "account_type": "checking",
      "account_routing_number": "*****6789",
      "is_primary": true
    }
  ]
}
```

### **Example: Credit Insights**

GET `https://api-sandbox.upwardli.com/v2/credit-insights/{consumer_id}/summary/`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Response

```javascript
{
    "credit_score_card": {
        "score": 655,
        "change": 28,
        "credit_usage": 14,
        "total_tradelines": 3,
        "payment_history": 2,
        "credit_inquiries": 1,
        "credit_age": 35,
        "debt_collection_count": 1,
        "report_date": "2025-01-06",
        "late_payment_percentage": 0,
        "total_public_records": 0,
        "total_open_revolving_accounts": 0,
        "total_open_collection_accounts": 0,
        "total_bankruptcies": 0,
        "credit_report_status": "NotOrdered"
    },
    "credit_score_history": [
        {
            "month": "2025-01",
            "score": 655
        },
        {
            "month": "2024-12",
            "score": 627
        },
        {
            "month": "2024-11",
            "score": 601
        },
        {
            "month": "2024-10",
            "score": 587
        },
        {
            "month": "2024-09",
            "score": 688
        }
    ]
}
```

POST [https://api-sandbox.upwardli.com/v2/accounts/](https://api-sandbox.upwardli.com/v2/accounts/)

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
	"account_name": "Account Name"
	"account_number": "0123456789"
	"bank_name": " . "
	"consumer_id": "00000000-0000-0000-0000-000000000003"
	"routing_number": "123456789"
}
```

Response

```json
{
    "message": "Bank account created successfully",
    "data": {
        "id": "0f845102-f717-4bb9-a96a-c167a36148d6",
        "consumer_id": "00000000-0000-0000-0000-000000000003",
        "bank_name": ".",
        "balance": 0,
        "account_name": "Account Name",
        "account_number": "******6789",
        "account_type": "checking",
        "account_routing_number": "*****6789",
        "is_primary": true
        "is_active": true
    }
}
```

## Transactions

```json
{
  "mcc": "{mcc_code}",
  "merchant_id": "{merchant_id}",
  "amount": "{trans_amount}",
  "consumer_id": "{consumer.external_id}",
  "auth_remarks": [
    {
      "code": "{response_code}",
      "code_objects": "{response_code_objects}",
      "description": "{response_code_description}"
    }
  ]
}
```

### Real-Time Transaction Handling

If you sign up to participate in the real-time authorization, we will sent purchase request data to a pre-defined endpoint on your system via HTTP POST. You will have 600ms to respond to this request, otherwise we will automatically decline the transaction.

Sample HTTP Headers:

```json
{
  "content-type": "application/json",
  "upwardli-signature": "{HMAC Signature}"
}
```

Sample Message Body:

```json
{
  "amount": "50.00",
  "consumer_id": "{guid}",
  "mcc": 1811,
  "merchant_id": "HBLr4RErBXkzrYU",
  "merchant_name": "COMPANY NAME",
  "payment_card_id": "{Guid}",
  "payment_reference_number": "9876543210",
  "auth_remarks": [
    {
      "code": "51",
      "code_objects": {
        "51": ["Non-sufficient funds and not a force post"]
      },
      "description": "Insufficient funds (NSF). The authorization amount is larger than the cardholder's available balance. Mastercard only."
    }
  ]
}
```

In order to approve the purchase, you must reply with the following response:

```json
{
  "response_code": "00"
}
```

Here are the most common Response codes

* `00` — Success
* `10` — Approved for partial amount
* `51` — Insufficient funds
* `59` — Suspected fraud
* `63` — Suspected fraud (Mastercard only)

For a list of all possible response codes, you can view [this page](https://docs.galileo-ft.com/pro/page/authorization-response-codes).

### **Example: Get Transaction History**

GET `https://api-sandbox.upwardli.com/v2/payment-cards/{payment_card_id}/transactions/`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Response

```json
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "3a8ee16d-a561-4265-886b-186c10e409f2",
      "status": "posted",
      "amount": "57.57",
      "posted_at": "2025-02-03 23:13:38",
      "effective_at": "2025-02-03 23:13:38",
      "description": "Test Client Transaction: 0",
      "direction": "credit"
    }
  ]
}
```

### **Example: Create ACH**

POST`https://api-sandbox.upwardli.com/v2/payments/ach/`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
	"amount": 6
	"consumer_id": "Consumer_id"
	"originating_account_id": "Account_id"
	"receiving_account_id": "Account_id"
	"description": "ACH originating_account_id to receiving_account_id"
}
```

### **Example: Fund Card**

Note: `payment_card_id` is not bank account id

POST [`https://api-sandbox.upwardli.com/v2/simulations/payment-cards/{{payment_card_id}}/create-simulated-fund-card`](https://api-sandbox.upwardli.com/v2/simulations/payment-cards/%7B%7Bpayment_card_id%7D%7D/create-simulated-fund-card)

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
```

## Sandbox Activity Simulation Endpoints

### **Example: Simulate Card Auth**

POST [`https://api-sandbox.upwardli.com/v2/simulations/payment-cards/{{payment_card_id}}/create-simulated-card-auth`](https://api-sandbox.upwardli.com/v2/simulations/payment-cards/%7B%7Bpayment_card_id%7D%7D/create-simulated-card-auth)

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
    "amount": 10.00,
    "association": "visa",
    "merchant_name": "UPW"
}
```

### **Example: Simulate Card Settlement**

POST [`https://api-sandbox.upwardli.com/v2/simulations/payment-cards/{{payment_card_id}}/create-simulated-card-settlement`](https://api-sandbox.upwardli.com/v2/simulations/payment-cards/%7B%7Bpayment_card_id%7D%7D/create-simulated-card-settlement)

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
    "auth_id": "<auth_id_from_above>",
    "settle_amount": 10.00
}
```

## **Card Actions**

### **Freeze**

Note: `payment_card_id` is not bank account id

POST `https://api-sandbox.upwardli.com/v2/payment-cards/{payment_card_id}/freeze`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
    "end_date": "input_formats=["%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M:%S.%fZ"]",
}
```

### **Unfreeze**

Note: `payment_card_id` is not bank account id

POST `https://api-sandbox.upwardli.com/v2/payment-cards/{payment_card_id}/unfreeze`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
```

### Lost or Stolen

Note: `payment_card_id` is not bank account id

POST `https://api-sandbox.upwardli.com/v2/payment-cards/{payment_card_id}/replace-lost-stolen/`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
		"card_status": "L|S"
}
```

### Replace Card

POST `https://api-sandbox.upwardli.com/v2/payment-cards/{payment_card_id}/reissue/`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
```

# Credit Goals

## Credit Goals via API

### **Example: Credit Insights**

GET `https://api-sandbox.upwardli.com/v2/credit-insights/{consumer_id}/summary/`

```javascript
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Response

```javascript
{
    "credit_score_card": {
        "score": 655,
        "change": 28,
        "credit_usage": 14,
        "total_tradelines": 3,
        "payment_history": 2,
        "credit_inquiries": 1,
        "credit_age": 35,
        "debt_collection_count": 1,
        "report_date": "2025-01-06",
        "late_payment_percentage": 0,
        "total_public_records": 0,
        "total_open_revolving_accounts": 0,
        "total_open_collection_accounts": 0,
        "total_bankruptcies": 0,
        "credit_report_status": "NotOrdered"
    },
    "credit_score_history": [
        {
            "month": "2025-01",
            "score": 655
        },
        {
            "month": "2024-12",
            "score": 627
        },
        {
            "month": "2024-11",
            "score": 601
        },
        {
            "month": "2024-10",
            "score": 587
        },
        {
            "month": "2024-09",
            "score": 688
        }
    ]
}
```

# Profile

**Important Parameters**

| Parameter     | Value                 | Notes                                                                                           |
| ------------- | --------------------- | ----------------------------------------------------------------------------------------------- |
| access\_token | Customer Access Token | A token that when used with the scope `api:card-management:read`                                |
| url           | URL                   | `https://component-embedded-sandbox.upwardli.com/consumer-profile/?access_token={access_token}` |

## Profile via API

### **Example: Statements**

GET `https://api-sandbox.upwardli.com/v2/consumers/{consumer_id}/statements`

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

`https://api-sandbox.upwardli.com/v2/consumers/{consumer_id}/statements/{pdf_filename}/download`

# General API information

If you are utilizing the API approach you will also want to access other APIs for requesting specific information about Upward resources

| Resource                 | URL                                              | Notes                                                                                              |
| ------------------------ | ------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| Consumer - Profile       | /v2/consumers/                                   |                                                                                                    |
| Consumer - Statement     | /v2/consumers/\{consumer\_id}/statements         |                                                                                                    |
| Consumer - Close         | /v2/payment-cards/\{payment\_card\_id}/close/    |                                                                                                    |
| Payments - Book Transfer | /v2/payments/transfer                            |                                                                                                    |
| Card - Repayments        | /v2/payment-cards/\{payment\_card\_id}/payments/ | Pay down the card's outstanding balance. See the [Card Repayments guide](/guides/card-repayments). |

Embedded Component Endpoints

**The Credit Builder Card API provides access to several different types of detail.**

**You decide which of the experiences you want to include:**

| Experiences                 | URL / Endpoint(s)                                                                                                                                                                                                                                                                          | Description                                                          |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| Onboarding                  | [https://component-embedded-sandbox.upwardli.com/en/onboarding/card-product/?pcid=\{\$partner\_consumer\_id}\&access\_token=\{\$access\_token}](https://component-embedded-sandbox.upwardli.com/en/onboarding/card-product/?pcid=\{\$partner_consumer_id}\&access_token=\{\$access_token}) | End to End Onboarding                                                |
| Onboarding initial transfer | [https://component-embedded-sandbox.upwardli.com/en/onboarding/transfer/?access\_token=\{userscopetoken}](https://component-embedded-sandbox.upwardli.com/en/onboarding/transfer/?access_token=\{userscopetoken})                                                                          | Initial ACH to fund the account                                      |
| Card Management             | [https://component-embedded-sandbox.upwardli.com/card-management?access\_token=\{userscopetoken}](https://component-embedded-sandbox.upwardli.com/card-management?access_token=\{userscopetoken})                                                                                          | Home Card Details Transactions Card Management Add External Accounts |
| Payments                    | Coming soon - available through card management or via API only. No stand alone option for external transfers is available today                                                                                                                                                           | Transfer Funds                                                       |
| Credit Goals                | [https://component-embedded-sandbox.upwardli.com/en/credit-goals/?access\_token=\{userscopetoken}](https://component-embedded-sandbox.upwardli.com/en/credit-goals/?access_token=\{userscopetoken})                                                                                        | Credit Insights Credit Guides                                        |
| Profile                     | [https://component-embedded-sandbox.upwardli.com/consumer-profile/?access\_token=\{userscopetoken}](https://component-embedded-sandbox.upwardli.com/consumer-profile/?access_token=\{userscopetoken})                                                                                      | Full Profile *(excludes Statements and Payment Settings)*            |
| Card image                  | [https://component-embedded-sandbox.upwardli.com/card-image?access\_token=\{userscopetoken}](https://component-embedded-sandbox.upwardli.com/card-image?access_token=\{userscopetoken})                                                                                                    | Virtual card image                                                   |
| Card actions                | [https://component-embedded-sandbox.upwardli.com/card-actions?access\_token=\{userscopetoken}](https://component-embedded-sandbox.upwardli.com/card-actions?access_token=\{userscopetoken})                                                                                                | Display Card actions                                                 |
| Pin reset                   | `https://component-embedded-sandbox.upwardli.com/card-pin-reset?access_token={userscopetoken}`                                                                                                                                                                                             | Display to set/update a card pin                                     |

# **Using the Upward Webhooks**

By design we do not include extensive information about the webhook data sources. To learn more about the object referenced by the webhook, you can use the url\[s] in the webhook body to make api requests.

## **Available Webhooks**

| Resource                  | Events                                                                                                                                                                                                                      | URL                                                                              |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Consumers                 | Consumer.Created, Consumer.Updated, Consumer.Closed, Consumer.KYC.Started, Consumer.KYC.Pending, Consumer.KYC.Completed, Consumer.KYC.NeedsReview (`consumer.kyc.needs_review`), Consumer.KYC.Approved, Consumer.KYC.Failed | `v2/consumer/{consumer_id}`                                                      |
| Payment Cards             | PaymentCard.Created, PaymentCard.Updated, PaymentCard.Closed, PaymentCard.Frozen, PaymentCard.Unfrozen, PaymentCard.Replaced, PaymentCard.Lost, PaymentCard.Stolen                                                          | `v2/payment-cards/{payment_card_external_id}`                                    |
| Payment Card Transactions | PaymentCard.Transaction.Auth, PaymentCard.Transaction.AuthExpired, PaymentCard.Transaction.Archived, PaymentCard.Transaction.Settlement                                                                                     | `v2/payment-cards/{self.payment_card_external_id}/transactions/{transaction_id}` |
| ACH Payments              | Payment.Ach.Created, Payment.Ach.Sent, Payment.Ach.Completed, Payment.Ach.Failed, Payment.Ach.Received                                                                                                                      | `v2/payments/ach/{ach_external_id}`                                              |
| Transfer Payments         | Payment.Transfer.Created, Payment.Transfer.Completed, Payment.Transfer.Failed                                                                                                                                               | `v2/payments/transfer/{payment_transfer_external_id}/`                           |
| Instant Payments          | Payment.Instant.Created, Payment.Instant.Sent, Payment.Instant.Failed                                                                                                                                                       | `/v2/payments/instant/{instant_payment_id}/`                                     |
| Dispute                   | Consumer.Dispute.Created                                                                                                                                                                                                    | `v2/disputes/{dispute_id}`                                                       |
| Statement                 | Consumer.Statement.Created                                                                                                                                                                                                  | `v2/statements/{file_name}`                                                      |
| BankAccount               | Consumer.BankAccount.Created (`consumer.bank_account.created`), Consumer.BankAccount.Deleted (`consumer.bank_account.deleted`), Consumer.BankAccount.VerificationFailed (`consumer.bank_account.verification_failed`)       | `v2/accounts/{bank_account_external_id}`                                         |

## Webhook Message Description

All Upward webhook messages use the same format. To learn more about the resource(s) that are referenced by a specific webhook message, you can make an API request to the url(s) inside of the `resources` property.

```json
{
  "id": "{Unique Webhook Id}",
  "created_at": "Datetime: YYYY-MM-DDTHH:MM:SS.SS-TZ",
  "event_name": "Webhook Message",
  "partner_id": "{Your unique Partner Id}",
  "resources": [
    "https://{environment}.upwardli.com/v2/{resource}/{resource_id}"
  ],
  "last_attempted_at": "Datetime: YYYY-MM-DDTHH:MM:SS.SS-TZ"
}
```

## **Webhook Authentication**

Upward’s webhooks are secured using a Hashed Message Authentication Code (HMAC) in the webhook message header. The name of this header value is `Upwardli-Signature`. The Upwardli-Signature header contains two comma-separated key-value pairs encoding information about the request.

The first key-value pair will be in the form `t=<unix_timestamp>` and represents the unix time that the request was sent. The second key-value pair will be in the form `v1=WeNeedSomethingHere`, where the signature is a sha256 hash computed from the consumers webhook secret and a dot-separated string composed of the unix timestamp joined with the request body.

Note: computing the signature is sensitive to the exact characters input into the algortihm. The request data should be a json string with no whitespace formatting.

### **Sample Data**

```json
`client_id => 'public'`

`signature => 't=2023-10-12T20:44:58.082694+00:00,v1=263a5f79d899f7d5e04eb9a902b173d5901a9088966b932edca7174aec3d9e12'`

`message => '{"id":"954935cb-be33-47a4-99af-ec8bbc662ec7","createdAt":"2023-10-05T17:39:21.097794+00:00","eventName":"consumer_created","partnerId":"cb739356-5f69-429c-8157-756876d08d27","resources":["api/v2/consumers/00000000-0000-0000-0000-000000000000"],"lastAttemptedAt":"2023-10-05T17:39:21.097794+00:00"}'`
```

Example decode in Python

```javascript
1t, v1 = [value.split('=')[1] for value in request.headers['Upwardli-Signature'].split(',')]2computed_digest = hmac.new(<YOUR_CLIENT_ID>.encode(), (t + '.' + request.data.decode('utf-8')).encode(), 'sha256').hexdigest()34if hmac.compare_digest(v1, computed_digest):5    # Process webhook
```

## **Registering for Webhook Messages**

POST `https://api-sandbox.upwardli.com/v2/webhooks/registrations/`

**Header**

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Example Request Body

```json
{
  "webhook_name": "{webhook_name}",
  "endpoint": "{endpoint to receive messages at}"
}
```

### Get All Webhook Registrations

GET `https://api-sandbox.upwardli.com/v2/webhooks/registrations/`

**Header**

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

Example Response

```json
{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": "{webhook_registration_id}",
            "partner_id": "{partner_id}",
            "webhook_name": "consumer.created",
            "endpoint": "{webhook_endpoint}",
            "status": "active",
            "failures": 0,
            "last_failure": null
        },
        {
            "id": "{webhook_registration_id}",
            "partner_id": "{partner_id}",
            "webhook_name": "consumer.updated",
            "endpoint": "{webhook_endpoint}",
            "status": "active",
            "failures": 0,
            "last_failure": null
        }
}
```

# Sandbox Testing and Activity Simulation

### **Example: Fund Card**

Note: `payment_card_id` is not back account id

POST [`https://api-sandbox.upwardli.com/v2/simulations/payment-cards/{{payment_card_id}}/create-simulated-fund-card`](https://api-sandbox.upwardli.com/v2/simulations/payment-cards/%7B%7Bpayment_card_id%7D%7D/create-simulated-fund-card)

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
```

### **Example: Simulate Card Auth**

Note: `payment_card_id` is not back account id

POST [`https://api-sandbox.upwardli.com/v2/simulations/payment-cards/{{payment_card_id}}/create-simulated-card-auth`](https://api-sandbox.upwardli.com/v2/simulations/payment-cards/%7B%7Bpayment_card_id%7D%7D/create-simulated-card-auth)

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
    "amount": 10.00,
    "association": "visa",
    "merchant_name": "Testing Transactions" length needs to greater than 5
}
```

### **Example: Simulate Card Settlement**

Note: `payment_card_id` is not bank account id

POST [`https://api-sandbox.upwardli.com/v2/simulations/payment-cards/{{payment_card_id}}/create-simulated-card-settlement`](https://api-sandbox.upwardli.com/v2/simulations/payment-cards/%7B%7Bpayment_card_id%7D%7D/create-simulated-card-settlement)

```json
Header
{
    "Authorization":"Bearer [access_token]"
}
Body
{
    "auth_id": "<auth_id_from_above_response>",
    "settle_amount": 10.00
}
```

Change Log

| Version  | Description of Changes and Updates |
| -------- | ---------------------------------- |
| v5.12.25 | Initial Document Creation          |