Connect your sandbox to see this tutorial in action.

Tutorials

Inventory

Learn how to track stock with Blnk.

Inventory is how many units of a product you have, and where each one is: in stock, sold, on the way to a buyer, or delivered. Each of those stages is a balance, and moving units from one stage to the next is a transaction, so every count has a history you can replay.

This tutorial shows how to implement that with Blnk.

Step

Design the money movement

Before we start building, we need to define our money movement. This helps us outline how Alice’s phones move from her stock to Bob.

Alice sells the iPhone 16 Black 128GB. She gets 30 phones from her supplier. We move them into her available balance from @StockIntake, an internal balance for stock that comes from outside.

Bob orders 2 phones. They move from available to sold, then to in transit, then to delivered.

We hold the sale as inflight when Bob checks out, so no one else can buy his 2 phones, and commit it when he pays. We record the pickup and the delivery when each one happens.

Step

Create the ledgers

Before we start recording transactions, we need to set up our ledgers to track Alice’s stock. We create one ledger for each stage: available, sold, in transit, and delivered.

Each ledger holds that stage for every product Alice sells. Listing the balances in the available ledger then shows how many of each product she can still sell.

Create the four ledgers:

curl -X POST "CORE_URL/ledgers" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "{{available_name}}"
  }'

curl -X POST "CORE_URL/ledgers" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "{{sold_name}}"
  }'

curl -X POST "CORE_URL/ledgers" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "{{in_transit_name}}"
  }'

curl -X POST "CORE_URL/ledgers" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "{{delivered_name}}"
  }'
const available = await blnk.Ledgers.create({
  name: '{{available_name}}',
});

const sold = await blnk.Ledgers.create({
  name: '{{sold_name}}',
});

const inTransit = await blnk.Ledgers.create({
  name: '{{in_transit_name}}',
});

const delivered = await blnk.Ledgers.create({
  name: '{{delivered_name}}',
});
available, _, _ := client.Ledger.Create(blnkgo.CreateLedgerRequest{
    Name: "{{available_name}}",
})

sold, _, _ := client.Ledger.Create(blnkgo.CreateLedgerRequest{
    Name: "{{sold_name}}",
})

inTransit, _, _ := client.Ledger.Create(blnkgo.CreateLedgerRequest{
    Name: "{{in_transit_name}}",
})

delivered, _, _ := client.Ledger.Create(blnkgo.CreateLedgerRequest{
    Name: "{{delivered_name}}",
})
available = blnk.ledgers.create({
  "name": "{{available_name}}",
})

sold = blnk.ledgers.create({
  "name": "{{sold_name}}",
})

in_transit = blnk.ledgers.create({
  "name": "{{in_transit_name}}",
})

delivered = blnk.ledgers.create({
  "name": "{{delivered_name}}",
})
ApiResponse<JsonNode> available = blnk.ledgers().create(
    CreateLedger.create()
        .name("{{available_name}}"));

ApiResponse<JsonNode> sold = blnk.ledgers().create(
    CreateLedger.create()
        .name("{{sold_name}}"));

ApiResponse<JsonNode> inTransit = blnk.ledgers().create(
    CreateLedger.create()
        .name("{{in_transit_name}}"));

ApiResponse<JsonNode> delivered = blnk.ledgers().create(
    CreateLedger.create()
        .name("{{delivered_name}}"));

Step

Create an identity

An identity is how we record the iPhone. We’ll link its four balances to it, one per stage, so we can see where every unit is.

Blnk has two identity types, individual and organization. We use organization for the phone and pass its name and category.

One identity is one seller’s stock of one SKU. If another seller lists the same phone, they get their own identity.

Anything else we want to keep goes in metadata. We’ll store the phone’s SKU (stock keeping unit) there as sku, so we can find every transaction for this phone later. We’ll also store item_code for the iPhone 16 family and seller_id for Alice.

Create the identity:

curl -X POST "CORE_URL/identities" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "identity_type": "organization",
    "organization_name": "{{organization_name}}",
    "category": "{{category}}",
    "meta_data": {
      "seller_id": "{{seller_id}}",
      "item_code": "{{item_code}}",
      "sku": "{{sku}}"
    }
  }'
