> 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 as a Service API-First Documentation

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

# 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.

### 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)

## 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"
}
```

## **API Onboarding Flow Specifics**

1. Create Consumer
2. Create Onboarding
3. Verify the Consumer’s Identity (KYC)
4. Provide Underwriting decision
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: Create Consumer

Partners must create a consumer via the [Create Consumer](/api-access/api-reference/consumers/create-new-consumer) API before creating the onboarding.

### Step 2: Create Onboarding

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 `cbaas_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": "cbaas_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 3: 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 4: Provide Underwriting Decision

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

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

Body

```json
{
  "result": "pass|fail",
  "data": "{}"
}
```

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 + CBAAS 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
}
```

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 + CBAAS agreements, you are ready to submit their loan data. This step will also begin to provision their credit line.

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

```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": 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. Keys you define are stored and returned untouched; `autopay_enabled` is reserved and described below.

**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"
        ]
    },
    "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**

A `PUT` merges the keys you send into the existing metadata. Keys you leave out are kept as they are.

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"
  }
}
```

The response is the full onboarding object, with `metadata` now containing `key_1` through `key_4`.

#### Reserved Key: `autopay_enabled`

`autopay_enabled` is a **reserved key**. It sets whether the consumer’s credit builder loan automatically pays its scheduled payment each cycle.

| Property    | Value                                         |
| ----------- | --------------------------------------------- |
| **Key**     | `autopay_enabled`                             |
| **Type**    | Boolean — `true` or `false`                   |
| **Default** | `true` — autopay is on unless you turn it off |
| **Send it** | 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.

**Example: Setting the autopay election**

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

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"
  }
}
```

> **Info**
>
> **Send it before Step 6: Submit Loan.** Submitting the loan begins provisioning the consumer’s credit line, and the election is read as part of that. Set it at any point in the flow before that call.

> **Info**
>
> **TIP:** The `metadata` object on the onboarding response echoes the value you sent — it is not a live read of the loan’s autopay setting.