Skip to navigation

CBaaS Tier Upgrades and Downgrades

Overview

Once a Credit Builder as a Service (CBaaS) consumer’s credit line is open, you can move them to a higher or lower tier by changing their credit limit with POST /v2/credit-lines/{credit_line_id}/.

The consumer starts with the credit limit set when their loan is submitted at Step 6: Submit Loan. This page covers changing that limit afterwards.

Tier upgrades and downgrades are enabled per program. Contact your Upward representative to turn them on and to agree on your tier ranges and cooldown period. Until then, this endpoint returns 403 Forbidden.

Lifecycle at a Glance

StageWhat you doAPI
Step 6: Submit LoanUpward opens the credit line with the consumer’s starting limitSubmit Loan
After the credit line is openUpgrade or downgrade the limitPOST /v2/credit-lines/{credit_line_id}/ with tier_update
After each changeConfirm the new limitcreditline.updated webhook, then GET /v2/credit-lines/{credit_line_id}/

When to Use This

Use this endpoint when an onboarded consumer moves to a higher tier (for example, after a run of on-time payments) or to a lower tier (for example, after missed payments or a change in your risk assessment).

Before You Start

Check all of these before you send a tier change:

  • Your program is enabled for tier changes. Upward turns this on per program. If it isn’t, the endpoint returns 403.
  • Your token has a write scope. The partner access token needs api:trade-line:write or api:write.
  • The credit line is open. The consumer must have completed Step 6: Submit Loan. Tier changes aren’t available before then.
  • You have the credit line id. It is returned by the onboarding flow and on the creditline.* webhooks.

The Request

POST https://api-sandbox.upwardli.com/v2/credit-lines/{credit_line_id}/

See the update credit line tier API.

Header
{
"Authorization":"Bearer [access_token]",
"Content-Type":"application/json"
}

Body

{
"tier_update": {
"approved_loan_amount": 2500,
"reason": "Moved to Gold tier after 6 on-time payments"
}
}
FieldTypeRequiredDescription
tier_update.approved_loan_amountintegerYesThe new credit limit in whole US dollars. Must be a JSON integer within the range allowed by your tier configuration. Quoted numbers, decimals and booleans are rejected.
tier_update.reasonstringNoWhy the limit changed, up to 255 characters. Upward stores it with the change for audit and support. Don’t include personal or sensitive consumer data.

The same endpoint handles both directions. A higher amount than the current limit is an upgrade; a lower amount is a downgrade.

The Response

A successful call returns 200 OK with the updated credit line, in the same shape as GET /v2/credit-lines/{credit_line_id}/:

{
"id": "0f3c9a52-8d1e-4b7a-9a7e-2f1d6c4e8b10",
"consumer_id": "a51e7c2b-3f4d-4e8a-b6c1-9d0e2f3a4b5c",
"current_status": "active",
"outstanding_balance": 420.0,
"approved_loan_amount": 2500.0,
"agreement_accepted": true,
"autopay_enabled": true
}

approved_loan_amount is the consumer’s credit limit and now shows the new value.


Walkthrough: Upgrade a Consumer

In this example, a consumer was onboarded at 1,500andhasearnedanupgradeto1,500 and has earned an upgrade to 2,500.

Step 1: Read the current credit line.

GET https://api-sandbox.upwardli.com/v2/credit-lines/{credit_line_id}/

{
"id": "0f3c9a52-8d1e-4b7a-9a7e-2f1d6c4e8b10",
...
"outstanding_balance": 420.0,
"approved_loan_amount": 1500.0,
...
}

Confirm the current limit and decide the new one. If the consumer has purchases that are still InProgress or Received, wait until they settle (see Pending transactions).

Step 2: Send the upgrade.

POST https://api-sandbox.upwardli.com/v2/credit-lines/{credit_line_id}/

{
"tier_update": {
"approved_loan_amount": 2500,
"reason": "Upgrade: 6 on-time payments"
}
}

The response is 200 OK with "approved_loan_amount": 2500.0.

Step 3: Handle the webhook.

Upward sends a creditline.updated webhook. Its resources array points to the credit line. Fetch the credit line and update the limit you store and show in your app.

What changes for the consumer:

  • New purchase holds are checked against the new 2,500limit,sotheconsumerhas2,500 limit, so the consumer has 1,000 more available credit right away.
  • Statements generated after the change show $2,500 as the credit limit.
  • The outstanding balance doesn’t change.
  • The cooldown starts. The consumer’s limit can’t change again until the cooldown period ends.

Walkthrough: Downgrade a Consumer

In this example, a consumer at 2,500movesdownto2,500 moves down to 1,000.

