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

# Trial & shared-pool number model

> How trial numbers really work — the single lifetime claim per organization, the fixed 24-hour lease, the 50-message daily send cap, purchase-to-keep versus release-back, the one-hour inbound grace period after release, and where this family differs from the aging and porting flows.

# Trial & shared-pool number model

A trial number is a lease from a shared platform pool, not a purchase. You
claim one free number, use it for a fixed 24 hours, and then either pay to
keep it or let it return to the pool for the next organization. The API
operations (claim, read, purchase, release) are documented endpoint-by-endpoint
in [Number lifecycle](/numbers/lifecycle#trial--shared-pool-numbers); this page
is the concept-level model behind them — the caps, the timers, and the
guarantees. The status vocabulary for purchased numbers lives in [Number status
map](/concepts/number-lifecycle).

## The lifetime claim: one free trial per organization, ever

Every organization gets exactly **one** free trial claim in its lifetime. The
enforcement is a `COUNT(*)` over all of the organization's pool assignments —
active, expired, or released — with **no rolling time window**
(`apps/api/src/routes/numbers/number-pool.service.ts:40-48`). Once the count
reaches one, a further claim returns `429`:

```json theme={null}
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "You have already used your one free trial number. Please purchase a dedicated number."
  }
}
```

Because the lifetime rule rejects the click anyway, `GET /numbers/trial`
carries a `meta.ever_claimed` flag: `true` once the organization's one claim
has been spent, whether or not an assignment is currently active. Clients use
it to stop offering the "Claim a trial number" action instead of discovering
the 429 at click time.

Claiming also presumes you own nothing yet: an organization that already holds
purchased numbers (any status other than released) is pointed at a regular
purchase instead — the free trial exists for accounts with no numbers of their
own.

## The 24-hour lease and the expiry scheduler

A claim stamps the assignment with an `expiresAt` exactly **24 hours** after
claim (`TRIAL_DURATION_HOURS = 24` in
`apps/api/src/routes/numbers/number-pool.service.ts:34`). The lease is fixed:
there is no extension, renewal, or longer paid hold. `GET /numbers/trial`
returns the assignment only while it is unexpired; past `expiresAt` it reads
`null` even before cleanup runs.

The actual reclamation is asynchronous. A scheduler sweeps every 30 minutes
(`POOL_NUMBER_RELEASE_POLL_MS` in `apps/webhook-worker/src/worker.ts:1467`),
running `releaseExpiredPoolNumbers`
(`apps/webhook-worker/src/scheduler-pool-numbers.ts`). Each pass:

1. Marks every assignment whose `expiresAt` has passed as released.
2. Returns the number to the shared pool and clears the previous owner, so the
   next claimant sees clean, unowned inventory.
3. Removes the prior organization's inbound routing for the number, so no
   configuration carries to the next claimant.

So expiry is honored within about half an hour of the 24-hour mark, and the
leased digits become claimable by someone else.

## The daily send cap: 50 messages per day

While the lease is active, sends routed through the trial number are capped
at **50 outbound messages per day** (`TRIAL_DAILY_SEND_LIMIT = 50` in
`apps/api/src/routes/numbers/number-pool.service.ts:48`) — a spam-control
ceiling on free inventory. The counter spans the trailing 24 hours of outbound
messages from that number and resets as the window rolls. Reaching the cap
rejects further sends from the trial until the window drains; inbound traffic
is unaffected.

## Purchase to keep, or release back

Two endpoints decide the number's fate:

* **`POST /numbers/purchase-trial`** is the only way to keep a trial number
  past expiry. It promotes the same digits into your owned inventory as an
  `active` number, ends the pool assignment, and — when the number carries a
  monthly rental — enrolls it in the recurring-billing cycle. It is also the
  one rate-limited write path shared with claim: claim and purchase are
  limited to 5 requests per minute per tenant.
* **`DELETE /numbers/release-trial`** ends the lease early and returns the
  number to the shared pool immediately, rather than waiting for the expiry
  sweep.

Nothing else keeps a trial alive. When the 24 hours lapse without a purchase,
the scheduler reclaims the number as above, and your one lifetime claim is
spent either way.

## The one-hour inbound grace period

A recipient's reply can arrive moments after you released the number or the
lease expired. To keep that reply from falling into a routeless void, inbound
resolution first looks for an active assignment and then falls back to any
assignment released within the last **hour** (`INBOUND_GRACE_PERIOD_MS` in
`apps/api/src/routes/numbers/number-pool.service.ts:51`). Late-arriving replies
in that window still resolve to you, the prior owner. Once the hour closes —
or a new claimant takes the number — inbound routes to the current owner, and
the released-lease history stops matching.

## Worked flow: claim, send, keep or lose

```
claim ──▶ active lease (24 h; ≤ 50 outbound sends/day)
   │
   ├── at hour ~20: POST /numbers/purchase-trial ──▶ owned, active number
   │
   └── no purchase: expiresAt passes ──▶ scheduler sweep (≤ 30 min)
             reclaims it ──▶ shared pool ──▶ claimable by another org
                   (inbound replies still reach you for 1 h post-release)
```

1. **Claim.** `POST /numbers/claim-trial` — accepted while your lifetime count
   is zero and you hold no purchased numbers (claim/purchase together are
   rate-limited to 5 requests/min per tenant).
2. **Use.** Send up to 50 messages a day, receive inbound, exercise your
   routing. `GET /numbers/trial` reports the assignment and its `expiresAt`.
3. **Decide.** Purchase before hour 24 to keep the digits — after purchase the
   daily cap no longer applies. Miss the window and the next scheduler sweep
   returns the number to the pool; additional claims then 429 against the
   lifetime rule.

## What this is not

* **Not the aging/reuse flow.** The 30/45/90-day parking window, reclaim, and
  carrier cooldown in [Number reuse, aging, and post-release
  posture](/concepts/number-reuse-and-aging) govern **purchased** DIDs you
  release. A trial number never enters that pipeline: it goes straight back
  to the shared pool on release or expiry, and the 24-hour lease has no
  parking grace. One hour of inbound grace is the entire buffer.
* **Not a port.** Porting moves a number between carriers. Trial DIDs are
  platform-owned inventory leased to you; the port-out model ([Port-out
  lifecycle and ownership](/concepts/number-port-out-model)) applies only once
  you have purchased the number into your inventory.
* **Not a subscription.** A purchased trial number becomes ordinary owned
  inventory; from then on the standard [billing and renewal
  model](/concepts/billing-and-numbers-renewal-model) applies.

## Tenant-visible guarantees

1. **Exactly one free claim, enforced permanently.** The lifetime count spans
   every assignment your organization ever held; there is no reset.
2. **Fixed expiry with bound lag.** The lease lasts 24 hours, and the
   30-minute sweep reclaims promptly — your `expiresAt` is a hard horizon, not
   a suggestion.
3. **A capped free channel.** At most 50 outbound sends per rolling day from a
   trial number; inbound is uncapped.
4. **Only purchase preserves.** There is no renew or extend path; releasing or
   expiring always returns the digits to the pool.
5. **Late inbound is buffered.** One hour after release, replies from the
   lease window still resolve to you rather than erroring or leaking to the
   next claimant.
6. **No lease state follows the next claimant.** Expiry and release both clear
   ownership and remove your inbound routing before the number is claimable
   again.

## See also

* [Number lifecycle](/numbers/lifecycle#trial--shared-pool-numbers) — the four
  trial operations, request by request
* [Number status map](/concepts/number-lifecycle) — the six-state vocabulary
  purchased numbers move through
* [Number reuse, aging, and post-release
  posture](/concepts/number-reuse-and-aging) — the parking/aging model for
  purchased DIDs
* [Port-out lifecycle and ownership
  model](/concepts/number-port-out-model) — moving a purchased number to
  another carrier
* [Billing and numbers renewal
  model](/concepts/billing-and-numbers-renewal-model) — the rental cycle a
  kept trial number joins
