API status

How to integrate ISA tax wrappers

Integrating tax wrapper functionality for ISAs

  1. Onboarding

    After creating your user, the next onboarding step is the creation of an account group. Tax-wrapped investment account groups must set type equal to PERSONAL, ISA during the account group creation API call:

    {
      "user_id": "413715f2-5401-4b97-8055-034a6b879f8c",
      "type": "PERSONAL, ISA"
    }

    Note: Tax-wrapped investment accounts are typically only available to (tax) residents of the country which regulates the specific tax wrapper. The account group will not transition to ACTIVE until the customer has confirmed their eligibility by creating a tax residency with an associated tax identification number (‘TIN’).

    After creating the account group, you can proceed with creating an account using the standard account creation flow.

  2. Tax Wrapper Creation

    The business rules and logic applicable to a tax-wrapped investment product are managed through the Tax Wrapper entity.

    A dedicated API call is available for each tax wrapper type.

    POST /isa/wrappers

    {
      "type": "STOCKS_AND_SHARES_ISA",
      "is_flexible": "true",
      "account_group_id": "0d68fea2-66e8-4ea8-b507-276e7a1eb4aa"
    }

    Specifically for STOCKS_AND_SHARES_ISA, we require an additional input parameter: is_flexible.

    Cash ISAs and Stocks & Shares ISAs come in two variations: flexible ISAs and non-flexible ISAs. Both allow customers to withdraw funds or sell assets from their ISA without limitations. Exceptions apply to specific ISA product types such as Fixed Rate ISAs, where withdrawals are allowed but penalised.

    For flexible ISAs, end-users can withdraw money and then replace that amount within the same tax year. In addition, a withdrawal will increase the end-user's allowance.

    For non-flexible ISAs, withdrawals do not impact your allowance.

    Tax Wrapper Status

    Once created, Tax Wrappers must pass the tax residency check before they can transition to ACTIVE. To accomplish this, you must create a tax residency as shown in the User Tax Onboarding section.

    In addition, the STOCKS_AND_SHARES_ISA account group requires an active tax wrapper in order to transition to ACTIVE.

  3. Allowance events

    Once the Tax Wrapper has been successfully created, the Investment API will automatically create the underlying Allowance resource and confirm its creation via the ISA_WRAPPER_ALLOWANCE webhook.

    {
      "id": "295cf14f-368c-450e-b57e-48d115d30fe4",
      "created_at": "2025-08-01T10:34:43Z",
      "type": "ISA_WRAPPER_ALLOWANCE.CREATED",
      "object": {
        "id": "f1a57a04-1a89-4dab-ae3a-ff9b2a9377c1",
        "created_at": "2025-10-05T14:48:00.000Z",
        "updated_at": "2025-10-05T14:48:00.000Z",
        "tax_wrapper_id": "0d68fea2-66e8-4ea8-b507-276e7a1eb4aa",
        "tax_year": "2025/2026",
        "type": "ANNUAL",
        "status": "ACTIVE, EXPIRED",
        "currency": "GBP",
        "total_amount": "20000.00",
        "used_amount": "1000.00",
        "remaining_amount": "19000.00",
        "valid_from": "2025-04-06T00:00:00.000Z",
        "valid_to": "2026-04-05T23:59:59.000Z",
        "first_subscription_at": "2025-11-13T00:00:00.000Z"
      },
      "webhook_id": "4a80c45f-204c-4498-ac20-d900a846e166"
    }

    ISA allowance events

    The ISA allowance events contain a lot of metadata, but the following values are related to the key business logic for ISA products.

    • tax_year: Since the UK tax year runs from April 6th until midnight April 5th, all year references will use the yyyy/yyyy (e.g., 2025/2026) format.

    • type: The Annual type refers to how the regulatory subscription limit renews annually. For 2025/2026 this value is set at £20,000. Regulatory changes to this limit are managed by Upvest and will automatically be applied before the start of the tax year.

    • status: Once an allowance entity with the type Annual hits the valid_to date, it will transition to the status EXPIRED. Expired allowances do not roll over. New allowance entities will be created at commencement of the new tax year.

    • Allowance values:

      • total_amount: Equals the regulatory determined subscription limit plus any flexible withdrawals in the current tax year.
      • used_amount: Reflects how much of the regulatory subscription limit has been used or flexible withdrawals replaced determined by cash subscriptions into the tax-wrapped product.
      • remaining_amount: The mathematical difference between total_amount and the used_amount.
      • valid_from and valid_to: Only relevant for Allowance entities with the type Annual.
      • first_subscription_at: Populated at the first cash subscription.

    Allowance events are emitted upon:

    • Creation: ISA_WRAPPER_ALLOWANCE.CREATED
    • Every time an inflow takes place into the tax wrapped product: ISA_WRAPPER_ALLOWANCE.UPDATED
    • Every time an outflow takes place from the tax wrapped product: ISA_WRAPPER_ALLOWANCE.UPDATED
    • When hitting the valid_to date Time: TAX_WRAPPER_ALLOWANCE.EXPIRED

    Supporting flexible ISAs

    Where the STOCKS_AND_SHARES_ISA parameter is_flexible equals true, the system automatically recognises any withdrawals made within the tax year and adds this to the total_amount ensuring the users are able to replace withdrawals made in that tax year before using their contribution.

    In the following example of a flexible ISA:

    The end user has an existing value of £50,000 in their ISA at the start of the tax year. They are allocated regulatory-determined amount of £20,000 allowance and have made no subscriptions.

    {
     "total_amount": "20000.00",
     "used_amount": "00.00",
     "remaining_amount": "20000.00",
    }

    When they make a subscription, in this example, £1000, the used_amount increases and the remaining_amount decreases by the amount of the subscription.

    {
      "total_amount": "20000.00",
      "used_amount": "1000.00",   
      "remaining_amount": "19000.00",
    }

    If they then make a withdrawal, in this example, £5,000, both the total_amount and the remaining_amount increase by the amount of the withdrawal.

    {
      "total_amount": "25000.00",   
      "used_amount": " 1000.00",
      "remaining_amount": "24000.00",
    }

    In the same scenario but with a non-flexible ISA, the allowance would not change due to the withdrawal as shown below.

    {
      "total_amount": "20000.00",    
      "used_amount": " 1000.00",   
      "remaining_amount": "19000.00",
    }
  4. Display allowance status

    The Investment API supports a synchronous endpoint to display the current state of allowances to an ISA account holder on your app or website.

    GET /isa/wrappers/{tax_wrapper_id}/allowances/

    {
      "meta": {
        "offset": 0,
        "limit": 100,
        "count": 2,
        "total_count": 2,
        "sort": "valid_from",
        "order": "DESC"
      }, 
      "data": [ 
        {
          "allowance_id": "019999a3-8a17-74e6-bfbd-50d9c7705ea0",  
          "tax_wrapper_id": "019999a3-c02a-7043-b100-9c2d76564748",
          "tax_year": "2024/2025", 
          "type": "ANNUAL",
          "status": "ACTIVE, EXPIRED",
          "currency": "GBP",
          "total_amount": "20000.00",
          "used_amount": "0.00",
          "remaining_amount": "20000.00",
          "first_subscription_at": "2021-07-21T14:10:00.00Z",
          "created_at": "2024-07-21T14:10:00.00Z",
          "updated_at": "2024-07-21T14:10:00.00Z",
          "valid_from": "2024-04-05T23:00:00.00Z",
          "valid_to": "2025-04-05T22:59:59.999999Z"
        },
        {
    	"allowance_id": "019999a3-8a17-74e6-bfbd-50d9c7705ea0",  
          "tax_wrapper_id": "019999a3-c02a-7043-b100-9c2d76564748",
          "tax_year": "2023/2024", 
          "type": "ANNUAL",
          "status": "ACTIVE, EXPIRED",
          "currency": "GBP",
          "total_amount": "20000.00",
          "used_amount": "1000.00",
          "remaining_amount": "19000.00",
          "first_subscription_at": "2023-07-21T14:10:00.00Z",
          "created_at": "2023-07-21T14:10:00.00Z",
          "updated_at": "2023-07-21T14:10:00.00Z",
          "valid_from": "2023-04-05T23:00:00.00Z",
          "valid_to": "2024-04-05T22:59:59.999999Z"
        }
      ]
    }
  5. Ensure a great ISA user experience

    The allowance events are the core of the Investment API’s tax wrapper functionality. The next section outlines how these and our Get /isa/wrappers/{tax_wrapper_id}/allowances endpoint can be leveraged to facilitate a great user experience for your customers.

    Allowance limits across ISA products

    Currently the Investment API only supports Stocks & Shares ISAs. However, we can enable a unified allowance UX where a client offers additional ISA products to their end users.

    By ingesting allowance events for the Stocks & Shares ISA as input values for an aggregated allowance value, Clients are able to represent a unified UX which outlines the total allowance limit across ISA products, such as Cash ISAs.

    Validations on ISA inflow

    As Upvest will not have oversight of other ISA types provided by the client, the Investment API will not block inflow into the ISA. This allows the client to manage overall allowance at the user level across cash ISA and Stocks & Shares ISA without creating a more limited check at Upvest for the Stocks & Shares ISA only.

    To prevent ISA account holders from breaching ISA subscription rules, the remaining_amount field can be leveraged to build front-end validations to prevent a deposit from being processed in the following scenarios:

    • A deposit exceeding a tax year’s remaining_amount
    • The overall subscription limit, as represented by amount

    The remaining amount figure will also take into account any additional allowance created by flexible withdrawals.

    Query parameters on Get Allowances

    To enable simplified integration, the tax_year query parameter allows specification of a particular tax year.

    GET /isa/wrappers/{tax_wrapper_id}/allowances?tax_year=2025/2026

    {
      "meta": {
        "offset": 0,
        "limit": 100,
        "count": 1,
        "total_count": 1,
        "sort": "valid_from",
        "order": "DESC",
      },
      "data": [ 
        {
          "allowance_id": "",  
          "tax_wrapper_id": "",
          "tax_year": "2025/2026", 
          "type": "ANNUAL",
          "status": "ACTIVE, EXPIRED",
          "currency": "GBP",
          "total_amount": "",
          "used_amount": "",
          "remaining_amount": "",
          "first_subscription_at": "2025-07-21T14:10:00.00Z",
          "created_at": "2025-07-21T14:10:00.00Z",
          "updated_at": "2025-07-21T14:10:00.00Z",
          "valid_from": "2025-04-05T23:00:00.00Z",
          "valid_to": "2025-04-05T22:59:59.999999Z",
        }
        ]
    }
  6. Start trading

    The steps outlined in our Order guides detail the steps necessary to place a trade in your newly created ISA accounts.

    Depending on the chosen cash model, ISA allowance values are automatically updated upon Virtual Cash increase / decrease or via direct funding methods outlined in our Payment guides.

    Associated Allowance events are generated asynchronously.

    The Investment API guarantees that only trading in ISA-eligible instruments is facilitated.