---
title: "Retrieve an import report (Beta)"
method: GET
path: "/migrations/{id}"
tags: ["Migrations"]
---

# Retrieve an import report (Beta)

`GET /migrations/{id}`

## Request

- Base URL: `https://api.groundmail.dev`
- URL: `https://api.groundmail.dev/migrations/{id}`
- Auth: HTTP bearer

The stored report of one import, with every request merged: each domain (with its `dns_plan`), webhook and template, suppression totals and skip reasons, errors, next steps, the code change and the agent prompt. Webhook signing secrets are not stored, so `secret` is always null here.

## Path parameters

- `id` string, uuid, required

## Response `200`

The import report

- MigrationResponse
  - `migration` Migration, required
    - `id` string, uuid, required: Shared by every request of one import
    - `provider` 'sendgrid' | 'postmark' | 'mailgun', required
    - `dry_run` boolean, required
    - `status` 'in_progress' | 'completed' | 'partial' | 'failed', required: `partial` when some items or resources could not be imported (each is listed); `failed` when nothing could be read.
    - `started_at` string, date-time, required
    - `resources` string[], required
    - `has_more` boolean, required
    - `next_cursor` string, nullable, required
    - `retry_after_seconds` integer, nullable: Wait this long before continuing (the provider rate-limited the import).
    - `domains` object
      - `totals` MigrationTotals: Running totals for the whole import. Keys: `found`, `imported`, `skipped`, `failed`; templates add `needs_attention`; suppressions add `already_suppressed`, `bounce`, `complaint`, `unsubscribe`, `manual` and `product_opt_out` (opt-outs that only covered some of your mail at the old provider; they stop product email only). In a dry run `imported` counts what would be imported.
      - `items` object[]: Domains handled by this request
        - `name` string
        - `status` 'imported' | 'would_import' | 'needs_attention' | 'skipped' | 'failed'
        - `domain_id` string, nullable
        - `verified_at_source` boolean, nullable
        - `records` object[]: DNS records to publish (also available from GET /domains/{id})
          - `type` string
          - `host` string
          - `value` string
          - `purpose` string
        - `dns_plan` MigrationDnsPlan
          - `checked` boolean, required: False when DNS could not be read; every record is then listed as `add`.
          - `changes` MigrationDnsChange[], required
            - `action` 'add' | 'update' | 'keep' | 'done', required: `add` a new record; `update` the record at this name to `value` (for SPF, our include added to your existing record, never a second SPF record); `keep` yours as it is (for example your DMARC record); `done` when it is already published.
            - `type` string, required
            - `host` string, required
            - `value` string, required: The value to publish (for `keep`, what is there now)
            - `purpose` string, required
            - `current` string, nullable, required: What this name holds today, when it holds something relevant
            - `note` string, nullable, required
          - `keep_old_records` string, required: Which of the old provider's records to keep while you switch, and when to remove them
        - `dashboard_url` string, nullable
        - `message` string, nullable
    - `webhooks` object
      - `totals` MigrationTotals: Running totals for the whole import. Keys: `found`, `imported`, `skipped`, `failed`; templates add `needs_attention`; suppressions add `already_suppressed`, `bounce`, `complaint`, `unsubscribe`, `manual` and `product_opt_out` (opt-outs that only covered some of your mail at the old provider; they stop product email only). In a dry run `imported` counts what would be imported.
      - `items` object[]
        - `url` string
        - `status` 'imported' | 'would_import' | 'needs_attention' | 'skipped' | 'failed'
        - `webhook_id` string, nullable
        - `secret` string, nullable: Signing secret of a webhook this request created. Shown once.
        - `enabled` boolean: Imported webhooks start disabled until your handler accepts Groundmail events.
        - `source_events` string[]
        - `events` string[]
        - `unmapped_events` string[]
        - `message` string, nullable
    - `templates` object
      - `totals` MigrationTotals: Running totals for the whole import. Keys: `found`, `imported`, `skipped`, `failed`; templates add `needs_attention`; suppressions add `already_suppressed`, `bounce`, `complaint`, `unsubscribe`, `manual` and `product_opt_out` (opt-outs that only covered some of your mail at the old provider; they stop product email only). In a dry run `imported` counts what would be imported.
      - `items` object[]
        - `source_id` string
        - `name` string
        - `status` 'imported' | 'would_import' | 'needs_attention' | 'skipped' | 'failed'
        - `template_id` string, nullable
        - `alias` string, nullable
        - `published` boolean
        - `variables` string[]
        - `notes` string[]: What changed in conversion, and anything that did not convert
        - `message` string, nullable
    - `suppressions` object
      - `totals` MigrationTotals: Running totals for the whole import. Keys: `found`, `imported`, `skipped`, `failed`; templates add `needs_attention`; suppressions add `already_suppressed`, `bounce`, `complaint`, `unsubscribe`, `manual` and `product_opt_out` (opt-outs that only covered some of your mail at the old provider; they stop product email only). In a dry run `imported` counts what would be imported.
      - `skipped_reasons` object
      - `estimated` boolean
    - `errors` object[], required: Resources that could not be read at all (for example, a key without that permission)
      - `resource` string
      - `code` string
      - `message` string
    - `notes` string[], required
    - `attention` string[], required: What you still need to do (publish DNS, enable webhooks, review drafts)
    - `template_map` object[], required: Provider template id → Groundmail alias, for updating your send calls
      - `source_id` string
      - `alias` string
    - `code_changes` object[], nullable: When the import has finished, the send call before and after, per stack
      - `stack` 'node' | 'python' | 'curl'
      - `label` string
      - `diff` string
    - `agent_prompt` string, nullable: When the import has finished, a prompt for your coding agent to make the code change

## Other responses

- `401`: Missing or invalid API key
- `404`: No import with this id in your workspace (previews are not stored)

---

[API](https://skmtc.dev/groundmail/apis/groundmail-api.md) · [All operations](https://skmtc.dev/groundmail/apis/groundmail-api/llms.txt) · [OpenAPI document](https://skmtc.dev/groundmail/apis/groundmail-api/revisions/479821c9fecf?raw)
