Skip to content

Transaction

A Transaction is money moving on a payment rail, such as a charge, a payout, or a transfer, reconciled to Entries.

Properties

PropertyTypeRequiredDescription
kindstringrequiredOne of charge, refund, payout, or transfer.
amountmoneyrequiredThe amount moved.
receiptFileThe receipt matched to a card Transaction.
settledAtdatetimeWhen the money became available in a cash Account.

Object

JSON
{
  "$id": "https://api.sb/tutorloop.com/transactions/transaction_1",
  "$type": "Transaction",
  "kind": "charge",
  "amount": {
    "amount": 60,
    "currency": "USD"
  },
  "receipt": "file_1",
  "settledAt": "2026-10-22T12:00:00Z"
}

Relationships

  • A Transaction reconciles many Entries: the ledger Entries the Transaction settles, matched during reconciliation. reconciles, inverse reconciledBy.

Verbs

  1. getReturns one Transaction by id.
    GET /{namespace}/transactions/{id}readNo Event
  2. listReturns Transactions, newest first, one page at a time.
    GET /{namespace}/transactionsreadNo Event
  3. attachAttach matches a receipt File to a card Transaction, or flags the Transaction when no receipt arrives in time.
    POST /{namespace}/transactions/{transaction}/attachdoTransaction.attached
  4. categorizeCategorize codes a Transaction to an account in the chart by the Startup’s Policy and flags a low-confidence code for review.
    POST /{namespace}/transactions/{transaction}/categorizedoTransaction.categorized
  5. reconcileReconcile matches a Transaction on a payment rail to the ledger Entries it settles.
    POST /{namespace}/transactions/{transaction}/reconciledoTransaction.reconciled

A Transaction is kept forever and never edited: it has no update or delete.

Events

Events no Verb emits. Each Verb’s Event is in the Verbs table above; every Event is delivered in the same shape.

Transaction.failed

The rail refused a charge or payout Transaction after it was sent. Raised by the rail.

FieldTypeRequiredDescription
namestringrequiredTransaction.failed.
atdatetimerequiredWhen it happened.
seqintegerIts position in the namespace, one more than the Event before; any seq is a cursor into the history.
datajsonrequiredThe Thing as the Action left it.
data.transactionTransactionrequiredThe Transaction as the change left it.
data.transaction.kindstringrequiredOne of charge, refund, payout, or transfer.
data.transaction.amountmoneyrequiredThe amount moved.
data.transaction.receiptFileThe receipt matched to a card Transaction.
data.transaction.settledAtdatetimeWhen the money became available in a cash Account.
data.reasontextrequiredWhy the rail refused it, in the rail’s words.
JSON
{
  "$id": "https://api.sb/tutorloop.com/events/event_1",
  "$type": "Event",
  "name": "Transaction.failed",
  "at": "2026-10-22T12:00:00Z",
  "data": {
    "transaction": {
      "$id": "https://api.sb/tutorloop.com/transactions/transaction_1",
      "$type": "Transaction",
      "kind": "charge",
      "amount": {
        "amount": 60,
        "currency": "USD"
      },
      "receipt": "file_1",
      "settledAt": "2026-10-22T12:00:00Z"
    },
    "reason": "The bank declined the transfer."
  },
  "seq": 1
}

Transaction.settled

The money in a Transaction became available in a cash Account. Raised by the rail.

FieldTypeRequiredDescription
namestringrequiredTransaction.settled.
atdatetimerequiredWhen it happened.
seqintegerIts position in the namespace, one more than the Event before; any seq is a cursor into the history.
datajsonrequiredThe Thing as the Action left it.
data.transactionTransactionrequiredThe Transaction as the change left it.
data.transaction.kindstringrequiredOne of charge, refund, payout, or transfer.
data.transaction.amountmoneyrequiredThe amount moved.
data.transaction.receiptFileThe receipt matched to a card Transaction.
data.transaction.settledAtdatetimeWhen the money became available in a cash Account.
data.accountAccountrequiredThe cash Account the money is in.
data.availableAtdatetimerequiredWhen the money became available.
JSON
{
  "$id": "https://api.sb/tutorloop.com/events/event_1",
  "$type": "Event",
  "name": "Transaction.settled",
  "at": "2026-10-22T12:00:00Z",
  "data": {
    "transaction": {
      "$id": "https://api.sb/tutorloop.com/transactions/transaction_1",
      "$type": "Transaction",
      "kind": "charge",
      "amount": {
        "amount": 60,
        "currency": "USD"
      },
      "receipt": "file_1",
      "settledAt": "2026-10-22T12:00:00Z"
    },
    "account": {
      "$id": "https://api.sb/tutorloop.com/accounts/account_1",
      "$type": "Account",
      "class": "cash"
    },
    "availableAt": "2026-10-22T12:00:00Z"
  },
  "seq": 1
}

Permissions

Which Access level may call each Verb. One-way Verbs wait their delay window.

Operationowneradminmemberviewer
Transaction.getYesYesYesYes
Transaction.listYesYesYesYes
Transaction.attachYesYesYesNo
Transaction.categorizeYesYesYesNo
Transaction.reconcileYesYesYesNo

Stripe

PaymentIntent (payment_intent), for a Transaction whose kind is charge. The source of truth is Stripe: db.sb mirrors it, written only from Stripe’s webhooks.

PropertyStripe fieldSource of truth
amountamountStripe

Payout (payout), for a Transaction whose kind is payout. The source of truth is Stripe: db.sb mirrors it, written only from Stripe’s webhooks.

PropertyStripe fieldSource of truth
amountamountStripe

Refund (refund), for a Transaction whose kind is refund. The source of truth is Stripe: db.sb mirrors it, written only from Stripe’s webhooks.

PropertyStripe fieldSource of truth
amountamountStripe

Call it

Text
Reconcile the latest transaction.

Example

A $49 Stripe charge is a Transaction. The monthly close reconciles it to two Entries.