# Usage periods

Source: https://docs.orbytelabs.com/usage-periods

Charge a wallet or entity once per day, week, month, or billing period.

Set a feature's `deduplicationPeriod` to charge its first use in a period. Later uses record zero-charge transactions. This works for monthly active resources, daily access fees, or other usage you want to count once per period.

Periods control which usage is charged. They do not schedule payments, issue invoices, reset a balance, or add credits.

## Choose a period [#choose-a-period]

| Value               | Charges                                    |
| ------------------- | ------------------------------------------ |
| `none`, the default | Every event.                               |
| `day`               | Once per UTC calendar day.                 |
| `week`              | Once per UTC week, starting Monday.        |
| `month`             | Once per UTC calendar month.               |
| `billing`           | Once per configured wallet billing period. |

For example, this configuration charges two credits for each resource's first use of the month:

```ts title="orbyte.config.ts"
import { credit, feature, Orbit } from "@orbytelabs/credit";

export const credits = credit("credits", "Credits");

export default Orbit({
  features: {
    "active-resource": feature("Active resource", "resource", credits(2), {
      deduplicationPeriod: "month",
    }),
  },
});
```

Deploy the configuration before sending usage. Each event must have quantity 1, which is the default. A proportional price such as `credits.per(5, 1_000)` is still allowed; its first eligible event costs 0.005 credits.

## Count resources within a shared wallet [#count-resources-within-a-shared-wallet]

If an organization pays for several resources, use its identity as the paying wallet and `entityId` for the resource:

```ts
import { check, track } from "@orbytelabs/credit";

const identity = "organization_456";
const entityId = "resource_123";

const access = await check("active-resource", identity, { entityId });
if (!access.allowed) throw new Error("Not enough credits.");

await track("active-resource", identity, {
  id: "activity_789:active-resource",
  entityId,
});
```

Deduplication uses the feature, paying wallet, entity ID, and period. Each resource gets its own first charge. Omit `entityId` to count the paying wallet itself.

An entity ID must contain 1 to 200 characters after trimming. It is only accepted for period features. Use one convention consistently; adding or removing an entity ID changes what Credit counts.

## Repeated uses and retries [#repeated-uses-and-retries]

Give every distinct use its own event ID. Credit derives the period key, so you do not need to encode the month into the event ID.

The first eligible event returns `accepted`. Another event for the same wallet or entity in that period returns `deduplicated`, a zero amount, and `deduplicatedFrom` pointing to the original transaction. Retrying either event with the same ID and payload returns `duplicate` and its original transaction.

Both checks and events include `periodStart` and `periodEnd` as Unix timestamps in milliseconds. Once the period has been charged, `check` returns a zero charge for the same scope, even if the wallet balance is empty.

## Wallet billing periods [#wallet-billing-periods]

Use `deduplicationPeriod: "billing"` when the cycle starts on a customer-specific date. Configure the wallet before its first billing-period check or event:

```ts
import { OrbyteClient } from "@orbytelabs/credit";

const client = new OrbyteClient();

await client.setBillingPeriod("customer_123", {
  interval: "month",
  anchor: Date.UTC(2026, 8, 15),
});
```

The example anchors the cycle on September 15, 2026 at 00:00 UTC. JavaScript month indexes start at zero. The call requires `wallets:write` and creates the wallet if it does not exist.

Supported intervals are `day`, `week`, and `month`. Daily and weekly intervals start at the anchor's time. A monthly anchor on the 31st uses the last day of shorter months, then returns to the 31st when available. The start is inclusive and the end is exclusive.

A billing-period check or event fails if the wallet has no billing period or its anchor is still in the future.

## Arrival time [#arrival-time]

Credit uses server processing time to choose the period. The API does not accept a custom event timestamp. A first submission that arrives late belongs to the period when it arrives.

An identical retry of a previously accepted event returns its original transaction, even after the next period begins. A check and a later track can fall in different periods, so the eventual charge can differ from the check.

## Changing period settings [#changing-period-settings]

The feature's deduplication period becomes locked after its first accepted period event, including a zero-price event. After that, changing the period returns `409 conflict`; create a new feature key for a different policy. Price and label edits remain available.

The wallet's billing interval and anchor also become locked after the first accepted event that uses them. Sending the same settings again is allowed. Checks and rejected charges do not lock these settings.

Read `deduplicationLocked` on a feature or `billingPeriodLocked` on a wallet to see its current state. See the [API reference](/api) for the response schemas.