> For the complete documentation index, see [llms.txt](https://developers.share.inc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.share.inc/api-reference/subscriptions.md).

# Subscriptions

A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.

## List subscriptions

> Returns the paginated set of subscriptions owned by the authenticated provider, with optional filtering by subscriber and status.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"SubscriptionResponseDto":{"properties":{"createdAt":{"format":"date-time","type":"string"},"demarcationPointId":{"format":"uuid","type":"object"},"expiresAt":{"format":"date-time","type":"string"},"gracePeriodDaysOverride":{"description":"Per-subscription grace period in days (renewal cycles only), overriding the plan grace period for this subscription. `null` when not set — the subscription uses the plan grace period.","maximum":30,"minimum":0,"nullable":true,"type":"object"},"id":{"format":"uuid","type":"string"},"inactiveReason":{"enum":["GRACE_EXPIRED","ADMIN_DEACTIVATED","PLAN_REMOVED","NO_PLAN_ASSIGNED","PLAN_DISABLED","ACTIVATION_GRACE_EXPIRED"],"type":"string"},"inactiveReasonNote":{"description":"Operator-supplied free-text rationale paired with `inactiveReason`. Persisted on the subscription when set during deactivation.","type":"object"},"isExternal":{"description":"True when the subscription is managed by an external BSS.","type":"boolean"},"name":{"description":"Subscription label set from the originating external service name (Splynx internet-service description). Populated for the current/non-Share migration subscription (which has no plan); null for Share-native subscriptions.","type":"object"},"nextPlanId":{"description":"Queued plan ID (set on plan-change-queued or migration-pending).","format":"uuid","type":"object"},"nextPlanName":{"type":"object"},"override":{"allOf":[{"$ref":"#/components/schemas/SubscriptionPricingOverrideResponseDto"}],"description":"Active and queued per-subscription pricing override. Populated on the detail endpoint (`GET /v1/subscriptions/:id`); the list endpoint always returns `null` here. `null` when no override has been applied."},"planId":{"format":"uuid","type":"object"},"planName":{"description":"Human-readable plan label","type":"object"},"pppoePassword":{"description":"PPPoE password on the subscriber CPE","type":"object"},"pppoeUsername":{"description":"PPPoE username on the subscriber CPE","type":"object"},"scheduledCancellationAt":{"description":"Finalize date when the subscription is scheduled for cancellation (set by `POST /v1/subscriptions/:id/deactivate`); `null` when not scheduled. Presence means \"scheduled for cancellation\": the subscription stays `ACTIVE` and keeps internet until the billing finalize cron archives it at/after this date. Cleared by `POST /v1/subscriptions/:id/cancel-scheduled-cancellation`.","format":"date-time","type":"object"},"serviceHandle":{"description":"Stable 13-digit handle derived from a per-subscription sequence and the provider country code. Read-only and deterministic — safe to expose in support tooling and partner integrations.","pattern":"^\\d{13}$","type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"enum":["PENDING","SCHEDULED","ACTIVE","EXPIRED","SUSPENDED","AWAITING_PAYMENT_FOR_UPGRADE","INACTIVE","ARCHIVED"],"type":"string"},"subscriberId":{"format":"uuid","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"wasMigrated":{"description":"True when this subscriber was carried over from a legacy BSS during platform migration.","type":"boolean"}},"required":["id","serviceHandle","subscriberId","status","isExternal","wasMigrated","startedAt","expiresAt","createdAt","updatedAt"],"type":"object"},"SubscriptionPricingOverrideResponseDto":{"properties":{"authorizedBy":{"description":"Identifier of the user that authorized the override.","format":"uuid","type":"object"},"createdAt":{"format":"date-time","type":"string"},"durationOverride":{"description":"Active duration override in days; overrides the plan duration.","type":"object"},"expiresAt":{"description":"Optional expiry — after this point the override is treated as cleared.","format":"date-time","type":"object"},"nextDurationOverride":{"description":"Queued duration override in days — promoted to the active value at the next renewal.","type":"object"},"nextPriceOverride":{"description":"Queued price override — promoted to the active value at the next renewal.","type":"object"},"nextSpeedOverride":{"description":"Queued speed override in Mbps — promoted to the active value at the next renewal.","type":"object"},"priceOverride":{"description":"Active price override; overrides the plan price.","type":"object"},"reason":{"description":"Operator-supplied rationale for the override.","type":"object"},"speedOverride":{"description":"Active speed override in Mbps; overrides the plan speed.","type":"object"},"updatedAt":{"format":"date-time","type":"string"}},"required":["createdAt","updatedAt"],"type":"object"}}},"paths":{"/v1/subscriptions":{"get":{"description":"Returns the paginated set of subscriptions owned by the authenticated provider, with optional filtering by subscriber and status.","operationId":"SubscriptionsController_listSubscriptions_v1","parameters":[{"description":"1-based page number. Defaults to 1 when omitted.","in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"number"}},{"description":"Number of items per page. Capped at 100 server-side. Defaults to 20 when omitted.","in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":100,"minimum":1,"type":"number"}},{"description":"Filter to subscriptions owned by this subscriber.","in":"query","name":"subscriberId","required":false,"schema":{"format":"uuid","type":"string"}},{"description":"Filter by `Subscription.status`. Omit to include every status.","in":"query","name":"status","required":false,"schema":{"enum":["PENDING","SCHEDULED","ACTIVE","EXPIRED","SUSPENDED","AWAITING_PAYMENT_FOR_UPGRADE","INACTIVE","ARCHIVED"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/SubscriptionResponseDto"},"type":"array"},"success":{"type":"boolean"}}}]}}},"description":"Paginated list of subscriptions."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"List subscriptions","tags":["Subscriptions"]}}}}
```

## Create a subscription

> Creates a subscription on an existing subscriber with a Share \`planId\`. A CPE record capturing \`demarcationPointId\` is always written. When PPPoE credentials are supplied, the subscription is prepared for installer activation.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"CreateSubscriptionRequestDto":{"properties":{"demarcationPointId":{"description":"Demarcation-point UUID where the CPE will be installed. Captured on the CPE record at creation time so the installer can plan the field visit.","format":"uuid","type":"string"},"gracePeriodDaysOverride":{"description":"Optional per-subscription grace period in days (renewal cycles only). Overrides the plan grace period for this one subscription — unpaid renewal cycles stay live in RADIUS this many days past the due date. Omit to use the plan default.","maximum":30,"minimum":0,"type":"number"},"installation":{"allOf":[{"$ref":"#/components/schemas/CreateSubscriptionInstallationDto"}],"description":"Optional installation requirement. When provided with `required=true`, an installation record is created together with the subscription."},"planId":{"description":"Active Share Plan ID to assign to the subscription.","format":"uuid","type":"string"},"pppoePassword":{"description":"PPPoE password. Stored alongside `pppoeUsername` on the CPE record.","type":"string"},"pppoeUsername":{"description":"PPPoE username. When supplied together with `pppoePassword`, the credentials are stored on the CPE record. The RADIUS push is driven by the installation workflow.","type":"string"},"subscriberId":{"description":"Share subscriber UUID the subscription belongs to.","format":"uuid","type":"string"}},"required":["subscriberId","planId","demarcationPointId"],"type":"object"},"CreateSubscriptionInstallationDto":{"properties":{"fee":{"description":"Installation fee. Defaults to the plan-level installation fee when omitted.","type":"number"},"free":{"default":false,"description":"When true, the installation is recorded as free of charge — no one-time installation charge is created.","type":"boolean"},"kind":{"default":"INITIAL","description":"Installation kind. Defaults to `INITIAL`.","enum":["INITIAL","REPLACEMENT","RELOCATION"],"type":"string"},"required":{"description":"When true, an installation record is created and linked to the new subscription.","type":"boolean"}},"required":["required"],"type":"object"},"ApiResponseDto":{"properties":{},"type":"object"},"SubscriptionResponseDto":{"properties":{"createdAt":{"format":"date-time","type":"string"},"demarcationPointId":{"format":"uuid","type":"object"},"expiresAt":{"format":"date-time","type":"string"},"gracePeriodDaysOverride":{"description":"Per-subscription grace period in days (renewal cycles only), overriding the plan grace period for this subscription. `null` when not set — the subscription uses the plan grace period.","maximum":30,"minimum":0,"nullable":true,"type":"object"},"id":{"format":"uuid","type":"string"},"inactiveReason":{"enum":["GRACE_EXPIRED","ADMIN_DEACTIVATED","PLAN_REMOVED","NO_PLAN_ASSIGNED","PLAN_DISABLED","ACTIVATION_GRACE_EXPIRED"],"type":"string"},"inactiveReasonNote":{"description":"Operator-supplied free-text rationale paired with `inactiveReason`. Persisted on the subscription when set during deactivation.","type":"object"},"isExternal":{"description":"True when the subscription is managed by an external BSS.","type":"boolean"},"name":{"description":"Subscription label set from the originating external service name (Splynx internet-service description). Populated for the current/non-Share migration subscription (which has no plan); null for Share-native subscriptions.","type":"object"},"nextPlanId":{"description":"Queued plan ID (set on plan-change-queued or migration-pending).","format":"uuid","type":"object"},"nextPlanName":{"type":"object"},"override":{"allOf":[{"$ref":"#/components/schemas/SubscriptionPricingOverrideResponseDto"}],"description":"Active and queued per-subscription pricing override. Populated on the detail endpoint (`GET /v1/subscriptions/:id`); the list endpoint always returns `null` here. `null` when no override has been applied."},"planId":{"format":"uuid","type":"object"},"planName":{"description":"Human-readable plan label","type":"object"},"pppoePassword":{"description":"PPPoE password on the subscriber CPE","type":"object"},"pppoeUsername":{"description":"PPPoE username on the subscriber CPE","type":"object"},"scheduledCancellationAt":{"description":"Finalize date when the subscription is scheduled for cancellation (set by `POST /v1/subscriptions/:id/deactivate`); `null` when not scheduled. Presence means \"scheduled for cancellation\": the subscription stays `ACTIVE` and keeps internet until the billing finalize cron archives it at/after this date. Cleared by `POST /v1/subscriptions/:id/cancel-scheduled-cancellation`.","format":"date-time","type":"object"},"serviceHandle":{"description":"Stable 13-digit handle derived from a per-subscription sequence and the provider country code. Read-only and deterministic — safe to expose in support tooling and partner integrations.","pattern":"^\\d{13}$","type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"enum":["PENDING","SCHEDULED","ACTIVE","EXPIRED","SUSPENDED","AWAITING_PAYMENT_FOR_UPGRADE","INACTIVE","ARCHIVED"],"type":"string"},"subscriberId":{"format":"uuid","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"wasMigrated":{"description":"True when this subscriber was carried over from a legacy BSS during platform migration.","type":"boolean"}},"required":["id","serviceHandle","subscriberId","status","isExternal","wasMigrated","startedAt","expiresAt","createdAt","updatedAt"],"type":"object"},"SubscriptionPricingOverrideResponseDto":{"properties":{"authorizedBy":{"description":"Identifier of the user that authorized the override.","format":"uuid","type":"object"},"createdAt":{"format":"date-time","type":"string"},"durationOverride":{"description":"Active duration override in days; overrides the plan duration.","type":"object"},"expiresAt":{"description":"Optional expiry — after this point the override is treated as cleared.","format":"date-time","type":"object"},"nextDurationOverride":{"description":"Queued duration override in days — promoted to the active value at the next renewal.","type":"object"},"nextPriceOverride":{"description":"Queued price override — promoted to the active value at the next renewal.","type":"object"},"nextSpeedOverride":{"description":"Queued speed override in Mbps — promoted to the active value at the next renewal.","type":"object"},"priceOverride":{"description":"Active price override; overrides the plan price.","type":"object"},"reason":{"description":"Operator-supplied rationale for the override.","type":"object"},"speedOverride":{"description":"Active speed override in Mbps; overrides the plan speed.","type":"object"},"updatedAt":{"format":"date-time","type":"string"}},"required":["createdAt","updatedAt"],"type":"object"}}},"paths":{"/v1/subscriptions":{"post":{"description":"Creates a subscription on an existing subscriber with a Share `planId`. A CPE record capturing `demarcationPointId` is always written. When PPPoE credentials are supplied, the subscription is prepared for installer activation.","operationId":"SubscriptionsController_createSubscription_v1","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubscriptionRequestDto"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SubscriptionResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"The newly created subscription."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Create a subscription","tags":["Subscriptions"]}}}}
```

