Skip to main content
The renewal cycle endpoints expose the Admin renewal queue and let you act on individual cycles. You can list scheduled or failed cycles for DataTable views, fetch a full detail payload including attempt history and approval state, force-run a cycle manually, and approve or reject pending subscription changes before a cycle executes. All routes require an authenticated Medusa Admin user. All mutations are workflow-backed and return the refreshed detail payload.
All routes require an authenticated Medusa Admin user. Unauthenticated requests return 401.

Status values

ValueMeaning
scheduledCycle is queued for its scheduled date
processingCycle execution is in progress
succeededCycle completed successfully
failedCycle failed; attempt history is available in detail
Approval status values: pending, approved, rejected. When approval is not required, the approval object returns status: null. Attempt status values: processing, succeeded, failed.

GET /admin/renewals

Returns the paginated renewal queue for Admin DataTable views.

Query parameters

limit
number
Number of results per page.
offset
number
Zero-based result offset for pagination.
q
string
Free-text search across subscription reference, customer name, and product title.
order
string
Field to sort by. Database-backed: scheduled_for, updated_at, created_at, status, approval_status, processed_at. In-memory: last_attempt_status, subscription_reference, customer_name, product_title, order_display_id.
direction
string
Sort direction. One of asc or desc.
status
string | string[]
Filter by cycle status.
approval_status
string | string[]
Filter by approval status.
scheduled_from
string
ISO datetime lower bound for scheduled_for.
scheduled_to
string
ISO datetime upper bound for scheduled_for.
last_attempt_status
string | string[]
Filter by the status of the most recent attempt.
subscription_id
string
Filter to renewals for a specific subscription.
generated_order_id
string
Filter by the ID of the order generated by a renewal.

Response

renewals
object[]
required
Array of renewal cycle list items.
count
number
required
Total matching records.
limit
number
required
Page size used.
offset
number
required
Result offset used.
Response example
{
  "renewals": [
    {
      "id": "re_123",
      "status": "scheduled",
      "subscription": {
        "subscription_id": "sub_123",
        "reference": "SUB-001",
        "status": "active",
        "customer_name": "Jane Doe",
        "product_title": "Coffee Subscription",
        "variant_title": "1 kg",
        "sku": "COFFEE-1KG"
      },
      "scheduled_for": "2026-04-15T10:00:00.000Z",
      "effective_scheduled_for": "2026-04-15T10:00:00.000Z",
      "last_attempt_status": "failed",
      "last_attempt_at": "2026-04-15T10:02:00.000Z",
      "approval": {
        "required": true,
        "status": "pending",
        "decided_at": null,
        "decided_by": null,
        "reason": null
      },
      "generated_order": null,
      "updated_at": "2026-04-15T10:02:00.000Z"
    }
  ],
  "count": 1,
  "limit": 20,
  "offset": 0
}

Errors

CodeErrorMeaning
400invalid_dataInvalid query parameter shape, unsupported query value, or unsupported sort field

GET /admin/renewals/:id

Returns the full detail payload for a single renewal cycle, including the full attempt history and operational metadata.

Path parameters

id
string
required
Renewal cycle ID.

Response

Returns a renewal object with all list fields plus:
renewal
object
required
Response example
{
  "renewal": {
    "id": "re_123",
    "status": "failed",
    "subscription": {
      "subscription_id": "sub_123",
      "reference": "SUB-001",
      "status": "active",
      "customer_name": "Jane Doe",
      "product_title": "Coffee Subscription",
      "variant_title": "1 kg",
      "sku": "COFFEE-1KG"
    },
    "scheduled_for": "2026-04-15T10:00:00.000Z",
    "effective_scheduled_for": "2026-04-15T10:00:00.000Z",
    "last_attempt_status": "failed",
    "last_attempt_at": "2026-04-15T10:02:00.000Z",
    "approval": {
      "required": true,
      "status": "approved",
      "decided_at": "2026-04-15T09:55:00.000Z",
      "decided_by": "user_123",
      "reason": "approved for processing"
    },
    "generated_order": {
      "order_id": "order_123",
      "display_id": 1001,
      "status": "pending"
    },
    "updated_at": "2026-04-15T10:03:00.000Z",
    "created_at": "2026-04-10T10:00:00.000Z",
    "processed_at": "2026-04-15T10:03:00.000Z",
    "last_error": null,
    "pending_changes": {
      "variant_id": "variant_456",
      "variant_title": "2 kg",
      "frequency_interval": "month",
      "frequency_value": 2,
      "effective_at": null
    },
    "attempts": [
      {
        "id": "reatt_123",
        "attempt_no": 1,
        "status": "failed",
        "started_at": "2026-04-15T10:00:00.000Z",
        "finished_at": "2026-04-15T10:02:00.000Z",
        "error_code": "renewal_failed",
        "error_message": "payment failed",
        "payment_reference": null,
        "order_id": null
      }
    ],
    "metadata": {
      "last_trigger_type": "manual",
      "last_correlation_id": "renewal-admin-force-uuid"
    }
  }
}

Errors

CodeErrorMeaning
404not_foundRenewal cycle does not exist

POST /admin/renewals/:id/force

Manually triggers execution for a renewal cycle, ignoring its scheduled date.

Path parameters

id
string
required
Renewal cycle ID.

Body parameters

reason
string
Optional reason for the manual trigger.
Request example
{
  "reason": "manual retry after review"
}

Errors

CodeErrorMeaning
404not_foundRenewal cycle does not exist
409conflictCycle is already processing
409conflictCycle already succeeded; duplicate execution is blocked
409conflictCycle is not in a forceable state
409conflictCycle requires approved changes before force-run
409conflictLinked subscription is not eligible for renewal
400invalid_dataCurrent Plans & Offers policy blocks the pending change

POST /admin/renewals/:id/approve-changes

Approves pending subscription changes for a renewal cycle that requires approval before execution.

Path parameters

id
string
required
Renewal cycle ID.

Body parameters

reason
string
Optional approval reason.
Request example
{
  "reason": "approved after review"
}

Errors

CodeErrorMeaning
404not_foundRenewal cycle does not exist
409conflictApproval is not required for this cycle
409conflictApproval was already decided for this cycle

POST /admin/renewals/:id/reject-changes

Rejects pending subscription changes for a renewal cycle. reason is required for rejections.

Path parameters

id
string
required
Renewal cycle ID.

Body parameters

reason
string
required
Reason for rejection. Required.
Request example
{
  "reason": "pending changes are not valid for this cycle"
}

Errors

CodeErrorMeaning
400invalid_dataMissing or invalid reason
404not_foundRenewal cycle does not exist
409conflictApproval is not required for this cycle
409conflictApproval was already decided for this cycle