Subscription
The Subscription entity (table core_api.subscriptions) records a SaaS subscription that a workspace-tracked company holds with an external software provider. Each row captures the commercial terms โ plan name, monthly recurring revenue, billing cadence, period dates, and optional trial/cancellation state โ and anchors the subscription to both a workspace (for tenant isolation) and a company (the subscriber). Subscriptions are written by the connector sync pipeline and the reconciliation layer; they are referenced by Invoice and InvoiceTransaction for revenue-recognition and reconciliation purposes.
| Naming | Value |
|---|---|
| Object | Subscription |
Resource type (JSON:API type) | subscription |
| Collection / records root | โ (not a records root) |
| REST base | /v1/subscriptions |
| Entity class | Subscription |
Internal object. Not currently exposed on the public REST API. The operations below describe the intended contract.
API operations
| Operation | Method & path | Status |
|---|---|---|
| List | GET /v1/subscriptions | ๐ก Planned |
| Retrieve | GET /v1/subscriptions/{id} | ๐ก Planned |
| Create | POST /v1/subscriptions | ๐ก Planned |
| Update | PATCH /v1/subscriptions/{id} | ๐ก Planned |
| Delete | DELETE /v1/subscriptions/{id} | ๐ก Planned |
Data model
Attributes
| Field | Type | Required | Constraints | Allowed values | Description |
|---|---|---|---|---|---|
| subscription_id | ๐ system โ UUID (string) | โ Yes | UNIQUE; default gen_random_uuid() | โ | Public-facing stable identifier for the subscription. Generated server-side on creation and never changed. |
| provider | string | โช No | max 255 chars; nullable | โ | Name of the billing provider or SaaS vendor (e.g. 'Stripe', 'Salesforce', 'HubSpot'). Populated by the connector sync when available; null when unknown. |
| plan_name | string | โ Yes | max 255 chars; NOT NULL | โ | Human-readable name of the subscription plan as surfaced by the provider (e.g. 'Business Pro', 'Enterprise Annual'). |
| mrr | decimal(12,2) stored as string | โ Yes | CHECK mrr >= 0; NOT NULL | โ | Monthly Recurring Revenue for this subscription, expressed in the subscription currency. For non-monthly intervals, this is the normalized monthly equivalent. |
| currency | enum (CurrencyCodeEnum via native DB enum currency_code_enum) | โ Yes | NOT NULL; nativeEnumName: currency_code_enum | ISO 4217 codes: USD, EUR, GBP, JPY, CHF, CAD, AUD, NZD โฆ +13 more | ISO 4217 currency code for the MRR amount and subscription pricing. |
| billing_interval | enum (BillingIntervalEnum via native DB enum billing_interval_enum) | โ Yes | NOT NULL; nativeEnumName: billing_interval_enum | monthly | quarterly | yearly | one_time | How frequently the subscription is billed. The stored value is the enum value string (e.g. 'monthly', 'one_time'). |
| current_period_start | date (ISO 8601 date string) | โ Yes | NOT NULL; columnType date | โ | Start date of the current billing period. |
| current_period_end | date (ISO 8601 date string) | โ Yes | NOT NULL; CHECK current_period_end >= current_period_start | โ | End date of the current billing period. Must be on or after current_period_start. |
| trial_start | date (ISO 8601 date string) | โช No | nullable; required when trial_end is set (CHECK trial_end IS NULL OR trial_start IS NOT NULL) | โ | Start date of the trial period. If trial_end is present, trial_start must also be present. |
| trial_end | date (ISO 8601 date string) | โช No | nullable; CHECK trial_end IS NULL OR trial_end >= trial_start | โ | End date of the trial period. Must be on or after trial_start when set. |
| canceled_at | timestamp (ISO 8601 datetime string) | โช No | nullable; columnType timestamptz | โ | Timestamp when the subscription was canceled. Null for active subscriptions. |
| renewal_date | date (ISO 8601 date string) | โช No | nullable; columnType date | โ | Next scheduled renewal date for the subscription. |
| created_at | ๐ system โ timestamp | โ Yes | set on create via @Property onCreate hook | โ | Server-assigned creation timestamp. Set once at insert; never updated. |
| updated_at | ๐ system โ timestamp | โช No | set on create and updated on every write via @Property onUpdate hook | โ | Server-assigned last-modification timestamp. Updated automatically by MikroORM on every flush. |
| deleted_at | ๐ system โ timestamp | โช No | nullable; soft-delete sentinel โ all live queries filter deleted_at IS NULL | โ | Soft-delete timestamp. When set, the subscription is logically deleted. The Hasura RLS and DataViewsService both gate on this column. |
Relationships
| Name | Type | Required | Description |
|---|---|---|---|
| workspace | to-one (ManyToOne) | โ Yes | The workspace this subscription belongs to. Primary tenant-isolation anchor; every query must filter by this relationship. References core_api.workspaces. |
| company | to-one (ManyToOne) | โ Yes | The company (customer or vendor) that holds this subscription. Used to surface the subscription in the companies composite list and for reconciliation joins. References core_api.companies. |
System-computed
- subscription_id โ generated by gen_random_uuid() on insert; also initialized client-side via randomUUID() as a JS default but the DB default is authoritative
- created_at โ set by @Property onCreate: () => new Date() on first flush
- updated_at โ set by @Property onCreate and refreshed by @Property onUpdate: () => new Date() on every subsequent flush
- deleted_at โ soft-delete sentinel written by the delete service path; never set to null once assigned; Hasura RLS and DataViewsService inject a 'deleted_at IS NULL' predicate automatically when rootHasColumn returns true
- Composite index (workspace, company) โ defined via @Index({ properties: ['workspace', 'company'] }) for the common Hasura user-permission query path
- Additional index (workspace_pk, deleted_at) โ added by Migration20260415130000 to cover the Hasura soft-delete scoped tenant lookup pattern
- All domain data (provider, plan_name, mrr, billing_interval, period dates) is written by the connector sync pipeline or reconciliation layer; there is no user-facing PATCH endpoint for this entity
Example
{
"data": {
"type": "subscription",
"id": "a3b7e1f2-9c44-4e8d-8b12-3d7f5a2e1c09",
"attributes": {
"subscription_id": "a3b7e1f2-9c44-4e8d-8b12-3d7f5a2e1c09",
"provider": "Stripe",
"plan_name": "Business Pro",
"mrr": "299.00",
"currency": "EUR",
"billing_interval": "monthly",
"current_period_start": "2026-05-01",
"current_period_end": "2026-05-31",
"trial_start": null,
"trial_end": null,
"canceled_at": null,
"renewal_date": "2026-06-01",
"created_at": "2026-04-28T14:32:00.000Z",
"updated_at": "2026-05-01T00:00:00.000Z",
"deleted_at": null
},
"relationships": {
"workspace": {
"data": { "type": "workspace", "id": "wks_uuid_here" }
},
"company": {
"data": { "type": "company", "id": "cmp_uuid_here" }
}
}
}
}apps/api/src/database/entities/Subscription.ts ยท domain: workspace ยท tier: Platform