> ## Documentation Index
> Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
> Use this file to discover all available pages before exploring further.

# App Billing Transactions

> List and inspect per-charge billing transactions for an installed app.

Every Stripe webhook the platform handles produces a row in
a billing-transaction ledger. A transaction represents **one charge event** for
an installed app — a subscription renewal, a one-time charge, or a usage-
based invoice line.

The transaction is the source of truth for developer revenue (after the
platform commission). When developer payouts are computed, the payout
service sums `developerAmount` over transactions in `status: paid` whose
`createdAt` falls in the payout period.

**Auth:** merchant JWT.

***

## List transactions

`GET /apps/billing/transactions`

<ParamField query="page" type="integer" default="1">Page number.</ParamField>
<ParamField query="limit" type="integer" default="50">Page size (max 250).</ParamField>
<ParamField query="status" type="string">Filter by status: `pending`, `paid`, `refunded`, `failed`.</ParamField>
<ParamField query="appId" type="string">Filter to one app's transactions. Pass the `appId` UUID.</ParamField>

```bash theme={null}
curl -X GET "https://api.launchmystore.io/apps/billing/transactions?status=paid&limit=50" \
  -H "Authorization: Bearer <MERCHANT_JWT>"
```

<ResponseField name="data.items" type="array">
  Array of transaction objects (see schema below).
</ResponseField>

<ResponseField name="data.pagination" type="object">
  <Expandable title="pagination">
    <ResponseField name="page" type="integer" />

    <ResponseField name="limit" type="integer" />

    <ResponseField name="total" type="integer" />

    <ResponseField name="hasMore" type="boolean" />
  </Expandable>
</ResponseField>

### Transaction object

| Field                   | Type     | Description                                             |
| ----------------------- | -------- | ------------------------------------------------------- |
| `transactionId`         | UUID     | Primary key.                                            |
| `appId`                 | UUID     | The app this charge is for.                             |
| `storeId`               | UUID     | The merchant store that paid.                           |
| `installationId`        | UUID     | Links to the installation.                              |
| `amount`                | decimal  | Total charged to the merchant (e.g. `9.99`).            |
| `commissionAmount`      | decimal  | Platform commission withheld (6%).                      |
| `developerAmount`       | decimal  | What the developer earned: `amount - commissionAmount`. |
| `currency`              | string   | ISO-4217 (default `USD`).                               |
| `type`                  | enum     | `subscription`, `one_time`, or `usage`.                 |
| `status`                | enum     | `pending`, `paid`, `refunded`, `failed`.                |
| `stripeInvoiceId`       | string   | Stripe `in_…` id (subscription / usage charges).        |
| `stripePaymentIntentId` | string   | Stripe `pi_…` id (one-time charges).                    |
| `billingPeriodStart`    | datetime | Start of the billed period (subscription / usage only). |
| `billingPeriodEnd`      | datetime | End of the billed period.                               |
| `createdAt`             | datetime | Row creation time = webhook-receipt time.               |
| `updatedAt`             | datetime | Last status change (e.g. `paid` → `refunded`).          |

### Example response

```json theme={null}
{
  "status": 200,
  "state": "success",
  "data": {
    "items": [
      {
        "transactionId": "8d4f1c10-3b6e-4e76-9b6a-1a17a5be58a0",
        "appId": "fb7c1c8b-8e1d-4f4e-a05c-1b8c5a3b9f02",
        "storeId": "f73049dc-b4d4-4f85-99c2-681a5e351a8a",
        "installationId": "5a0e8d2c-8c0e-4e26-9f70-3bd2bce29c11",
        "amount": "9.99",
        "commissionAmount": "0.60",
        "developerAmount": "9.39",
        "currency": "USD",
        "type": "subscription",
        "status": "paid",
        "stripeInvoiceId": "in_1OqW2NABC...",
        "stripePaymentIntentId": null,
        "billingPeriodStart": "2026-04-15T00:00:00.000Z",
        "billingPeriodEnd":   "2026-05-15T00:00:00.000Z",
        "createdAt": "2026-04-15T03:12:47.881Z",
        "updatedAt": "2026-04-15T03:12:49.012Z"
      }
    ],
    "pagination": { "page": 1, "limit": 50, "total": 7, "hasMore": false }
  }
}
```

***

## Get a transaction summary

`GET /apps/billing/transactions/summary` returns aggregated totals across
all of the merchant's app charges. Useful for dashboards.

```bash theme={null}
curl -X GET "https://api.launchmystore.io/apps/billing/transactions/summary" \
  -H "Authorization: Bearer <MERCHANT_JWT>"
```

```json theme={null}
{
  "status": 200,
  "data": {
    "totalSpent": 247.83,
    "totalCommission": 14.87,
    "totalToDevelopers": 232.96,
    "currency": "USD",
    "transactionCounts": {
      "paid": 23,
      "refunded": 1,
      "failed": 0,
      "pending": 0
    }
  }
}
```

<Note>
  `totalSpent`, `totalCommission`, and `totalToDevelopers` are reported in the
  merchant's default currency. Transactions originally booked in other
  currencies are converted at the FX rate at receipt time and the rate is
  frozen onto the row — re-running the summary later returns the same totals.
</Note>

***

## Get one transaction

There is no per-id endpoint. Filter the list call by `transactionId` if you
need a single row:

```bash theme={null}
curl -X GET "https://api.launchmystore.io/apps/billing/transactions?limit=1&transactionId=<UUID>" \
  -H "Authorization: Bearer <MERCHANT_JWT>"
```

***

## Refunds

Refunds are issued either through the Stripe Dashboard (manual ops) or
programmatically by the developer via the Stripe API. When Stripe fires
`charge.refunded`, the webhook handler:

1. Marks the transaction as `status: refunded`.
2. Inserts a negative ledger entry on the developer's earnings balance.
3. Fires `app/subscription/refunded` to the app.

The original transaction is **not** deleted — historical reporting stays
intact.

## Error codes

| Code  | Description                                                                       |
| ----- | --------------------------------------------------------------------------------- |
| `401` | Missing or invalid merchant JWT.                                                  |
| `403` | The merchant has no installed apps.                                               |
| `400` | Invalid `status` filter — must be one of `pending`, `paid`, `refunded`, `failed`. |