const response = await blnk.Identity.create({
  identity_type: 'organization',
  organization_name: '{{organization_name}}',
  category: '{{category}}',
  meta_data: {
    seller_id: '{{seller_id}}',
    item_code: '{{item_code}}',
    sku: '{{sku}}',
  },
});
identity, _, _ := client.Identity.Create(blnkgo.Identity{
    IdentityType: blnkgo.Organization,
    OrganizationName: "{{organization_name}}",
    Category: "{{category}}",
    MetaData: blnkgo.MetaData{
        "seller_id": "{{seller_id}}",
        "item_code": "{{item_code}}",
        "sku": "{{sku}}",
    },
})
response = blnk.identity.create({
  "identity_type": "organization",
  "organization_name": "{{organization_name}}",
  "category": "{{category}}",
  "meta_data": {
    "seller_id": "{{seller_id}}",
    "item_code": "{{item_code}}",
    "sku": "{{sku}}",
  },
})
ApiResponse<JsonNode> response = blnk.identity().create(
    IdentityData.create()
        .identityType("organization")
        .organizationName("{{organization_name}}")
        .category("{{category}}")
        .metaData(Map.of(
            "seller_id", "{{seller_id}}",
            "item_code", "{{item_code}}",
            "sku", "{{sku}}"
        )));

Step

Create the stage balances

Alice’s iPhone needs a balance in each of the four ledgers. Each request takes a ledger_id from step 2 and the same identity_id from step 3.

We set the currency to UNIT. When Alice receives her 30 phones in the next step, her available balance will show 30.

Create the four balances:

curl -X POST "CORE_URL/balances" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ledger_id": "{{available_ledger}}",
    "identity_id": "{{identity_id}}",
    "currency": "UNIT"
  }'

curl -X POST "CORE_URL/balances" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ledger_id": "{{sold_ledger}}",
    "identity_id": "{{identity_id}}",
    "currency": "UNIT"
  }'

curl -X POST "CORE_URL/balances" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ledger_id": "{{in_transit_ledger}}",
    "identity_id": "{{identity_id}}",
    "currency": "UNIT"
  }'

curl -X POST "CORE_URL/balances" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ledger_id": "{{delivered_ledger}}",
    "identity_id": "{{identity_id}}",
    "currency": "UNIT"
  }'
const available = await blnk.LedgerBalances.create({
  ledger_id: '{{available_ledger}}',
  identity_id: '{{identity_id}}',
  currency: 'UNIT',
});

const sold = await blnk.LedgerBalances.create({
  ledger_id: '{{sold_ledger}}',
  identity_id: '{{identity_id}}',
  currency: 'UNIT',
});

const inTransit = await blnk.LedgerBalances.create({
  ledger_id: '{{in_transit_ledger}}',
  identity_id: '{{identity_id}}',
  currency: 'UNIT',
});

const delivered = await blnk.LedgerBalances.create({
  ledger_id: '{{delivered_ledger}}',
  identity_id: '{{identity_id}}',
  currency: 'UNIT',
});
available, _, _ := client.LedgerBalance.Create(blnkgo.CreateLedgerBalanceRequest{
    LedgerID: "{{available_ledger}}",
    IdentityID: "{{identity_id}}",
    Currency: "UNIT",
})

sold, _, _ := client.LedgerBalance.Create(blnkgo.CreateLedgerBalanceRequest{
    LedgerID: "{{sold_ledger}}",
    IdentityID: "{{identity_id}}",
    Currency: "UNIT",
})

inTransit, _, _ := client.LedgerBalance.Create(blnkgo.CreateLedgerBalanceRequest{
    LedgerID: "{{in_transit_ledger}}",
    IdentityID: "{{identity_id}}",
    Currency: "UNIT",
})

delivered, _, _ := client.LedgerBalance.Create(blnkgo.CreateLedgerBalanceRequest{
    LedgerID: "{{delivered_ledger}}",
    IdentityID: "{{identity_id}}",
    Currency: "UNIT",
})
available = blnk.ledger_balances.create({
  "ledger_id": "{{available_ledger}}",
  "identity_id": "{{identity_id}}",
  "currency": "UNIT",
})