Step 1: Read the current credit line and note the outstanding_balance.

Step 2: Send the downgrade.

POST https://api-sandbox.upwardli.com/v2/credit-lines/{credit_line_id}/

{
"tier_update": {
"approved_loan_amount": 1000,
"reason": "Downgrade: tier review"
}
}

The response is 200 OK with "approved_loan_amount": 1000.0.

Step 3: Handle the creditline.updated webhook the same way as an upgrade.

Downgrading Below the Current Balance

Upward doesn’t block a downgrade below the consumer’s current balance. If the consumer owes 1,200andyoudowngradethelimitto1,200 and you downgrade the limit to 1,000:

  • the downgrade succeeds, and the balance stays at $1,200
  • existing transactions aren’t reversed
  • new purchase holds are declined with 400 Bad Request (“insufficient funds in their Credit Line”) until the balance plus the new hold fits within $1,000
  • the consumer keeps repaying as usual

Tell the consumer before you downgrade. A downgrade below the balance means new purchases are declined until they pay down. Check outstanding_balance first, and decide whether to wait for a lower balance or tell the consumer what to expect.


Rules for Tier Changes

Cooldown Between Changes

After a limit change, the consumer’s limit can’t change again until the cooldown period ends. The cooldown is set per program and is 30 days unless you’ve agreed a different period with Upward.

  • The cooldown applies to upgrades and downgrades alike. An upgrade followed by a downgrade inside the window is rejected.
  • Setting the starting limit at onboarding does not start the cooldown. The first upgrade or downgrade after onboarding can happen at any time.
  • A change inside the cooldown returns 409 Conflict. The message gives the next date a change is allowed (UTC), for example Credit limit can be changed again on 2026-12-06.

If you need an exception, such as a correction made in error, contact Upward support.

Pending Transactions

A limit change is rejected with 409 Conflict while the consumer has transactions with status InProgress or Received. Wait for them to settle and try again.

Transactions in Hold status don’t block a change.

Retries Are Safe

If you send the consumer’s current limit, Upward returns 200 OK and changes nothing: no webhook is sent and the cooldown doesn’t start. You can safely retry a request if you didn’t get a response, for example after a timeout.

If two different changes arrive for the same consumer at the same time, Upward processes them one after the other. With a cooldown in place, the first is applied and the second is rejected with 409 Conflict.

Allowed Values

The new limit must be a whole-dollar JSON integer within the range allowed by your tier configuration. Quoted numbers such as "1500", decimals such as 1500.5 or 1500.0, and booleans are rejected with 400 Bad Request. You can move a consumer up or down by any amount within that range. You don’t have to step through each tier.


  1. Store the credit line id when the loan is submitted.
  2. When your tier logic decides to move a consumer, read the credit line, check outstanding_balance and pending transactions, then POST the tier_update.
  3. Treat 200 OK as done. On a timeout, retry with the same amount.
  4. On 409 Conflict, read the message. For a cooldown, schedule the change for the date given. For pending transactions, retry after they settle.
  5. Listen for creditline.updated and refresh the limit you show from GET /v2/credit-lines/{credit_line_id}/. The same webhook fires for other credit line updates, so always read approved_loan_amount instead of assuming what changed.


Errors

StatusMessageCauseWhat to do
400 Bad RequestField errors under detailtier_update is missing, approved_loan_amount isn’t a whole-dollar JSON integer within your tier range, or reason is over 255 characters.Fix the body and resend.
403 ForbiddenCredit limit changes are not enabled for this program.Tier changes aren’t enabled for your program.Contact your Upward representative.
403 ForbiddenPermission errorYour token doesn’t have api:trade-line:write or api:write.Request a token with one of those scopes.
404 Not FoundNo credit line with that id exists for your partner account.Check the credit_line_id.
409 ConflictCredit limit can only be changed after the loan is created.Step 6: Submit Loan hasn’t completed for this consumer.Wait until the loan is submitted, then retry.
409 ConflictCredit limit can be changed again on YYYY-MM-DD.The last change was inside the cooldown period.Retry on or after the date given.
409 ConflictCredit limit can't be changed while transactions are pending.The consumer has InProgress or Received transactions.Retry after they settle.

A 400 response lists the field errors:

{
"detail": {
"tier_update": {
"approved_loan_amount": ["A valid integer is required."]
}
},
"code": 400,
"messages": []
}

409 responses, and the 403 for a program without tier changes, use this shape:

{
"error": "Credit limit can be changed again on 2026-12-06.",
"error_code": "api_error",
"message": []
}

A rejected request changes nothing: the limit, the cooldown and the webhooks are all left as they were.