User-Provided Cost Basis

Overview

When end-users transfer digital assets onto your platform, the initial acquisition information of the transfer-in transaction will be considered "missing cost basis" (see Inventory Key Terms). As a result, gains and losses cannot be accurately calculated.

Digital Asset exchanges that have built out a customer experience to accept user-provided cost-basis information can send the transfer information to Taxbit to calculate and maintain accurate inventory values. Taxbit leverages the user-provided cost basis values to calculate inventory and manage dispositions at the lot-level. Taxbit will also indicate impacted disposition items that have a user-provided cost basis value.

Example UI that can be powered for end users to fill in lot level acquisition details

Example UI that can be powered for end users to fill in lot level acquisition details


Creating Transfer Lots

A set of Transfer Lots can be created and associated with a transfer-in transaction. A Transfer Lots item consists of an Acquisition Date (of the lot), Quantity (in the lot), and Cost Basis (value of lot at acquisition). You can leverage the Transfer-Lots APIs with the POST , GET and DELETE.

📘

Transfer Lots can only be created for Transfer-In transactions

Creating transfer-lots for any other transaction type will result in a 400 error response.

In the following example, we will: walk through creating a transfer-in transaction (with missing cost basis), review inventory with missing cost basis, create the transfer lots representing user-provided cost basis, and review the impact to inventory.

post /v1/transaction (transfer-in)

First, we will show creating a transfer-in transaction of 1.75BTC. It has no cost basis information.

curl --request POST \
  --url https://api.multi1.enterprise.taxbit.com/v1/transactions/external-id \
  --header 'Authorization: Bearer {{token}}' \
  --header 'Content-Type: application/json' \
  --data '{
    "account_id": "{{account_id}}",
    "id": "{{transfer-in-transaction-id}}",
    "datetime": "2024-01-01T00:00:00.000Z",
    "type": "deposit",
    "received": [
        {
            "asset_amount": {
                "amount": "1.75",
                "asset": {
                    "code": "BTC",
                    "type": "crypto"
                }
            }
        }
    ],
    "version": "2.0"
}'

{
  "status": "success",
  "message": "Transaction post successful."
}

get /v1/inventory

When we call the inventory, we will note that there is a missing_cost_basis = true

curl --request GET \
    --url '{{base-url}}/v1/inventory?account_id={{account-id}}&asset_code=BTC' \
    --header 'Authorization: Bearer {{token}}'

{
  "data": {
    "asset": {
      "uuid": "9cd9f4d4-078b-4e44-a308-7662fec0f546",
      "name": "Bitcoin",
      "code": "BTC",
      "type": "Crypto"
    },
    "fiat_asset": {
      "uuid": "df939ab7-b7ed-4216-be63-ca1d2a130396",
      "name": "United States Dollar",
      "code": "USD",
      "type": "Fiat"
    },
    "summary": {
      "latest_transaction_datetime": "2024-01-01T00:00:00.000Z",
      "total_quantity": "1.75",
      "total_cost": "0",
      "average_unit_cost": "0",
      "total_quantity_with_cost_basis": "0",
      "total_quantity_missing_cost_basis": "1.75"
    },
    "lots": [
      {
        "id": "c73deecc-fd19-50cc-9ab4-2b024a76a23d",
        "acquisition_datetime": "2024-01-01T00:00:00Z",
        "term": "short-term",
        "quantity": "1.75",
        "missing_cost_basis": true
      }
    ]
  }
}

post /v1/transfer-lots

If a user provides cost-basis information for a transfer-in transaction, you can send that data as an array of transfer-lots on the source transaction.

curl --request POST \
  --url '{{base_url}}/v1/transfer-lots/{{transfer-in-transaction-id}}' \
  --header 'Authorization: Bearer {{token}}' \
  --header 'Content-Type: application/json' \
  --data '{
    "transfer_lots": [
        {
            "quantity": ".5",
            "cost_basis": "20000.00",
            "acquisition_transaction_datetime": "2023-06-15T12:00:00Z"
        },
        {
            "quantity": "1.0",
            "cost_basis": "18050.50",
            "acquisition_transaction_datetime": "2023-05-10T09:30:00Z"
        },
        {
            "quantity": ".25",
            "cost_basis": "17000.50",
            "acquisition_transaction_datetime": "2023-04-25T14:45:00Z"
        }
    ]
}'

get /v1/transfer-lots

You may retrieve transfer lots associated with a specific transaction after creating them.