## Migrate an external service onto a Share plan

> Onboards an external (non-Share) service onto a target Share \`planId\` for an existing subscriber, honoring the external cutover date and producing the two-subscription model — \*\*per service\*\*, so a subscriber can be migrated for N concurrent services via distinct \`externalServiceId\`s. This endpoint makes no calls to the partner BSS.\
> \
> \*\*Variants:\*\*\
> \- \`free = true\` (free-immediate): the external subscription is archived now and the Share plan activates immediately with a zero-amount PAID lead-in \`\[now, endBillingCycleDate]\`; the payable cycle opens at renewal. \`installation\` is rejected.\
> \- \`free = false\` (scheduled, default): the external subscription stays live with an informative cycle until \`endBillingCycleDate\`, and a SCHEDULED payable successor activates at that cutover. Supply \`installation\` (\`kind\` defaults \`REPLACEMENT\`) to gate full-speed access behind an install at cutover.\
> \
> A missing \`demarcationPointId\` leaves the successor stranded (RADIUS is skipped). Replay on \`(subscriberId, externalServiceId)\` is idempotent — the existing rows are returned.\
> \
> \*\*Error codes:\*\* \`FREE\_INSTALLATION\_CONFLICT\` (422) — \`free = true\` combined with \`installation\`; \`END\_DATE\_NOT\_FUTURE\` (422) — \`endBillingCycleDate\` is not in the future; \`NOT\_FOUND\` (404) — the subscriber does not exist under the authenticated provider.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"MigrateSubscriptionRequestDto":{"properties":{"demarcationPointId":{"description":"Resolved Share DemarcationPoint UUID stamped on the successor subscription + CPE. Absent → the subscription is stranded (no RADIUS push until a demarcation point is assigned).","format":"uuid","type":"string"},"endBillingCycleDate":{"description":"ISO date — the external service’s cutover / end-of-billing-cycle date. Must be in the future. On the free path it anchors the zero-amount PAID lead-in `[now, endBillingCycleDate]`; on the scheduled path it is the cutover at which the payable successor activates.","type":"string"},"externalServiceId":{"description":"Per-service idempotency key (the external service id). Repeat calls with the same `(subscriberId, externalServiceId)` are idempotent — the existing rows are returned, no duplicate is created. Distinct ids let a subscriber be migrated for N concurrent services.","type":"string"},"free":{"default":false,"description":"Free-immediate migration (`true`) vs scheduled payable migration (`false`, default). Free-immediate archives the external subscription now and activates the Share plan immediately with a zero-amount PAID lead-in; `installation` MUST be omitted (rejected with 422).","type":"boolean"},"installation":{"allOf":[{"$ref":"#/components/schemas/MigrateSubscriptionInstallationDto"}],"description":"Scheduled path only — spawns an installation (`kind` defaults `REPLACEMENT`) + one-time charge on the successor. MUST be omitted when `free = true` (rejected with 422)."},"name":{"description":"Human label for the external subscription (the operator’s service name).","type":"string"},"planId":{"description":"Active target Share Plan UUID the subscriber migrates onto.","format":"uuid","type":"string"},"pppoePassword":{"description":"Existing PPPoE password. Supply together with `pppoeUsername`. Never logged.","type":"string"},"pppoeUsername":{"description":"Existing PPPoE username to reuse on the migrated CPE. Supply together with `pppoePassword` — a one-sided pair is ignored.","type":"string"},"subscriberId":{"description":"Existing Share subscriber UUID the migrated service belongs to.","format":"uuid","type":"string"}},"required":["subscriberId","planId","endBillingCycleDate"],"type":"object"},"MigrateSubscriptionInstallationDto":{"properties":{"fee":{"description":"Installation fee. Defaults to the plan-level installation fee when omitted.","type":"number"},"free":{"default":false,"description":"When true, the installation is recorded free of charge — no one-time installation charge is created.","type":"boolean"},"kind":{"default":"REPLACEMENT","description":"Installation kind. Defaults to `REPLACEMENT`.","enum":["INITIAL","REPLACEMENT","RELOCATION"],"type":"string"},"required":{"description":"When true, an installation record and one-time charge are created on the scheduled successor.","type":"boolean"}},"required":["required"],"type":"object"},"ApiResponseDto":{"properties":{},"type":"object"},"MigrateSubscriptionResponseDto":{"properties":{"alreadyExisted":{"description":"Scheduled path — `true` when an existing SCHEDULED successor was returned (idempotent replay on `(subscriberId, externalServiceId)`).","type":"boolean"},"currentSubscriptionId":{"description":"The external subscription (Sub A). Archived after the free-immediate replace; live (external) on the scheduled path until cutover.","format":"uuid","type":"string"},"free":{"description":"Whether this migration ran the free-immediate (`true`) or scheduled payable (`false`) path.","type":"boolean"},"idempotentReplay":{"description":"Free path — `true` when an existing Share-native replacement was returned (idempotent replay on `(subscriberId, externalServiceId)`).","type":"boolean"},"targetSubscriptionId":{"description":"The Share-native target subscription (Sub B) — the ACTIVE replacement (free path) or the SCHEDULED successor (scheduled path).","format":"uuid","type":"string"}},"required":["currentSubscriptionId","targetSubscriptionId","free"],"type":"object"}}},"paths":{"/v1/subscriptions/migrate":{"post":{"description":"Onboards an external (non-Share) service onto a target Share `planId` for an existing subscriber, honoring the external cutover date and producing the two-subscription model — **per service**, so a subscriber can be migrated for N concurrent services via distinct `externalServiceId`s. This endpoint makes no calls to the partner BSS.\n\n**Variants:**\n- `free = true` (free-immediate): the external subscription is archived now and the Share plan activates immediately with a zero-amount PAID lead-in `[now, endBillingCycleDate]`; the payable cycle opens at renewal. `installation` is rejected.\n- `free = false` (scheduled, default): the external subscription stays live with an informative cycle until `endBillingCycleDate`, and a SCHEDULED payable successor activates at that cutover. Supply `installation` (`kind` defaults `REPLACEMENT`) to gate full-speed access behind an install at cutover.\n\nA missing `demarcationPointId` leaves the successor stranded (RADIUS is skipped). Replay on `(subscriberId, externalServiceId)` is idempotent — the existing rows are returned.\n\n**Error codes:** `FREE_INSTALLATION_CONFLICT` (422) — `free = true` combined with `installation`; `END_DATE_NOT_FUTURE` (422) — `endBillingCycleDate` is not in the future; `NOT_FOUND` (404) — the subscriber does not exist under the authenticated provider.","operationId":"SubscriptionsController_migrateSubscription_v1","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrateSubscriptionRequestDto"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/MigrateSubscriptionResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"The external subscription + the Share-native target subscription."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"422":{"content":{"application/json":{"schema":{"properties":{"data":{"description":"Context for recovery — e.g. the created subscriber id when a create-time side effect is rejected after the create committed.","nullable":true,"properties":{"id":{"format":"uuid","type":"string"}},"type":"object"},"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"enum":["STATIC_IP_CONFLICT","CPE_NOT_FOUND"],"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Migration rejected (codes: FREE_INSTALLATION_CONFLICT, END_DATE_NOT_FUTURE)."},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Migrate an external service onto a Share plan","tags":["Subscriptions"]}}}}
```

