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.

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