curl --request GET  
  --url '{{base_url}}/v1/transfer-lots/transactions/{{transfer-in-transaction-id}}'  
  --header 'Authorization: Bearer {{token}}'
{
  "transaction_id": "{{transfer-in-transaction-id}}",
  "transfer_lots": [
    {
      "cost_basis": "20000",
      "transaction_id": "{{transfer-in-transaction-id}}",
      "created_datetime": "2024-08-09T21:10:08.975Z",
      "acquisition_transaction_datetime": "2023-06-15T12:00:00Z",
      "modified_datetime": "2024-08-09T21:10:08.975Z",
      "quantity": "0.5"
    },
    {
      "cost_basis": "18050.5",
      "transaction_id": "{{transfer-in-transaction-id}}",
      "created_datetime": "2024-08-09T21:10:08.975Z",
      "acquisition_transaction_datetime": "2023-05-10T09:30:00Z",
      "modified_datetime": "2024-08-09T21:10:08.975Z",
      "quantity": "1"
    },
    {
      "cost_basis": "17000.5",
      "transaction_id": "{{transfer-in-transaction-id}}",
      "created_datetime": "2024-08-09T21:10:08.975Z",
      "acquisition_transaction_datetime": "2023-04-25T14:45:00Z",
      "modified_datetime": "2024-08-09T21:10:08.975Z",
      "quantity": "0.25"
    }
  ]
}

get /v1/ inventory

Note that inventory will also be updated with calculations based on the respective transfer-lot values sent to Taxbit.

{
  "data": {
    "asset": {
      "uuid": "9cd9f4d4-078b-4e44-a308-7662fec0f546",
      "name": "Bitcoin",
      "code": "BTC",
      "type": "Crypto"
    },
    "fiat_asset": {
      "uuid": "df939ab7-b7ed-4216-be63-ca1d2a130396",
      "name": "United States Dollar",
      "code": "USD",
      "type": "Fiat"
    },
    "summary": {
      "latest_transaction_datetime": "2024-01-01T00:00:00.000Z",
      "total_quantity": "1.75",
      "total_cost": "55051",
      "average_unit_cost": "31457.714285714285714286",
      "total_quantity_with_cost_basis": "1.75"
    },
    "lots": [
      {
        "id": "29bb8990-60f6-5bff-b73b-e4f840025276",
        "acquisition_datetime": "2023-04-25T14:45:00Z",
        "term": "long-term",
        "quantity": "0.25",
        "fiat_asset_code": "USD",
        "cost": "17000.5",
        "unit_cost": "68002"
      },
      {
        "id": "336218b1-ee25-5327-93a6-45167b9ddd56",
        "acquisition_datetime": "2023-06-15T12:00:00Z",
        "term": "long-term",
        "quantity": "0.5",
        "fiat_asset_code": "USD",
        "cost": "20000",
        "unit_cost": "40000"
      },
      {
        "id": "6cc4608e-df72-5b9f-a80a-cf2086e02f7f",
        "acquisition_datetime": "2023-05-10T09:30:00Z",
        "term": "long-term",
        "quantity": "1",
        "fiat_asset_code": "USD",
        "cost": "18050.5",
        "unit_cost": "18050.5"
      }
    ]
  }
}

Validations

During a POST, the quantity of assets of a set of transfer lots must match the transfer transaction’s quantity. If there is a mismatch in quantity, there will be a failed 400 response.

🚧

If a transaction with existing transfer lots is updated and the validation rules are broken, Taxbit will return the transfer lots with a 203 response.

During an update of a transaction with existing transfer lots, the following will conditionally occur:

  • If transaction date-time moves backward, any impacted transfer lots where the transfer-lot timestamp is later than the transfer-transaction timestamp will be ignored, and missing cost basis lots will fill the remaining quantity of the transfer
    • Calling a GET transfer-lots for this transaction will return a 203 response.
  • If quantity of the transfer-in transaction changes, ignore all lots & create MCB lot for the transfer-in.

Downstream API Impacts

Creating transfer-lots with user-provided-cost-basis for values will have downstream impacts on Transactions and Gains items. Taxbit’s API can inform if there has been an impact or derivation from a user-provided-cost-basis value.

  • Transactions GET – the tag has_transfer_lot_data = true if the cost basis was manually set on the transfer_in transaction
  • Gains (/v1/gains/cost-bases) GET – account_owner_edited = true when a gain item is impacted by a user-provided cost basis