## Get a subscription

> Returns a single subscription owned by the authenticated provider.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"SubscriptionResponseDto":{"properties":{"createdAt":{"format":"date-time","type":"string"},"demarcationPointId":{"format":"uuid","type":"object"},"expiresAt":{"format":"date-time","type":"string"},"gracePeriodDaysOverride":{"description":"Per-subscription grace period in days (renewal cycles only), overriding the plan grace period for this subscription. `null` when not set — the subscription uses the plan grace period.","maximum":30,"minimum":0,"nullable":true,"type":"object"},"id":{"format":"uuid","type":"string"},"inactiveReason":{"enum":["GRACE_EXPIRED","ADMIN_DEACTIVATED","PLAN_REMOVED","NO_PLAN_ASSIGNED","PLAN_DISABLED","ACTIVATION_GRACE_EXPIRED"],"type":"string"},"inactiveReasonNote":{"description":"Operator-supplied free-text rationale paired with `inactiveReason`. Persisted on the subscription when set during deactivation.","type":"object"},"isExternal":{"description":"True when the subscription is managed by an external BSS.","type":"boolean"},"name":{"description":"Subscription label set from the originating external service name (Splynx internet-service description). Populated for the current/non-Share migration subscription (which has no plan); null for Share-native subscriptions.","type":"object"},"nextPlanId":{"description":"Queued plan ID (set on plan-change-queued or migration-pending).","format":"uuid","type":"object"},"nextPlanName":{"type":"object"},"override":{"allOf":[{"$ref":"#/components/schemas/SubscriptionPricingOverrideResponseDto"}],"description":"Active and queued per-subscription pricing override. Populated on the detail endpoint (`GET /v1/subscriptions/:id`); the list endpoint always returns `null` here. `null` when no override has been applied."},"planId":{"format":"uuid","type":"object"},"planName":{"description":"Human-readable plan label","type":"object"},"pppoePassword":{"description":"PPPoE password on the subscriber CPE","type":"object"},"pppoeUsername":{"description":"PPPoE username on the subscriber CPE","type":"object"},"scheduledCancellationAt":{"description":"Finalize date when the subscription is scheduled for cancellation (set by `POST /v1/subscriptions/:id/deactivate`); `null` when not scheduled. Presence means \"scheduled for cancellation\": the subscription stays `ACTIVE` and keeps internet until the billing finalize cron archives it at/after this date. Cleared by `POST /v1/subscriptions/:id/cancel-scheduled-cancellation`.","format":"date-time","type":"object"},"serviceHandle":{"description":"Stable 13-digit handle derived from a per-subscription sequence and the provider country code. Read-only and deterministic — safe to expose in support tooling and partner integrations.","pattern":"^\\d{13}$","type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"enum":["PENDING","SCHEDULED","ACTIVE","EXPIRED","SUSPENDED","AWAITING_PAYMENT_FOR_UPGRADE","INACTIVE","ARCHIVED"],"type":"string"},"subscriberId":{"format":"uuid","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"wasMigrated":{"description":"True when this subscriber was carried over from a legacy BSS during platform migration.","type":"boolean"}},"required":["id","serviceHandle","subscriberId","status","isExternal","wasMigrated","startedAt","expiresAt","createdAt","updatedAt"],"type":"object"},"SubscriptionPricingOverrideResponseDto":{"properties":{"authorizedBy":{"description":"Identifier of the user that authorized the override.","format":"uuid","type":"object"},"createdAt":{"format":"date-time","type":"string"},"durationOverride":{"description":"Active duration override in days; overrides the plan duration.","type":"object"},"expiresAt":{"description":"Optional expiry — after this point the override is treated as cleared.","format":"date-time","type":"object"},"nextDurationOverride":{"description":"Queued duration override in days — promoted to the active value at the next renewal.","type":"object"},"nextPriceOverride":{"description":"Queued price override — promoted to the active value at the next renewal.","type":"object"},"nextSpeedOverride":{"description":"Queued speed override in Mbps — promoted to the active value at the next renewal.","type":"object"},"priceOverride":{"description":"Active price override; overrides the plan price.","type":"object"},"reason":{"description":"Operator-supplied rationale for the override.","type":"object"},"speedOverride":{"description":"Active speed override in Mbps; overrides the plan speed.","type":"object"},"updatedAt":{"format":"date-time","type":"string"}},"required":["createdAt","updatedAt"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}":{"get":{"description":"Returns a single subscription owned by the authenticated provider.","operationId":"SubscriptionsController_getSubscription_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SubscriptionResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"The requested subscription."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Get a subscription","tags":["Subscriptions"]}}}}
```

## Update a subscription

> Supports five mutations: plan change (\`planId: \<uuid>\`), plan removal (\`planId: null\`), PPPoE credential rotation (\`pppoeUsername\` + \`pppoePassword\`), demarcation-point move (\`demarcationPointId\`), and RADIUS IP assignment (\`radiusIpAssignment\`, DEV-1220 — set/change with a mode object, clear with \`null\`; applies to the subscription's CPE and takes effect via an immediate re-provision).\
> \
> Core fields and \`radiusIpAssignment\` are applied in sequence (core first): if the core update commits and the assignment is then rejected, the core changes stay applied — re-send only \`radiusIpAssignment\` after fixing the rejection.\
> \
> \*\*Error codes:\*\* \`SUBSCRIPTION\_TERMINAL\` (400) — the subscription is in a terminal state (also enforced for radius-only updates, including \`null\` clears); \`PLAN\_DISABLED\` (400) — target plan is disabled; \`PLAN\_PRICE\_BELOW\_FLOOR\` (400) — target plan violates the documented price floor; \`CONTACT\_SHARE\` (400) — change requires Share intervention (e.g. external→Share plan migration mid-cycle); \`STATIC\_IP\_CONFLICT\` (422) — the static IP is already assigned on the same RADIUS instance; \`CPE\_NOT\_FOUND\` (422) — the subscription has no CPE to carry the assignment; \`RADIUS\_INSTANCE\_NOT\_CONFIGURED\` (400) — static-IP uniqueness cannot be validated because the demarcation point has no RADIUS instance. See the \[Error codes]\(../errors/error-codes.md) reference.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"UpdateSubscriptionRequestDto":{"properties":{"cancelQueuedSwap":{"description":"Clear a queued plan swap (`nextPlanId`) without touching the current `planId`. Mutually exclusive with `planId` — sending both returns 400.","type":"boolean"},"demarcationPointId":{"description":"Move the subscription to a different demarcation point. The change is persisted on the CPE record.","format":"uuid","type":"string"},"gracePeriodDaysOverride":{"description":"Set the per-subscription grace period (days, renewal cycles only), overriding the plan grace period for this subscription. Send `null` to clear the override and revert to the plan default. Omit to leave the current value unchanged.","maximum":30,"minimum":0,"nullable":true,"type":"object"},"planId":{"description":"Change the assigned plan. Send `null` to remove the plan — the removal is queued until cycle expiry, applied immediately when the cycle has been refunded, or applied immediately when no cycle is in flight.","format":"uuid","nullable":true,"type":"object"},"pppoePassword":{"description":"Rotate the PPPoE password. See `pppoeUsername`.","type":"string"},"pppoeUsername":{"description":"Rotate the PPPoE username. The CPE record is updated and a credential push is scheduled or queued depending on cycle state.","type":"string"},"radiusIpAssignment":{"allOf":[{"$ref":"#/components/schemas/RadiusIpAssignmentDto"}],"description":"Set or change the RADIUS IP assignment on the subscription's CPE (static IP, default/custom pool, dual-mode uplink). Send `null` to clear the assignment back to the demarcation-point default. Omit to leave the current assignment untouched. A duplicate static IP on the same RADIUS instance returns 422 `STATIC_IP_CONFLICT`.","nullable":true,"type":"object"}},"type":"object"},"RadiusIpAssignmentDto":{"properties":{"ip":{"description":"IPv4 address to pin. Required for `STATIC_IP` and `DUAL_UPLINK`; rejected for the pool modes. Must be unique per RADIUS instance — a duplicate returns 422 `STATIC_IP_CONFLICT`.","type":"string"},"mode":{"description":"IP-assignment scenario for the RADIUS reply. `STATIC_IP` pins `ip` and suppresses the PPP profile attribute; `DEFAULT_POOL` suppresses the profile attribute so the NAS default pool applies; `CUSTOM_POOL` replies `Framed-Pool = poolName`; `DUAL_UPLINK` pins `ip` while keeping the demarcation-point profile attribute.","enum":["STATIC_IP","DEFAULT_POOL","CUSTOM_POOL","DUAL_UPLINK"],"type":"string"},"poolName":{"description":"NAS pool name to reply as `Framed-Pool`. Required for `CUSTOM_POOL`; rejected for the other modes.","type":"string"}},"required":["mode"],"type":"object"},"ApiResponseDto":{"properties":{},"type":"object"},"SubscriptionResponseDto":{"properties":{"createdAt":{"format":"date-time","type":"string"},"demarcationPointId":{"format":"uuid","type":"object"},"expiresAt":{"format":"date-time","type":"string"},"gracePeriodDaysOverride":{"description":"Per-subscription grace period in days (renewal cycles only), overriding the plan grace period for this subscription. `null` when not set — the subscription uses the plan grace period.","maximum":30,"minimum":0,"nullable":true,"type":"object"},"id":{"format":"uuid","type":"string"},"inactiveReason":{"enum":["GRACE_EXPIRED","ADMIN_DEACTIVATED","PLAN_REMOVED","NO_PLAN_ASSIGNED","PLAN_DISABLED","ACTIVATION_GRACE_EXPIRED"],"type":"string"},"inactiveReasonNote":{"description":"Operator-supplied free-text rationale paired with `inactiveReason`. Persisted on the subscription when set during deactivation.","type":"object"},"isExternal":{"description":"True when the subscription is managed by an external BSS.","type":"boolean"},"name":{"description":"Subscription label set from the originating external service name (Splynx internet-service description). Populated for the current/non-Share migration subscription (which has no plan); null for Share-native subscriptions.","type":"object"},"nextPlanId":{"description":"Queued plan ID (set on plan-change-queued or migration-pending).","format":"uuid","type":"object"},"nextPlanName":{"type":"object"},"override":{"allOf":[{"$ref":"#/components/schemas/SubscriptionPricingOverrideResponseDto"}],"description":"Active and queued per-subscription pricing override. Populated on the detail endpoint (`GET /v1/subscriptions/:id`); the list endpoint always returns `null` here. `null` when no override has been applied."},"planId":{"format":"uuid","type":"object"},"planName":{"description":"Human-readable plan label","type":"object"},"pppoePassword":{"description":"PPPoE password on the subscriber CPE","type":"object"},"pppoeUsername":{"description":"PPPoE username on the subscriber CPE","type":"object"},"scheduledCancellationAt":{"description":"Finalize date when the subscription is scheduled for cancellation (set by `POST /v1/subscriptions/:id/deactivate`); `null` when not scheduled. Presence means \"scheduled for cancellation\": the subscription stays `ACTIVE` and keeps internet until the billing finalize cron archives it at/after this date. Cleared by `POST /v1/subscriptions/:id/cancel-scheduled-cancellation`.","format":"date-time","type":"object"},"serviceHandle":{"description":"Stable 13-digit handle derived from a per-subscription sequence and the provider country code. Read-only and deterministic — safe to expose in support tooling and partner integrations.","pattern":"^\\d{13}$","type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"enum":["PENDING","SCHEDULED","ACTIVE","EXPIRED","SUSPENDED","AWAITING_PAYMENT_FOR_UPGRADE","INACTIVE","ARCHIVED"],"type":"string"},"subscriberId":{"format":"uuid","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"wasMigrated":{"description":"True when this subscriber was carried over from a legacy BSS during platform migration.","type":"boolean"}},"required":["id","serviceHandle","subscriberId","status","isExternal","wasMigrated","startedAt","expiresAt","createdAt","updatedAt"],"type":"object"},"SubscriptionPricingOverrideResponseDto":{"properties":{"authorizedBy":{"description":"Identifier of the user that authorized the override.","format":"uuid","type":"object"},"createdAt":{"format":"date-time","type":"string"},"durationOverride":{"description":"Active duration override in days; overrides the plan duration.","type":"object"},"expiresAt":{"description":"Optional expiry — after this point the override is treated as cleared.","format":"date-time","type":"object"},"nextDurationOverride":{"description":"Queued duration override in days — promoted to the active value at the next renewal.","type":"object"},"nextPriceOverride":{"description":"Queued price override — promoted to the active value at the next renewal.","type":"object"},"nextSpeedOverride":{"description":"Queued speed override in Mbps — promoted to the active value at the next renewal.","type":"object"},"priceOverride":{"description":"Active price override; overrides the plan price.","type":"object"},"reason":{"description":"Operator-supplied rationale for the override.","type":"object"},"speedOverride":{"description":"Active speed override in Mbps; overrides the plan speed.","type":"object"},"updatedAt":{"format":"date-time","type":"string"}},"required":["createdAt","updatedAt"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}":{"patch":{"description":"Supports five mutations: plan change (`planId: <uuid>`), plan removal (`planId: null`), PPPoE credential rotation (`pppoeUsername` + `pppoePassword`), demarcation-point move (`demarcationPointId`), and RADIUS IP assignment (`radiusIpAssignment`, DEV-1220 — set/change with a mode object, clear with `null`; applies to the subscription's CPE and takes effect via an immediate re-provision).\n\nCore fields and `radiusIpAssignment` are applied in sequence (core first): if the core update commits and the assignment is then rejected, the core changes stay applied — re-send only `radiusIpAssignment` after fixing the rejection.\n\n**Error codes:** `SUBSCRIPTION_TERMINAL` (400) — the subscription is in a terminal state (also enforced for radius-only updates, including `null` clears); `PLAN_DISABLED` (400) — target plan is disabled; `PLAN_PRICE_BELOW_FLOOR` (400) — target plan violates the documented price floor; `CONTACT_SHARE` (400) — change requires Share intervention (e.g. external→Share plan migration mid-cycle); `STATIC_IP_CONFLICT` (422) — the static IP is already assigned on the same RADIUS instance; `CPE_NOT_FOUND` (422) — the subscription has no CPE to carry the assignment; `RADIUS_INSTANCE_NOT_CONFIGURED` (400) — static-IP uniqueness cannot be validated because the demarcation point has no RADIUS instance. See the [Error codes](../errors/error-codes.md) reference.","operationId":"SubscriptionsController_updateSubscription_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSubscriptionRequestDto"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SubscriptionResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"The updated subscription."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"422":{"content":{"application/json":{"schema":{"properties":{"data":{"description":"Context for recovery — e.g. the created subscriber id when a create-time side effect is rejected after the create committed.","nullable":true,"properties":{"id":{"format":"uuid","type":"string"}},"type":"object"},"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"enum":["STATIC_IP_CONFLICT","CPE_NOT_FOUND"],"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"radiusIpAssignment rejected (codes: STATIC_IP_CONFLICT, CPE_NOT_FOUND)."},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Update a subscription","tags":["Subscriptions"]}}}}
```

## Activate a subscription

> Transitions the subscription to ACTIVE and creates or updates its billing cycle. Idempotent — repeat calls return the same terminal outcome. Returns \`DEFERRED\` when prerequisites (CPE credentials, plan assignment) are missing.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"ActivateSubscriptionResponseDto":{"properties":{"amount":{"type":"number"},"currency":{"type":"string"},"cycleId":{"format":"uuid","type":"string"},"endDate":{"format":"date-time","type":"string"},"message":{"description":"Human-readable reason when terminal is DEFERRED or FAILED.","type":"string"},"paymentStatus":{"enum":["PENDING","EXTERNAL","PAID","WAIVED","SETTLEMENT_FAILED"],"type":"string"},"planId":{"format":"uuid","type":"string"},"startDate":{"format":"date-time","type":"string"},"subscriberId":{"format":"uuid","type":"string"},"subscriptionId":{"format":"uuid","type":"string"},"terminal":{"description":"Activation outcome. `DEFERRED` means a prerequisite is missing (CPE credentials, plan assignment).","enum":["ACTIVATED-PAID","ACTIVATED-PENDING-PAYMENT","DEFERRED","FAILED"],"type":"string"}},"required":["terminal","subscriberId","subscriptionId"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/activate":{"post":{"description":"Transitions the subscription to ACTIVE and creates or updates its billing cycle. Idempotent — repeat calls return the same terminal outcome. Returns `DEFERRED` when prerequisites (CPE credentials, plan assignment) are missing.","operationId":"SubscriptionsController_activateSubscription_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ActivateSubscriptionResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"Activation outcome."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Activate a subscription","tags":["Subscriptions"]}}}}
```

## List billing cycles for a subscription

> Returns the paginated billing cycles for a subscription, sorted by \`startDate\` DESC. Each row carries \`paidAt\` (settlement timestamp of the linked payment) and \`graceEndsAt\` (activation-grace deadline) so consumers can render the cycle history without a follow-up fetch.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"BillingCycleResponseDto":{"properties":{"amount":{"type":"number"},"endDate":{"format":"date-time","type":"string"},"graceEndsAt":{"description":"Activation-grace deadline (`BillingCycle.activationGraceExpiresAt`). Null outside the activation-grace window.","format":"date-time","nullable":true,"type":"string"},"id":{"description":"BillingCycle id","format":"uuid","type":"string"},"paidAt":{"description":"`PaymentTransaction.completedAt` for the cycle's linked transaction. Null when no settled payment is attached.","format":"date-time","nullable":true,"type":"string"},"paymentStatus":{"enum":["PENDING","EXTERNAL","PAID","WAIVED","SETTLEMENT_FAILED"],"type":"string"},"startDate":{"format":"date-time","type":"string"},"status":{"enum":["SCHEDULED","EXTERNAL","ACTIVE","OVERDUE","SUSPENDED","COMPLETED","CANCELLED","ARCHIVED"],"type":"string"}},"required":["id","startDate","endDate","amount","status","paymentStatus","paidAt","graceEndsAt"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/billing-cycles":{"get":{"description":"Returns the paginated billing cycles for a subscription, sorted by `startDate` DESC. Each row carries `paidAt` (settlement timestamp of the linked payment) and `graceEndsAt` (activation-grace deadline) so consumers can render the cycle history without a follow-up fetch.","operationId":"SubscriptionsController_listBillingCycles_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"number"}},{"in":"query","name":"pageSize","required":false,"schema":{"default":20,"maximum":100,"minimum":1,"type":"number"}},{"description":"When `true`, includes billing cycles whose subscription is archived.","in":"query","name":"includeArchived","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/BillingCycleResponseDto"},"type":"array"},"success":{"type":"boolean"}}}]}}},"description":"Paginated billing cycles for this subscription."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"List billing cycles for a subscription","tags":["Subscriptions"]}}}}
```

## Un-schedule a pending cancellation

> Clears a pending scheduled cancellation set by \`POST /v1/subscriptions/:id/deactivate\`. The subscription stays \`ACTIVE\` and renews normally. Idempotent — a no-op when nothing is scheduled. The response carries \`scheduledCancellationAt: null\`.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"SubscriptionResponseDto":{"properties":{"createdAt":{"format":"date-time","type":"string"},"demarcationPointId":{"format":"uuid","type":"object"},"expiresAt":{"format":"date-time","type":"string"},"gracePeriodDaysOverride":{"description":"Per-subscription grace period in days (renewal cycles only), overriding the plan grace period for this subscription. `null` when not set — the subscription uses the plan grace period.","maximum":30,"minimum":0,"nullable":true,"type":"object"},"id":{"format":"uuid","type":"string"},"inactiveReason":{"enum":["GRACE_EXPIRED","ADMIN_DEACTIVATED","PLAN_REMOVED","NO_PLAN_ASSIGNED","PLAN_DISABLED","ACTIVATION_GRACE_EXPIRED"],"type":"string"},"inactiveReasonNote":{"description":"Operator-supplied free-text rationale paired with `inactiveReason`. Persisted on the subscription when set during deactivation.","type":"object"},"isExternal":{"description":"True when the subscription is managed by an external BSS.","type":"boolean"},"name":{"description":"Subscription label set from the originating external service name (Splynx internet-service description). Populated for the current/non-Share migration subscription (which has no plan); null for Share-native subscriptions.","type":"object"},"nextPlanId":{"description":"Queued plan ID (set on plan-change-queued or migration-pending).","format":"uuid","type":"object"},"nextPlanName":{"type":"object"},"override":{"allOf":[{"$ref":"#/components/schemas/SubscriptionPricingOverrideResponseDto"}],"description":"Active and queued per-subscription pricing override. Populated on the detail endpoint (`GET /v1/subscriptions/:id`); the list endpoint always returns `null` here. `null` when no override has been applied."},"planId":{"format":"uuid","type":"object"},"planName":{"description":"Human-readable plan label","type":"object"},"pppoePassword":{"description":"PPPoE password on the subscriber CPE","type":"object"},"pppoeUsername":{"description":"PPPoE username on the subscriber CPE","type":"object"},"scheduledCancellationAt":{"description":"Finalize date when the subscription is scheduled for cancellation (set by `POST /v1/subscriptions/:id/deactivate`); `null` when not scheduled. Presence means \"scheduled for cancellation\": the subscription stays `ACTIVE` and keeps internet until the billing finalize cron archives it at/after this date. Cleared by `POST /v1/subscriptions/:id/cancel-scheduled-cancellation`.","format":"date-time","type":"object"},"serviceHandle":{"description":"Stable 13-digit handle derived from a per-subscription sequence and the provider country code. Read-only and deterministic — safe to expose in support tooling and partner integrations.","pattern":"^\\d{13}$","type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"enum":["PENDING","SCHEDULED","ACTIVE","EXPIRED","SUSPENDED","AWAITING_PAYMENT_FOR_UPGRADE","INACTIVE","ARCHIVED"],"type":"string"},"subscriberId":{"format":"uuid","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"wasMigrated":{"description":"True when this subscriber was carried over from a legacy BSS during platform migration.","type":"boolean"}},"required":["id","serviceHandle","subscriberId","status","isExternal","wasMigrated","startedAt","expiresAt","createdAt","updatedAt"],"type":"object"},"SubscriptionPricingOverrideResponseDto":{"properties":{"authorizedBy":{"description":"Identifier of the user that authorized the override.","format":"uuid","type":"object"},"createdAt":{"format":"date-time","type":"string"},"durationOverride":{"description":"Active duration override in days; overrides the plan duration.","type":"object"},"expiresAt":{"description":"Optional expiry — after this point the override is treated as cleared.","format":"date-time","type":"object"},"nextDurationOverride":{"description":"Queued duration override in days — promoted to the active value at the next renewal.","type":"object"},"nextPriceOverride":{"description":"Queued price override — promoted to the active value at the next renewal.","type":"object"},"nextSpeedOverride":{"description":"Queued speed override in Mbps — promoted to the active value at the next renewal.","type":"object"},"priceOverride":{"description":"Active price override; overrides the plan price.","type":"object"},"reason":{"description":"Operator-supplied rationale for the override.","type":"object"},"speedOverride":{"description":"Active speed override in Mbps; overrides the plan speed.","type":"object"},"updatedAt":{"format":"date-time","type":"string"}},"required":["createdAt","updatedAt"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/cancel-scheduled-cancellation":{"post":{"description":"Clears a pending scheduled cancellation set by `POST /v1/subscriptions/:id/deactivate`. The subscription stays `ACTIVE` and renews normally. Idempotent — a no-op when nothing is scheduled. The response carries `scheduledCancellationAt: null`.","operationId":"SubscriptionsController_cancelScheduledCancellation_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SubscriptionResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"The subscription with `scheduledCancellationAt` cleared (`null`)."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Un-schedule a pending cancellation","tags":["Subscriptions"]}}}}
```

## Schedule a subscription for cancellation at cycle end

> Schedules the subscription for cancellation at the end of its current billing cycle (or immediately on the next finalize tick when there is no active cycle). The subscription stays \`ACTIVE\` and internet keeps running until the finalize date — RADIUS is \*\*not\*\* cut at scheduling time. The response carries \`scheduledCancellationAt\` (the finalize date) and \`status\` (still \`ACTIVE\`). Idempotent: re-scheduling an already-scheduled subscription preserves the original finalize date. Revertible via \`POST /v1/subscriptions/:id/cancel-scheduled-cancellation\`. Rejects with \`400\` when the subscription is already \`ARCHIVED\`. For an irreversible teardown now, use \`POST /v1/subscriptions/:id/deactivate-immediate\`.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ScheduleCancellationRequestDto":{"properties":{"reason":{"description":"Optional free-text rationale for the scheduled cancellation. Persisted on the subscription alongside the finalize date for audit.","maxLength":500,"type":"string"}},"type":"object"},"ApiResponseDto":{"properties":{},"type":"object"},"SubscriptionResponseDto":{"properties":{"createdAt":{"format":"date-time","type":"string"},"demarcationPointId":{"format":"uuid","type":"object"},"expiresAt":{"format":"date-time","type":"string"},"gracePeriodDaysOverride":{"description":"Per-subscription grace period in days (renewal cycles only), overriding the plan grace period for this subscription. `null` when not set — the subscription uses the plan grace period.","maximum":30,"minimum":0,"nullable":true,"type":"object"},"id":{"format":"uuid","type":"string"},"inactiveReason":{"enum":["GRACE_EXPIRED","ADMIN_DEACTIVATED","PLAN_REMOVED","NO_PLAN_ASSIGNED","PLAN_DISABLED","ACTIVATION_GRACE_EXPIRED"],"type":"string"},"inactiveReasonNote":{"description":"Operator-supplied free-text rationale paired with `inactiveReason`. Persisted on the subscription when set during deactivation.","type":"object"},"isExternal":{"description":"True when the subscription is managed by an external BSS.","type":"boolean"},"name":{"description":"Subscription label set from the originating external service name (Splynx internet-service description). Populated for the current/non-Share migration subscription (which has no plan); null for Share-native subscriptions.","type":"object"},"nextPlanId":{"description":"Queued plan ID (set on plan-change-queued or migration-pending).","format":"uuid","type":"object"},"nextPlanName":{"type":"object"},"override":{"allOf":[{"$ref":"#/components/schemas/SubscriptionPricingOverrideResponseDto"}],"description":"Active and queued per-subscription pricing override. Populated on the detail endpoint (`GET /v1/subscriptions/:id`); the list endpoint always returns `null` here. `null` when no override has been applied."},"planId":{"format":"uuid","type":"object"},"planName":{"description":"Human-readable plan label","type":"object"},"pppoePassword":{"description":"PPPoE password on the subscriber CPE","type":"object"},"pppoeUsername":{"description":"PPPoE username on the subscriber CPE","type":"object"},"scheduledCancellationAt":{"description":"Finalize date when the subscription is scheduled for cancellation (set by `POST /v1/subscriptions/:id/deactivate`); `null` when not scheduled. Presence means \"scheduled for cancellation\": the subscription stays `ACTIVE` and keeps internet until the billing finalize cron archives it at/after this date. Cleared by `POST /v1/subscriptions/:id/cancel-scheduled-cancellation`.","format":"date-time","type":"object"},"serviceHandle":{"description":"Stable 13-digit handle derived from a per-subscription sequence and the provider country code. Read-only and deterministic — safe to expose in support tooling and partner integrations.","pattern":"^\\d{13}$","type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"enum":["PENDING","SCHEDULED","ACTIVE","EXPIRED","SUSPENDED","AWAITING_PAYMENT_FOR_UPGRADE","INACTIVE","ARCHIVED"],"type":"string"},"subscriberId":{"format":"uuid","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"wasMigrated":{"description":"True when this subscriber was carried over from a legacy BSS during platform migration.","type":"boolean"}},"required":["id","serviceHandle","subscriberId","status","isExternal","wasMigrated","startedAt","expiresAt","createdAt","updatedAt"],"type":"object"},"SubscriptionPricingOverrideResponseDto":{"properties":{"authorizedBy":{"description":"Identifier of the user that authorized the override.","format":"uuid","type":"object"},"createdAt":{"format":"date-time","type":"string"},"durationOverride":{"description":"Active duration override in days; overrides the plan duration.","type":"object"},"expiresAt":{"description":"Optional expiry — after this point the override is treated as cleared.","format":"date-time","type":"object"},"nextDurationOverride":{"description":"Queued duration override in days — promoted to the active value at the next renewal.","type":"object"},"nextPriceOverride":{"description":"Queued price override — promoted to the active value at the next renewal.","type":"object"},"nextSpeedOverride":{"description":"Queued speed override in Mbps — promoted to the active value at the next renewal.","type":"object"},"priceOverride":{"description":"Active price override; overrides the plan price.","type":"object"},"reason":{"description":"Operator-supplied rationale for the override.","type":"object"},"speedOverride":{"description":"Active speed override in Mbps; overrides the plan speed.","type":"object"},"updatedAt":{"format":"date-time","type":"string"}},"required":["createdAt","updatedAt"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/deactivate":{"post":{"description":"Schedules the subscription for cancellation at the end of its current billing cycle (or immediately on the next finalize tick when there is no active cycle). The subscription stays `ACTIVE` and internet keeps running until the finalize date — RADIUS is **not** cut at scheduling time. The response carries `scheduledCancellationAt` (the finalize date) and `status` (still `ACTIVE`). Idempotent: re-scheduling an already-scheduled subscription preserves the original finalize date. Revertible via `POST /v1/subscriptions/:id/cancel-scheduled-cancellation`. Rejects with `400` when the subscription is already `ARCHIVED`. For an irreversible teardown now, use `POST /v1/subscriptions/:id/deactivate-immediate`.","operationId":"SubscriptionsController_deactivateSubscription_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleCancellationRequestDto"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SubscriptionResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"The subscription with `scheduledCancellationAt` set; `status` stays `ACTIVE`."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Schedule a subscription for cancellation at cycle end","tags":["Subscriptions"]}}}}
```

## Deactivate a subscription immediately (no refund)

> Irreversibly archives the subscription \*\*now\*\*: the subscription and its dependent billing cycles, installations, and one-time charges are flipped to \`ARCHIVED\`, and RADIUS is cut now (FreeRADIUS \`DELETE\_USER\` + Disconnect-Request) when this was the subscriber's last non-terminal subscription. \*\*No refund\*\* — any remaining paid days are forfeited. \*\*Not revertible.\*\* For a graceful end-of-cycle cancellation that keeps internet until the cycle ends, use \`POST /v1/subscriptions/:id/deactivate\` instead.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"DeactivateImmediateResponseDto":{"properties":{"archivedBillingCycles":{"description":"Number of billing cycles cascade-archived.","type":"number"},"archivedInstallations":{"description":"Number of installations cascade-archived.","type":"number"},"archivedOneTimeCharges":{"description":"Number of one-time charges cascade-archived.","type":"number"},"radiusToreDown":{"description":"True when this archive emptied the subscriber's last non-terminal subscription and therefore drove the RADIUS teardown (FreeRADIUS `DELETE_USER` + Disconnect-Request). False when sibling subscriptions remain live.","type":"boolean"},"subscriptionId":{"format":"uuid","type":"string"}},"required":["subscriptionId","archivedBillingCycles","archivedInstallations","archivedOneTimeCharges","radiusToreDown"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/deactivate-immediate":{"post":{"description":"Irreversibly archives the subscription **now**: the subscription and its dependent billing cycles, installations, and one-time charges are flipped to `ARCHIVED`, and RADIUS is cut now (FreeRADIUS `DELETE_USER` + Disconnect-Request) when this was the subscriber's last non-terminal subscription. **No refund** — any remaining paid days are forfeited. **Not revertible.** For a graceful end-of-cycle cancellation that keeps internet until the cycle ends, use `POST /v1/subscriptions/:id/deactivate` instead.","operationId":"SubscriptionsController_deactivateImmediate_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/DeactivateImmediateResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"Archive outcome (cascade counts + whether RADIUS was cut)."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Deactivate a subscription immediately (no refund)","tags":["Subscriptions"]}}}}
```

## List outstanding obligations for a subscription

> Returns a single merged list of everything still owed on a subscription — pending one-time charges and unpaid billing cycles in one call. Each underlying source is queried for the two outstanding states \`PENDING\` and \`SETTLEMENT\_FAILED\`; \`PAID\` / \`WAIVED\` / \`CANCELLED\` / \`REFUNDED\` rows are excluded. Rows are tagged with \`kind\` (\`'CHARGE'\` | \`'BILLING\_CYCLE'\`) and sorted by \`createdAt\` DESC. The list is not paginated: each source is capped at 100 rows per outstanding state, and \`meta.total\` reflects the true outstanding count even when the returned list is capped.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"OutstandingItemResponseDto":{"properties":{"amount":{"type":"number"},"createdAt":{"description":"Row creation timestamp. The merged list is sorted by this field DESC (newest obligation first).","format":"date-time","type":"string"},"currency":{"type":"string"},"description":{"description":"`CHARGE` only — operator-facing description. `null` for cycles.","nullable":true,"type":"object"},"endDate":{"description":"`BILLING_CYCLE` only — cycle end date (the due date). `null` for charges.","format":"date-time","nullable":true,"type":"string"},"expiresAt":{"description":"`CHARGE` only — `OneTimeCharge.expiresAt` deadline. `null` when the charge has no deadline or for cycles.","format":"date-time","nullable":true,"type":"string"},"graceEndsAt":{"description":"`BILLING_CYCLE` only — activation-grace deadline (`BillingCycle.activationGraceExpiresAt`). `null` outside the activation-grace window or for charges.","format":"date-time","nullable":true,"type":"string"},"id":{"description":"`OneTimeCharge.id` for `CHARGE` rows, `BillingCycle.id` for `BILLING_CYCLE` rows.","format":"uuid","type":"string"},"kind":{"description":"Row discriminator. `CHARGE` rows carry `type` / `description` / `expiresAt`; `BILLING_CYCLE` rows carry `startDate` / `endDate` / `graceEndsAt`.","enum":["CHARGE","BILLING_CYCLE"],"type":"string"},"startDate":{"description":"`BILLING_CYCLE` only — cycle start date. `null` for charges.","format":"date-time","nullable":true,"type":"string"},"status":{"description":"For `CHARGE` rows this is a `OneTimeChargeStatus`; for `BILLING_CYCLE` rows a `BillingPaymentStatus`. Always `PENDING` or `SETTLEMENT_FAILED`.","enum":["PENDING","SETTLEMENT_FAILED"],"type":"string"},"type":{"description":"`CHARGE` only — one-time charge type. `null` for cycles.","enum":["INSTALLATION","EQUIPMENT","RECONNECTION","OTHER"],"nullable":true,"type":"string"}},"required":["kind","id","amount","currency","status","createdAt"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/outstanding":{"get":{"description":"Returns a single merged list of everything still owed on a subscription — pending one-time charges and unpaid billing cycles in one call. Each underlying source is queried for the two outstanding states `PENDING` and `SETTLEMENT_FAILED`; `PAID` / `WAIVED` / `CANCELLED` / `REFUNDED` rows are excluded. Rows are tagged with `kind` (`'CHARGE'` | `'BILLING_CYCLE'`) and sorted by `createdAt` DESC. The list is not paginated: each source is capped at 100 rows per outstanding state, and `meta.total` reflects the true outstanding count even when the returned list is capped.","operationId":"SubscriptionsController_listOutstanding_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/OutstandingItemResponseDto"},"type":"array"},"success":{"type":"boolean"}}}]}}},"description":"Merged outstanding one-time charges + unpaid billing cycles for this subscription, newest first."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"List outstanding obligations for a subscription","tags":["Subscriptions"]}}}}
```

## Initiate a deposit (M-Pesa STK push covering the subscription’s outstanding billing cycles + one-time charges)

> The server derives the push amount from the sum of every PENDING billing cycle and PENDING one-time charge on the subscription at request time — callers do not pre-compute a number. Returns the rail reference, the resolved total, and the \`billingCycleIds\` + \`oneTimeChargeIds\` the push is intended to settle — the asynchronous C2B callback drives the authoritative cycle-by-cycle settlement. Returns 400 with \`{ code: "NOTHING\_TO\_PAY" }\` when there is nothing outstanding. \`body.phone\` is an STK-push-only override (falls back to the subscriber's stored phone when omitted) and never mutates the subscriber record.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"InitiateDepositRequestDto":{"properties":{"phone":{"description":"M-Pesa phone override for this STK push only. Falls back to the subscriber's stored phone when omitted; the subscriber record is never mutated by this endpoint.","type":"string"}},"type":"object"},"ApiResponseDto":{"properties":{},"type":"object"},"InitiateDepositResponseDto":{"properties":{"accountReference":{"description":"Rail-aware \"Account Number\" the subscriber types into M-PESA's paybill prompt to settle this push manually if the STK prompt is cancelled or times out. The inbound C2B callback echoes it back so the same outstanding obligations are still credited. Display it as a fallback whenever the STK push is reported as failed.","type":"string"},"billingCycleIds":{"description":"Billing cycle ids that this STK push is intended to settle (every BillingCycle on the subscription with paymentStatus=PENDING at request time). The asynchronous C2B callback drives the authoritative cycle-by-cycle settlement.","items":{"type":"string"},"type":"array"},"currency":{"description":"Currency of `totalAmount`. Inherited from the underlying billing records (always KES for current providers).","type":"string"},"message":{"description":"Message echoed from the payment rail.","type":"string"},"oneTimeChargeIds":{"description":"One-time charge ids that this STK push is intended to settle (every OneTimeCharge on the subscription with status=PENDING at request time).","items":{"type":"string"},"type":"array"},"paybill":{"allOf":[{"$ref":"#/components/schemas/InitiateDepositPaybillDto"}],"description":"Paybill routing block for the deposit, included so callers have everything needed to render the manual-paybill fallback (M-PESA paybill number + account reference + subscriber outstanding balance) without a follow-up request."},"paymentId":{"description":"Share's internal payment reference. Use this id when reconciling the M-Pesa C2B callback against the obligations listed below.","type":"string"},"status":{"description":"Outcome of the push. `INITIATED` means the STK push was accepted by the rail; the actual collection is confirmed asynchronously via the C2B callback. Failures are returned as HTTP errors, not as a `FAILED` status here.","enum":["INITIATED"],"type":"string"},"totalAmount":{"description":"Total amount pushed to the rail. Server-derived from the sum of the PENDING BillingCycles + PENDING OneTimeCharges resolved at request time.","type":"number"}},"required":["paymentId","status","totalAmount","currency","billingCycleIds","oneTimeChargeIds","accountReference","paybill"],"type":"object"},"InitiateDepositPaybillDto":{"properties":{"accountReference":{"description":"Account-number value to pair with `paybillNumber` in the M-Pesa prompt. Matches the top-level `accountReference` on this response — surfaced here too so the full paybill block is self-contained.","type":"string"},"balanceAmount":{"description":"Subscriber-scoped outstanding balance returned by the payments rail at request time. Differs from `totalAmount`, which is the subscription-scoped sum that this STK push targets.","type":"number"},"balanceCurrency":{"description":"ISO-4217 currency code of `balanceAmount`.","type":"string"},"externalUserId":{"description":"Subscriber id in the partner's BSS/OSS, if mapped.","type":"string"},"id":{"description":"Share internal subscriber id (the paybill resource owner).","format":"uuid","type":"string"},"paybillNumber":{"description":"M-Pesa paybill business number the subscriber enters into the paybill prompt to pay manually (fallback when the STK push is cancelled or times out).","type":"string"}},"required":["id","externalUserId","paybillNumber","accountReference","balanceAmount","balanceCurrency"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/payment/initiate-deposit":{"post":{"description":"The server derives the push amount from the sum of every PENDING billing cycle and PENDING one-time charge on the subscription at request time — callers do not pre-compute a number. Returns the rail reference, the resolved total, and the `billingCycleIds` + `oneTimeChargeIds` the push is intended to settle — the asynchronous C2B callback drives the authoritative cycle-by-cycle settlement. Returns 400 with `{ code: \"NOTHING_TO_PAY\" }` when there is nothing outstanding. `body.phone` is an STK-push-only override (falls back to the subscriber's stored phone when omitted) and never mutates the subscriber record.","operationId":"SubscriptionsController_initiateDeposit_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateDepositRequestDto"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/InitiateDepositResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"STK push accepted by the rail."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Initiate a deposit (M-Pesa STK push covering the subscription’s outstanding billing cycles + one-time charges)","tags":["Subscriptions"]}}}}
```

## Activate a subscription, skipping the initial payment

> "Create account, payment later" onboarding flow — activates the subscription via the same path as activate, but the initial cycle is opened with \`paymentStatus = WAIVED\` and no activation-grace clock. Payment-instructions messaging (paybill number + account reference) is dispatched to the subscriber so they can pay later. Idempotent — repeat calls return the same \`ACTIVATED-SKIPPED\` terminal without re-opening the cycle.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"ActivateSubscriptionResponseDto":{"properties":{"amount":{"type":"number"},"currency":{"type":"string"},"cycleId":{"format":"uuid","type":"string"},"endDate":{"format":"date-time","type":"string"},"message":{"description":"Human-readable reason when terminal is DEFERRED or FAILED.","type":"string"},"paymentStatus":{"enum":["PENDING","EXTERNAL","PAID","WAIVED","SETTLEMENT_FAILED"],"type":"string"},"planId":{"format":"uuid","type":"string"},"startDate":{"format":"date-time","type":"string"},"subscriberId":{"format":"uuid","type":"string"},"subscriptionId":{"format":"uuid","type":"string"},"terminal":{"description":"Activation outcome. `DEFERRED` means a prerequisite is missing (CPE credentials, plan assignment).","enum":["ACTIVATED-PAID","ACTIVATED-PENDING-PAYMENT","DEFERRED","FAILED"],"type":"string"}},"required":["terminal","subscriberId","subscriptionId"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/skip-payment":{"post":{"description":"\"Create account, payment later\" onboarding flow — activates the subscription via the same path as activate, but the initial cycle is opened with `paymentStatus = WAIVED` and no activation-grace clock. Payment-instructions messaging (paybill number + account reference) is dispatched to the subscriber so they can pay later. Idempotent — repeat calls return the same `ACTIVATED-SKIPPED` terminal without re-opening the cycle.","operationId":"SubscriptionsController_skipPayment_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/ActivateSubscriptionResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"Activation outcome."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Activate a subscription, skipping the initial payment","tags":["Subscriptions"]}}}}
```

## Preview a plan swap (dry run)

> Side-effect-free dry run for the plan-swap confirmation flow — nothing is written and no downstream events fire. Decision discrimination mirrors \`PATCH /v1/subscriptions/:id\` so the predicted outcome (\`applied\` / \`queued\` / \`recorded\` / \`no-op\` / \`rejected\`) matches what would actually happen on commit.

```json
{"openapi":"3.0.0","info":{"title":"Share API","version":"1.0"},"tags":[{"description":"A Subscription binds a Subscriber to a Plan on a specific demarcation point and carries the PPPoE credentials. Supports plan change (`PATCH ... planId`), credential rotation, override application (price / speed / duration per Schedule H), and per-subscription activation/deactivation. See the Subscription states concept guide for the state machine.","name":"Subscriptions"}],"security":[{"X-Access-Secret":[]},{"X-Access-Id":[]}],"components":{"securitySchemes":{"X-Access-Secret":{"description":"Provider Access Secret Key (JWT)","in":"header","name":"X-Access-Secret","type":"apiKey"},"X-Access-Id":{"description":"Provider Access ID","in":"header","name":"X-Access-Id","type":"apiKey"}},"schemas":{"ApiResponseDto":{"properties":{},"type":"object"},"SwapPreviewResponseDto":{"properties":{"predictedCoaPush":{"description":"Present only when `predictedResult=applied`. `true` when the target plan’s effective speed differs from the subscription’s current effective speed AND the subscription is currently ACTIVE — a CoA push would be enqueued.","type":"boolean"},"predictedQueuedEffectiveDate":{"description":"Present only when `predictedResult=queued`. End of the current active billing cycle — the point at which the renewal tick would promote `nextPlanId` → `planId`.","format":"date-time","type":"string"},"predictedResult":{"description":"Predicted swap-rule outcome.","enum":["applied","queued","recorded","no-op","rejected"],"type":"string"},"rejectionDetails":{"allOf":[{"$ref":"#/components/schemas/SwapPreviewRejectionDetailsDto"}],"description":"Present only when `predictedResult=rejected`. Mirrors the error shape the real update endpoint would throw."}},"required":["predictedResult"],"type":"object"},"SwapPreviewRejectionDetailsDto":{"properties":{"code":{"enum":["SUBSCRIPTION_TERMINAL","PLAN_DISABLED","CONTACT_SHARE","PLAN_PRICE_BELOW_FLOOR"],"type":"string"},"details":{"description":"Code-dependent detail bag. SUBSCRIPTION_TERMINAL carries `status`; CONTACT_SHARE carries `downloadSpeedMbps` + `maxSpeedMbps`; PLAN_PRICE_BELOW_FLOOR carries `downloadSpeedMbps`, `minPriceKes`, `providedPriceKes`; PLAN_DISABLED is detail-less.","type":"object"}},"required":["code"],"type":"object"}}},"paths":{"/v1/subscriptions/{id}/swap-preview":{"get":{"description":"Side-effect-free dry run for the plan-swap confirmation flow — nothing is written and no downstream events fire. Decision discrimination mirrors `PATCH /v1/subscriptions/:id` so the predicted outcome (`applied` / `queued` / `recorded` / `no-op` / `rejected`) matches what would actually happen on commit.","operationId":"SubscriptionsController_swapPreview_v1","parameters":[{"description":"Subscription identifier (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Target plan id to evaluate the swap onto.","in":"query","name":"planId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiResponseDto"},{"properties":{"data":{"$ref":"#/components/schemas/SwapPreviewResponseDto"},"success":{"type":"boolean"}}}]}}},"description":"Predicted swap outcome for the supplied target plan."},"400":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"rejectionReasons":{"items":{"properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"type":"object"},"type":"array"},"success":{"type":"boolean"}}}}},"description":"Validation failed"},"401":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Unauthorized — missing or invalid credentials"},"403":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Forbidden — insufficient permissions"},"404":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Resource not found"},"408":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Request timeout"},"500":{"content":{"application/json":{"schema":{"properties":{"error":{"type":"string"},"success":{"type":"boolean"}}}}},"description":"Internal server error"}},"summary":"Preview a plan swap (dry run)","tags":["Subscriptions"]}}}}
```
