Set up the trial
Register custom-field keys (once)
Custom fields are how you mark a contract or credit as a trial, so that alerts, webhooks, and reports can tell trials apart from everything else a customer holds. Register each key once per environment before anything references it.Create the customer
Create the trial contract — expiring credit
$100 of credit, valid 14 days, scoped to the products carrying theLanguage models product tag, and burned before anything else the customer holds (priority: 1).
overrides[] entry with "entitled": false for those product tags.
The trial ends as soon as either limit is reached: the balance hits 0, or the access schedule reaches its ending_before date. If any balance is left when the schedule ends, Metronome expires the remainder and records an expiration entry on the credit’s ledger. That entry does not affect revenue, unlike the expiration of a prepaid commit — see revenue recognition for how each is treated.
Note that the contract above has no end date, and only the credit is time-bounded. When the credit expires the contract carries on and usage is rated at your list prices, so the customer lands on pay-as-you-go with no further action from you. Create a separate paid contract with a transition when the paid terms differ from the trial contract’s, such as a different rate card, a prepaid commit, or a recurring free tier. The reference architecture covers the trade-off between the two shapes.
To build one of the other patterns, start from the request above and change it as follows:
-
Skew toward time. Keep a modest amount and push
ending_beforefurther out, for products where adoption ramps slowly. Every access-schedule segment requires anending_before, so a credit that never expires isn’t possible. - Effectively unlimited. Grant far more than a trial customer could plausibly consume and keep the window short. The customer never meets the cap, and you still get balance tracking, alerts, and a complete drawdown record to learn from.
-
Quantity-based instead of spend-based. Denominate the credit in a custom pricing unit rather than a currency by setting
credit_type_idto that unit. The trial then grants an amount of units, such as tokens or requests, instead of dollars. -
Time-only, uncapped. Remove the
creditsarray and add a time-bounded zero multiplier in its place:Because there is no credit, this model produces no balance alerts and nocredit.segment.endevent. The override’s end date is your only trial-end signal. To limit exposure after the trial, consider a spend threshold on the paid contract. -
Reverse trial. Keep the trial credit as-is, and add a
recurring_credits[]item to the paid contract you renew into, so conversion lands the customer on a small permanent allowance. See recurring free tier.
Alerts
Threshold alerts are evaluated per customer, so create each one once and leave outcustomer_id to have it apply to everyone. Use alert_specifiers to evaluate only trial-tagged credits. Set a uniqueness_key so that retrying a request doesn’t create a duplicate alert.
evaluate_on_create: falseskips only the initial evaluation. An alert that applies to all customers still fires for existing ones the next time their state changes.- The days-remaining alert fires as soon as you create it if the trial is shorter than its threshold.
alert_specifierscontrols which credits are evaluated, but it is not echoed back in the webhook payload. Validentityvalues areContract,Commit,ContractCredit, andContractCreditOrCommit. Usinggroup_key_filteror per-key grouped specifiers requires account enablement, so contact Metronome support if you need them.
Handle the webhooks
Enable thecredit.segment.start, credit.segment.end, credit.archive, and contract.end system notifications and point them at your webhook endpoint.
Example payload:
contract_id, or environment_type, so look the credit up through the API when you need those. Of the three alerts, only the days-remaining one includes a credit_id, and only it has no timestamp. triggered_by names the evaluation trigger rather than the reason the threshold was crossed, so don’t branch on it.
Convert to paid
Create the paid contract with a transition from the trial contract.starting_at must be hour-aligned, and it is the instant the trial ends.
- The trial contract’s
ending_beforeis set to the paid contract’sstarting_at, leaving no gap and no overlap. - The trial credit is truncated to that instant and any unused balance expires. The ledger records a deduction for consumed usage and an expiration entry for the remainder, both stamped at the transition time. Nothing rolls over unless you set
rollover_fraction. - Accrued trial usage is re-dated from the billing-period boundary to the transition instant, then invoiced once the grace period ends and the invoice finalizes.
- You receive
contract.editwhen the paid contract is created, followed bycredit.segment.endandcontract.endat the transition instant. - Both contracts return the same
transitions[]entry, holdingtype,from_contract_id, andto_contract_id. It has no timestamp, so read the effective time fromcontracts_transitions.datein Data Export.
End a trial early
You might need to end a trial before its window closes: the customer converts ahead of schedule and you don’t want free credit burning alongside paid usage, sales renegotiates the evaluation period, or a trial is being misused and you want to shut off the allowance. The cleanest way to do it is to truncate the credit’s access schedule. The credit keeps its ledger, Metronome emitscredit.segment.end, and the $0 balance alert fires shortly afterward. Set ending_before to an hour boundary at or after the segment’s starting_at; a zero-length segment is accepted and expires the full balance immediately.
update_credits[] identifies the credit with credit_id while the nested schedule item uses id. Both values come from POST /v1/contracts/customerBalances/list.
Recurring free tier
A recurring credit grants an allowance that refreshes every period, which suits both a permanent free tier and the landing state of a reverse trial. This example grants $10 of usage a month on a perpetual contract, with no rollover.recurrence_frequency is an enum string, and recurring credits do not accept custom_fields.
recurring_credit_id, which webhook payloads call parent_recurring_credit_id. Setting recurrence_frequency explicitly anchors each period to the credit’s own starting_at, which means a period can reset partway through a billing period. Omit it to follow the contract’s usage statement schedule instead.
Alerts mean something different on this model. A $0 or percentage-remaining alert now tells you that this period’s allowance is used up, which is a monthly throttling signal rather than the end of a trial, so keep a separate alert configuration for each model.
Prepaid landing with a payment gate
For a “buy $20 before you continue” conversion, add a payment-gated prepaid commit to the paid contract. Metronome creates the invoice immediately and releases the commit once payment succeeds. See that guide for the billing-provider setup and the rest of the requirements.Behavior reference
How each trial-end path shows up
The $0 balance alert is a usage signal. Threshold notifications are evaluated when usage is ingested and when customer metadata changes, so a credit that reaches its end date with unused balance does not produce one. Use
credit.segment.end to detect a trial that ends on schedule, and keep the $0 alert for trials exhausted by usage.
Payload differences between the two notification families
Things that are easy to get backwards
- The percentage alert’s
thresholdis the percentage remaining, so a threshold of 25 fires when 25% is left. - Ledger entry types are named differently in each surface:
CREDIT_EXPIRATIONin the API iscredit_segment_expirationin Data Export and in-app reports. See the database reference for the full mapping. - Usage drawdown appears as a single deduction entry per invoice, dated at the end of the service period and rewritten in place, so don’t use the ledger to date individual usage.
- An invoice’s
issued_atis its nominal date, while finalization happens after the grace period.