sold = blnk.ledger_balances.create({
  "ledger_id": "{{sold_ledger}}",
  "identity_id": "{{identity_id}}",
  "currency": "UNIT",
})

in_transit = blnk.ledger_balances.create({
  "ledger_id": "{{in_transit_ledger}}",
  "identity_id": "{{identity_id}}",
  "currency": "UNIT",
})

delivered = blnk.ledger_balances.create({
  "ledger_id": "{{delivered_ledger}}",
  "identity_id": "{{identity_id}}",
  "currency": "UNIT",
})
ApiResponse<JsonNode> available = blnk.ledgerBalances().create(
    CreateLedgerBalance.create()
        .ledgerId("{{available_ledger}}")
        .identityId("{{identity_id}}")
        .currency("UNIT"));

ApiResponse<JsonNode> sold = blnk.ledgerBalances().create(
    CreateLedgerBalance.create()
        .ledgerId("{{sold_ledger}}")
        .identityId("{{identity_id}}")
        .currency("UNIT"));

ApiResponse<JsonNode> inTransit = blnk.ledgerBalances().create(
    CreateLedgerBalance.create()
        .ledgerId("{{in_transit_ledger}}")
        .identityId("{{identity_id}}")
        .currency("UNIT"));

ApiResponse<JsonNode> delivered = blnk.ledgerBalances().create(
    CreateLedgerBalance.create()
        .ledgerId("{{delivered_ledger}}")
        .identityId("{{identity_id}}")
        .currency("UNIT"));

Step

Receive the stock

Alice’s 30 phones arrive from her supplier. We move them from @StockIntake to her available balance, with the SKU in metadata so this transaction shows up when we read the phone’s history in step 10.

A phone can’t be split into fractions, so we set precision to 1. The amount is then just the number of phones, 30.

skip_queue records the transaction straight away, so the 30 phones are ready to sell before Bob orders.

After the transaction, @StockIntake shows -30, one for each phone Alice received.

Receive the stock:

curl -X POST "CORE_URL/transactions" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "precise_amount": {{quantity_precise}},
    "precision": 1,
    "reference": "RCV-20261019-090000",
    "description": "Stock received",
    "currency": "UNIT",
    "source": "@StockIntake",
    "destination": "{{destination}}",
    "allow_overdraft": true,
    "skip_queue": true,
    "meta_data": {
      "sku": "{{receipt_sku}}"
    }
  }'
const response = await blnk.Transactions.create({
  precise_amount: {{quantity}},
  precision: 1,
  reference: 'RCV-20261019-090000',
  description: 'Stock received',
  currency: 'UNIT',
  source: '@StockIntake',
  destination: '{{destination}}',
  allow_overdraft: true,
  skip_queue: true,
  meta_data: {
    sku: '{{receipt_sku}}',
  },
});
transaction, _, _ := client.Transaction.Create(blnkgo.CreateTransactionRequest{
    ParentTransaction: blnkgo.ParentTransaction{
        PreciseAmount: big.NewInt({{quantity}}),
        Precision: 1,
        Reference: "RCV-20261019-090000",
        Description: "Stock received",
        Currency: "UNIT",
        Source: "@StockIntake",
        Destination: "{{destination}}",
        SkipQueue: true,
        MetaData: blnkgo.MetaData{
            "sku": "{{receipt_sku}}",
        },
    },
    AllowOverdraft: true,
})
response = blnk.transactions.create({
  "precise_amount": {{quantity}},
  "precision": 1,
  "reference": "RCV-20261019-090000",
  "description": "Stock received",
  "currency": "UNIT",
  "source": "@StockIntake",
  "destination": "{{destination}}",
  "allow_overdraft": True,
  "skip_queue": True,
  "meta_data": {
    "sku": "{{receipt_sku}}",
  },
})
ApiResponse<JsonNode> response = blnk.transactions().create(
    CreateTransactions.create()
        .preciseAmount({{quantity}})
        .precision(1)
        .reference("RCV-20261019-090000")
        .description("Stock received")
        .currency("UNIT")
        .source("@StockIntake")
        .destination("{{destination}}")
        .allowOverdraft(true)
        .skipQueue(true)
        .metaData(Map.of("sku", "{{receipt_sku}}")));

