syrup-rail 0.2.1

Validated domain types and lifecycle policy for Syrup Rail billing
Documentation

syrup-rail

syrup-rail contains the provider-independent domain types and lifecycle policy for Syrup Rail billing. It validates subscription terms, snapshots paid trial and recurring authority, models dunning and terminal nonpayment, exposes canonical entitlement decisions, and defines the gateway and host-admission ports used by the adapter crates.

[dependencies]
syrup-rail = "0.2.0"

Construct subscription offers from explicit start, recurring, and failure terms. Dunning delays are relative to the preceding submitted determinate automatic-renewal failure:

use syrup_rail::{
    ChargeAmount, CurrencyCode, DunningExhaustion, DunningRetryDelay,
    DunningSchedule, PastDueAccessPolicy, PlanKey, RecurringSubscriptionTerms,
    RenewalFailurePolicy, SubscriptionOffer, SubscriptionPeriodRule,
    SubscriptionStart,
};

let usd = CurrencyCode::new("USD")?;
let offer = SubscriptionOffer::new(
    PlanKey::new("base_subscription")?,
    RecurringSubscriptionTerms::new(
        ChargeAmount::new(1_000, usd)?,
        SubscriptionPeriodRule::calendar_months(1)?,
    ),
    SubscriptionStart::RecurringImmediately,
    RenewalFailurePolicy::new(
        DunningSchedule::from_delays([
            DunningRetryDelay::days(1)?,
            DunningRetryDelay::days(3)?,
        ])?,
        DunningExhaustion::MarkUnpaid,
        PastDueAccessPolicy::ContinueUntilDunningExhausted,
    ),
)?;
# let _ = offer;
# Ok::<(), Box<dyn std::error::Error>>(())

Use Entitlement::permits_product_access() for the canonical product-access decision. A past_due payment state does not by itself imply suspended access. For BillingEvent::SubscriptionPaymentFailed, consume the event's typed access outcome rather than rebuilding it from current offer configuration.

Use PaymentCardBrand for customer-facing or host-event card presentation. PaymentCardBrand::from_provider maps recognized provider values into a stable vocabulary and reduces unknown nonempty text to Other, so arbitrary provider strings do not cross that projection boundary. Its aliases include the documented NMI diners label for DinersClub; provider adapters retain exact evidence and test their own documented scheme vocabulary.

SubscriptionPaymentMethodDisplay cannot represent an all-empty display. Its persisted/provider-parts conversion normalizes first and returns None when no renderable field remains.

Syrup Rail does not authenticate subscribers, persist gateway credentials, or define a transport wire format for billing events. Those remain host responsibilities. See the workspace subscription_terms, entitlement_access, and PostgreSQL host_integration examples for complete integration patterns.

This package is proprietary software distributed under the terms in the packaged LICENSE file.