Get a price migration
The subscriptions.migrations.get operation: GET /api/v1/subscriptions/migrations/{id} in the REST API and the subscriptions_migrations_get tool in the MCP server.
/api/v1/subscriptions/migrations/{id}Returns a price migration with its progress: how many subscriptions matched and were scheduled, how many
customers were notified, how many changes were applied at a renewal and how many are still pending, and how
many were skipped (at once, or dropped later because the subscription was canceled or changed again).
status is completed once no change is pending.
At a glance
- REST:
GET /api/v1/subscriptions/migrations/{id} - MCP tool:
subscriptions_migrations_get - Operation ID:
subscriptions.migrations.get - Scope: Brand
- Permission:
subscriptions:read - Risk tier:
read - Dry run: Not supported
- Idempotency: Not needed (read only)
- Modes: Test and live
- Authentication: API key with the
subscriptions:readscope - Since: M5
Request
Path parameters
| Field | Type | Description |
|---|---|---|
id | smig_… ID |
Query parameters
This operation takes no query parameters.
Response
200 OK with a JSON object:
| Field | Type | Description |
|---|---|---|
id | smig_… ID | |
object | "subscription_migration" | |
livemode | boolean | |
brandId | brd_… ID | |
fromPriceId | price_… ID | |
toPriceId | price_… ID | |
currency | string | |
effective | one of next_renewal, date | |
effectiveDate | date-time or null | |
noticeDays | integer | |
filter | object | |
filter.statuses | array of one of incomplete, incomplete_expired, trialing, active, past_due, unpaid, paused, canceled | |
filter.customerIds | array of cus_… ID or null | |
status | one of scheduled, completed | scheduled while changes are still waiting for their renewal; completed once none is. |
counts | object | Progress (spec §16.14). |
counts.matched | integer (at least 0) | Subscriptions on the old price that the filter matched. |
counts.scheduled | integer (at least 0) | Of those, the ones given the change. |
counts.notified | integer (at least 0) | Customers sent their notice. |
counts.applied | integer (at least 0) | Changes applied at a renewal. |
counts.pending | integer (at least 0) | Changes still waiting for their renewal. |
counts.skipped | integer (at least 0) | Matched but not changed: skipped at once (skippedAtCreation), or dropped before their renewal because the subscription was canceled or changed again. |
skippedAtCreation | object | Why matching subscriptions weren't changed: pending_update (another change was already waiting), cancel_scheduled (set to end at its period end). |
revenue | object | The monthly recurring amount of the changed items before and after (licensed items; metered items are billed from usage). |
revenue.mrrBefore | money | |
revenue.mrrAfter | money | |
revenue.mrrDelta | money | |
firstChangeAt | date-time or null | The first scheduled change. |
lastChangeAt | date-time or null | The last scheduled change. |
version | integer | |
createdAt | date-time | |
updatedAt | date-time |
Examples
A migration half applied
GET /api/v1/subscriptions/migrations/smig_01jacq4m3xf0v8w9zq2y7k5n6h
Authorization: Bearer or_test_…
Response (200):
{
"id": "smig_01jacq4m3xf0v8w9zq2y7k5n6h",
"object": "subscription_migration",
"livemode": false,
"brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
"fromPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6p",
"toPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6q",
"currency": "EUR",
"effective": "next_renewal",
"effectiveDate": null,
"noticeDays": 30,
"filter": {
"statuses": ["trialing", "active", "past_due"],
"customerIds": null
},
"status": "scheduled",
"counts": {
"matched": 42,
"scheduled": 40,
"notified": 40,
"applied": 25,
"pending": 14,
"skipped": 3
},
"skippedAtCreation": {
"pending_update": 2,
"cancel_scheduled": 0
},
"revenue": {
"mrrBefore": {
"amount": "400000000",
"currency": "EUR"
},
"mrrAfter": {
"amount": "480000000",
"currency": "EUR"
},
"mrrDelta": {
"amount": "80000000",
"currency": "EUR"
}
},
"firstChangeAt": "2026-11-20T10:00:00.000Z",
"lastChangeAt": "2026-12-19T10:00:00.000Z",
"version": 67,
"createdAt": "2026-10-20T09:00:00.000Z",
"updatedAt": "2026-12-05T10:00:00.000Z"
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
resource_not_found | 404 | No price migration with this ID exists for the brand in this mode. | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
permission_denied | 403 | The credentials can't read this brand's subscriptions. | Ask an organization owner or admin for a role or scope that allows this action. |
It can also return these common errors: validation_failed, api_version_unsupported, authentication_required, api_key_invalid, scope_required, dry_run_not_supported, rate_limited, internal_error.