Step

Hold the sale

Bob checks out with 2 phones. We record the sale from Alice’s available balance to her sold balance as inflight, so his 2 phones are reserved and no one else can buy them.

Each transaction’s reference starts with Bob’s order ID, ord_4412, and the SKU goes in metadata. skip_queue records the hold straight away, so we can commit it in the next step.

Blnk rejects a second transaction with a reference it has already seen. If a request times out and your code sends it again, the phones still move only once.

Hold the sale:

curl -X POST "CORE_URL/transactions" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "precise_amount": 2,
    "precision": 1,
    "reference": "ord_4412_sold",
    "description": "Checkout paid",
    "currency": "UNIT",
    "source": "{{sale_source}}",
    "destination": "{{sale_destination}}",
    "inflight": true,
    "skip_queue": true,
    "meta_data": {
      "order_id": "ord_4412",
      "sku": "IP16-BLK-128"
    }
  }'
const response = await blnk.Transactions.create({
  precise_amount: 2,
  precision: 1,
  reference: 'ord_4412_sold',
  description: 'Checkout paid',
  currency: 'UNIT',
  source: '{{sale_source}}',
  destination: '{{sale_destination}}',
  inflight: true,
  skip_queue: true,
  meta_data: {
    order_id: 'ord_4412',
    sku: 'IP16-BLK-128',
  },
});
transaction, _, _ := client.Transaction.Create(blnkgo.CreateTransactionRequest{
    ParentTransaction: blnkgo.ParentTransaction{
        PreciseAmount: big.NewInt(2),
        Precision: 1,
        Reference: "ord_4412_sold",
        Description: "Checkout paid",
        Currency: "UNIT",
        Source: "{{sale_source}}",
        Destination: "{{sale_destination}}",
        SkipQueue: true,
        MetaData: blnkgo.MetaData{
            "order_id": "ord_4412",
            "sku": "IP16-BLK-128",
        },
    },
    Inflight: true,
})
response = blnk.transactions.create({
  "precise_amount": 2,
  "precision": 1,
  "reference": "ord_4412_sold",
  "description": "Checkout paid",
  "currency": "UNIT",
  "source": "{{sale_source}}",
  "destination": "{{sale_destination}}",
  "inflight": True,
  "skip_queue": True,
  "meta_data": {
    "order_id": "ord_4412",
    "sku": "IP16-BLK-128",
  },
})
ApiResponse<JsonNode> response = blnk.transactions().create(
    CreateTransactions.create()
        .preciseAmount(2)
        .precision(1)
        .reference("ord_4412_sold")
        .description("Checkout paid")
        .currency("UNIT")
        .source("{{sale_source}}")
        .destination("{{sale_destination}}")
        .inflight(true)
        .skipQueue(true)
        .metaData(Map.of("order_id", "ord_4412", "sku", "IP16-BLK-128")));

Step

Commit the sale

Bob’s payment goes through, so we commit the hold. The 2 phones move from Alice’s available balance to her sold balance.

After the commit, her available balance is 28 and her sold balance is 2.

Commit the sale:

curl -X PUT "CORE_URL/transactions/inflight/{{sale_transaction_id}}" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "commit"
  }'
const response = await blnk.Transactions.updateStatus(
  '{{sale_transaction_id}}',
  {
    status: 'commit',
  },
);
transaction, _, _ := client.Transaction.Update(
    "{{sale_transaction_id}}",
    blnkgo.UpdateStatus{
        Status: blnkgo.InflightStatusCommit,
    },
)
response = blnk.transactions.update_status(
  "{{sale_transaction_id}}",
  {
    "status": "commit",
  },
)
ApiResponse<JsonNode> response = blnk.transactions().updateStatus(
    "{{sale_transaction_id}}",
    UpdateTransactionStatus.create()
        .status("commit"));

Step

Record the pickup

The courier picks up Bob’s phones. We record a transaction from Alice’s sold balance to her in-transit balance.

This one is not inflight, because the pickup has already happened. After it, her sold balance is back to 0 and her in-transit balance is 2.

Record the pickup:

curl -X POST "CORE_URL/transactions" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "precise_amount": 2,
    "precision": 1,
    "reference": "ord_4412_in_transit",
    "description": "Picked up for delivery",
    "currency": "UNIT",
    "source": "{{pickup_source}}",
    "destination": "{{pickup_destination}}",
    "skip_queue": true,
    "meta_data": {
      "order_id": "ord_4412",
      "sku": "IP16-BLK-128"
    }
  }'
const response = await blnk.Transactions.create({
  precise_amount: 2,
  precision: 1,
  reference: 'ord_4412_in_transit',
  description: 'Picked up for delivery',
  currency: 'UNIT',
  source: '{{pickup_source}}',
  destination: '{{pickup_destination}}',
  skip_queue: true,
  meta_data: {
    order_id: 'ord_4412',
    sku: 'IP16-BLK-128',
  },
});
transaction, _, _ := client.Transaction.Create(blnkgo.CreateTransactionRequest{
    ParentTransaction: blnkgo.ParentTransaction{
        PreciseAmount: big.NewInt(2),
        Precision: 1,
        Reference: "ord_4412_in_transit",
        Description: "Picked up for delivery",
        Currency: "UNIT",
        Source: "{{pickup_source}}",
        Destination: "{{pickup_destination}}",
        SkipQueue: true,
        MetaData: blnkgo.MetaData{
            "order_id": "ord_4412",
            "sku": "IP16-BLK-128",
        },
    },
})
response = blnk.transactions.create({
  "precise_amount": 2,
  "precision": 1,
  "reference": "ord_4412_in_transit",
  "description": "Picked up for delivery",
  "currency": "UNIT",
  "source": "{{pickup_source}}",
  "destination": "{{pickup_destination}}",
  "skip_queue": True,
  "meta_data": {
    "order_id": "ord_4412",
    "sku": "IP16-BLK-128",
  },
})
ApiResponse<JsonNode> response = blnk.transactions().create(
    CreateTransactions.create()
        .preciseAmount(2)
        .precision(1)
        .reference("ord_4412_in_transit")
        .description("Picked up for delivery")
        .currency("UNIT")
        .source("{{pickup_source}}")
        .destination("{{pickup_destination}}")
        .skipQueue(true)
        .metaData(Map.of("order_id", "ord_4412", "sku", "IP16-BLK-128")));

Step

Record the delivery

Bob receives his phones. We record a transaction from Alice’s in-transit balance to her delivered balance.

After it, her in-transit balance is back to 0 and her delivered balance is 2.

Record the delivery:

curl -X POST "CORE_URL/transactions" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "precise_amount": 2,
    "precision": 1,
    "reference": "ord_4412_delivered",
    "description": "Customer confirmed delivery",
    "currency": "UNIT",
    "source": "{{delivery_source}}",
    "destination": "{{delivery_destination}}",
    "skip_queue": true,
    "meta_data": {
      "order_id": "ord_4412",
      "sku": "IP16-BLK-128"
    }
  }'
const response = await blnk.Transactions.create({
  precise_amount: 2,
  precision: 1,
  reference: 'ord_4412_delivered',
  description: 'Customer confirmed delivery',
  currency: 'UNIT',
  source: '{{delivery_source}}',
  destination: '{{delivery_destination}}',
  skip_queue: true,
  meta_data: {
    order_id: 'ord_4412',
    sku: 'IP16-BLK-128',
  },
});
transaction, _, _ := client.Transaction.Create(blnkgo.CreateTransactionRequest{
    ParentTransaction: blnkgo.ParentTransaction{
        PreciseAmount: big.NewInt(2),
        Precision: 1,
        Reference: "ord_4412_delivered",
        Description: "Customer confirmed delivery",
        Currency: "UNIT",
        Source: "{{delivery_source}}",
        Destination: "{{delivery_destination}}",
        SkipQueue: true,
        MetaData: blnkgo.MetaData{
            "order_id": "ord_4412",
            "sku": "IP16-BLK-128",
        },
    },
})
response = blnk.transactions.create({
  "precise_amount": 2,
  "precision": 1,
  "reference": "ord_4412_delivered",
  "description": "Customer confirmed delivery",
  "currency": "UNIT",
  "source": "{{delivery_source}}",
  "destination": "{{delivery_destination}}",
  "skip_queue": True,
  "meta_data": {
    "order_id": "ord_4412",
    "sku": "IP16-BLK-128",
  },
})
ApiResponse<JsonNode> response = blnk.transactions().create(
    CreateTransactions.create()
        .preciseAmount(2)
        .precision(1)
        .reference("ord_4412_delivered")
        .description("Customer confirmed delivery")
        .currency("UNIT")
        .source("{{delivery_source}}")
        .destination("{{delivery_destination}}")
        .skipQueue(true)
        .metaData(Map.of("order_id", "ord_4412", "sku", "IP16-BLK-128")));

Step

Read the phone's history

Every transaction for the phone has its SKU in metadata, so one filter on meta_data.sku returns its whole history. We sort it by created_at, newest first.

The results show the 30 phones Alice received, the sale hold with its commit, the pickup, and the delivery. If Alice asks why her count changed, this is the record you show her.

The filter returns 20 results by default. Pass limit (up to 100) and offset to page through a longer history.

Read the history:

curl -X POST "CORE_URL/transactions/filter" \
  -H "X-blnk-key: CORE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filters": [
      {
        "field": "meta_data.sku",
        "operator": "eq",
        "value": "{{history_sku}}"
      }
    ],
    "sort_by": "created_at",
    "sort_order": "desc"
  }'
const response = await blnk.Search.filter(
  {
    filters: [
      {
        field: 'meta_data.sku',
        operator: 'eq',
        value: '{{history_sku}}',
      },
    ],
    sort_by: 'created_at',
    sort_order: 'desc',
  },
  'transactions',
);
results, _, _ := client.Transaction.Filter(blnkgo.FilterParams{
    Filters: []blnkgo.Filter{
        {
            Field: "meta_data.sku",
            Operator: blnkgo.OpEqual,
            Value: "{{history_sku}}",
        },
    },
    SortBy: "created_at",
    SortOrder: "desc",
})
response = blnk.search.filter(
  {
    "filters": [
      {
        "field": "meta_data.sku",
        "operator": "eq",
        "value": "{{history_sku}}",
      },
    ],
    "sort_by": "created_at",
    "sort_order": "desc",
  },
  "transactions",
)
ApiResponse<JsonNode> response = blnk.search().filter(
    FilterParams.create()
        .filters(List.of(
            FilterCondition.create()
                .field("meta_data.sku")
                .operator("eq")
                .value("{{history_sku}}")))
        .sortBy("created_at")
        .sortOrder("desc"),
    "transactions");

Step

Read a past stock count

Alice may ask how many phones she had available at an earlier time. A historical balance returns her available balance as it was then, not as it is today.

Pass her available balance_id and a timestamp from your own run, in RFC 3339 format. A time after the transaction in step 5 and before the hold in step 6 shows 30.

A time after the sale is held returns 28. The historical balance counts the 2 held phones from the moment of the hold, even though her live balance still shows 30 until the commit.

Read the available balance at a past time:

curl -X GET "CORE_URL/balances/{{available_balance_id}}/at?timestamp={{timestamp}}" \
  -H "X-blnk-key: CORE_SECRET_KEY"
const response = await blnk.LedgerBalances.getAt(
  '{{available_balance_id}}',
  {
    timestamp: '{{timestamp}}',
  },
);
timestamp, _ := time.Parse(time.RFC3339, "{{timestamp}}")

balance, _, _ := client.LedgerBalance.GetHistorical(
    "{{available_balance_id}}",
    timestamp,
    false,
)
response = blnk.ledger_balances.get_at(
  "{{available_balance_id}}",
  {
    "timestamp": "{{timestamp}}",
  },
)
ApiResponse<JsonNode> response = blnk.ledgerBalances().getAt(
    "{{available_balance_id}}",
    GetBalanceAtRequest.create()
        .timestamp("{{timestamp}}"));

Step

Confirmation

Alice should now have 28 phones in her available balance and 2 in her delivered balance. Her sold and in-transit balances are back to 0, and @StockIntake is at -30.

If you have a Blnk Cloud account or an Enterprise license, you can confirm this by checking the dashboard or using the CLI.

Print every balance:

blnk balances list