# Sending Multiple ANS Objects to Arc XP Services Using Migration Center

Source: https://dev.arcxp.com/migration-center/developer-docs/sending-multiple-ans-objects-to-arc-xp-services-using-migration-center/

As a developer for an organization moving its content from a legacy CMS to Arc XP, you have worked to map the source fields from your legacy CMS content and are writing the adapter that transforms the legacy content into Arc XP Native Specification (ANS) and moves the ANS into Arc XP applications. You will be using the Migration Center APIs. You have an example source document from a legacy CMS that you will work out how to send through Migration Center. The source document is a story, and that story contains an image. You realize that to fully convert this story so that it looks the same in Arc XP means that you also will need to convert the image, resulting in two items of ANS to send to Arc XP.

With the transformed story and image ANS at hand, you can explore the options of how to send both these ANS items through to the Arc XP services using Migration Center.

## Option 1: Migration Center API `/ans` Endpoint

The `/ans` API endpoint is used to send a single piece of ANS into the Arc XP system. The endpoint accepts a POST with a few optional query parameters and a payload of a Migration Center JSON object formatted with specific keys. One of the keys in the Migration Center JSON object holds the ANS object. Other keys provide instructions that control the downstream API requests that Migration Center will be making.

You can include three query parameters with the `/ans` API endpoint:

- `website`: If used, this value becomes a tag the MC reports. You can query Migration Center’s reporting API `/summary` endpoint to find all requests that were tagged as belonging to this value. The value of this parameter should be the ANS content’s primary website ID.
- `groupId`: If used, this value is an arbitrary value used to tag requests coming through the MC API. You can query content flagged with the same groupId value by using the MC Reporting API.
- `priority`: input either `historical` or `live` values. This parameter is applicable only when sending a story object in the ANS key. This value sets the `Arc-Priority` header in Draft API. If not included, the MC API defaults this value to `historical`.

Terminal window

```bash
curl --request POST \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/content/ans
    ?website=my-website-id
    &groupId=ingested-on-march11
    &priority=historical' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{...}'  // the Migration Center JSON object
```

> **Note:**
> 
> The `website=` query parameter is intended to hold the Site Service website ID tied to the content’s canonical URL. The value passed to this parameter is not validated, so you can decide to use this parameter as another arbitrary grouping value for filtering. However, doing so might complicate support requests relating to the behavior of this API endpoint.

### Send one request per ANS object to the `/ans` endpoint

Sending the story and image through Migration Center requires two separate calls to the `/ans` API endpoint. In order to query the Migration Center Reporting API and return only these two records, filtering out all past Migration Center ingestions, you must attach filter values to each record. You can make use of the optional query parameters available on the `/ans` API endpoint, passing the same `website=` and `groupId=` query parameters in each request.

### Migration Center API JSON object for `/ans` endpoint

The JSON object sent in the payload of the `/ans` API endpoint has one required key, `ANS`, which holds the ANS of an Arc XP object. The ANS in this key is validated when the request is submitted, and the request fails if the ANS is poorly constructed.

- `ANS`: The JSON of the Arc XP content object: a story, gallery, video, image, tag, or author object.
- `circulation`: The JSON of a story’s circulation data. This key is applicable only when a story object is in the `ANS` key.
- `operation`: A JSON object containing data that registers a future publication operation on a story. This key is applicable only when a story object is in the ANS key.
- `arcAdditionalProperties`: A JSON object that contains commands to affect the behavior of specific downstream Arc XP APIs. Migration Center constructs calls to these APIs depending on the ANS type. This key is applicable only when a story or video object is in the ANS key.

```json
{
  "ANS": {},         // the ANS JSON
  "circulation": [], // circulations for a story document
  "operation": [],   // scheduled publishing operations for a story document
  "arcAdditionalProperties": {}  // additional commands controlling the migration process, broken down by ANS type
}
```

### Request 1: Story

- is sending story ANS
- is sending a story circulation
- is sending MC reporting tags in the query parameters

> **Note:**
> 
> The query parameters in the code snippet are broken into separate lines for readability.

Terminal window

```bash
curl --request POST \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/content/ans
    ?website=my-website-id
    &groupId=ingested-on-march11 \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
  {
    "ANS": {
      "type": "story",
      "version": "0.10.7",
      "_id": "ANSIDAND26MORECHARACTERS",
      "headlines": {
        "basic": "The origin of the bicycle, a history"
      },
      "source": {
        "system": "alc",
        "source_id": "123"
      },
      "owner": {
        "id": "{{org}}"
      }
    },
    "circulation": [{
        "document_id": "ANSIDAND26MORECHARACTERS",
        "website_id": "cyclist-daily",
        "website_url": "/main/origin-of-bicycle-history/",
        "website_primary_section": {
            "type": "reference",
            "referent": {
                "id": "/main",
                "type": "section",
                "website": "cyclist-daily"
            }
        },
        "website_sections": [
            {
                "type": "reference",
                "referent": {
                    "id": "/main",
                    "type": "section",
                    "website": "cyclist-daily"
                }
            }
        ]
    }]
  }
'
```

### Request 2: Image

- is sending image ANS
- is sending Migration Center reporting tags in the query parameters

> **Note:**
> 
> The query parameters in the code snippet are broken into separate lines for readability.

Terminal window

```bash
curl --request POST \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/content/ans
    ?website=my-website-id
    &groupId=ingested-on-march11 \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
  {
    "ANS": {
      "type": "image",
      "version": "0.10.7",
      "_id": "ANSIDFORANIMAGESTILL26CHARS",
      "owner": {
        "id": "{{org}}"
      },
      "source": {
        "system": "Unsplash",
        "source_id": "1555848960-c881e30379c"
      },
            "additional_properties": {
        "originalName": "olympic-medal.jpg",
        "version": 0,
        "originalUrl": "https://images.unsplash.com/photo-1555848960-c881e30379c0"
      }
    }
  }
'
```

## Option 2: Migration Center API `/bulk` Endpoint

Migration Center has a `/bulk` API endpoint that allows you to send both the story and image ANS objects in one request. When using the `/bulk` API endpoint, the structure of the Migration Center JSON object changes. Migration Center JSON for `/bulk` API allows a list of ANS objects to be part of the request payload, and adds extra keys per object to hold what had been query parameters on the `/ans` endpoint.

Terminal window

```bash
curl --request POST \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/content/ans/bulk \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{...}'  // Migration Center JSON objects for /bulk
```

Notice that the `/bulk` endpoint does not support query parameters at the endpoint’s URL. These are represented instead in the Migration Center JSON object for `/bulk`.

### Migration Center API JSON object for /bulk endpoint

The `/bulk` version of the Migration Center JSON object contains four top-level keys:

- `content` \- Contains a list of objects. Each item in this list contains the information about an ANS document and the Migration Center request options that affect the object. See our maximum and recommended number of items below.
- `defaultPriority` \- Provides the default value for `Arc-Priority` header. All items with story ANS in the `content` key use this value, unless it is overridden specifically per ANS object.
- `defaultWebsite`, `defaultGroupId` \- Provides the default value for filter that you can use with the `/report` API endpoint. You can override these keys per ANS object in the content list.

The `/ans` version of the Migration Center JSON object is reused as a nested object in the `/bulk` Migration Center JSON, as item in the content list. When used in this list, the objects also can contain three optional keys to mimic the query parameters accepted by the `/ans` API endpoint. If used, these nested values override any default values set by the top level `/bulk` Migration Center JSON keys `defaultPriority`, `defaultWebsite`, and `defaultGroupId`.

In one call to the `/bulk` API endpoint, you can pass up to 50 nested objects in the `content` key. We recommend limiting the number of items to 25 to optimize bulk ingestion.

```json
  // MC JSON object for /bulk
  {
          "defaultPriority": "historical",
          "defaultWebsite": "my-website",
          "defaultGroupId": "test_batch_bicycles",
          "content": [
      // MC json object normally used at /ans endpoint
      {
        "ANS": { ... },  // queried for in reporting api using filters website: my-website and groupId: test_batch_bicycles
        "circulation": [],
        "operation": [],
        "arcAdditionalProperties": {}
      },
      // /ans MC JSON object and keys that overrride default values set in the parent object
      {
        "ANS": { ... },  // queried for in reporting api using filters website: my-website2 and groupId: test-batch-2
        "priority": "live",
        "website": "my-website2",
        "groupId": "test-batch-2"
      },
      {
        "ANS": { ... }  // queried for in reporting api using filters website: my-website and groupId: test_batch_bicycles
      }
      // up to 50 ANS documents allowed
    ]
  }
```

The example shows that you can override the default values set in the parent object by including specific keys in the objects in the content list. However, this is not necessarily the best idea. The best practice if you are sending many objects through the `/bulk` API is to have them all carry the same filters and priority so you can query for just these items at the `/report` API endpoint.

Additionally, you should always use the `historical` priority value when migrating content from a legacy CMS.

Behind the scenes, the `/bulk` API endpoint splits the content key into separate requests. If the objects in the content list have specific values for priority, website or group ID, then those values are applied in place of the default values. Otherwise, the defaults at the top level of the payload are applied to all items in the content list. Because each content item results as a separate request, when a POST to the `/bulk` endpoint is successful, the API returns a very generic message saying that only the request was accepted.

```json
// 202 Accepted
{
        "success": true,
        "message": "Bulk ANS content has been accepted and added to the queue for migration."
}
```

To check on the status of the items in the POST to `/bulk`, you must construct a `/report/detail` API call for each separate ANS ID contained in the content list. Or, if you included values in the `defaultWebsite`, `defaultGroupId`, `content.website`, or `content.groupId` keys, you can query the `/report/summary` API endpoint to filter for only these records.

### Sending one request for up to 50 ANS objects to the /bulk endpoint

Because the `/bulk` API endpoint can accept up to 50 ANS records, we can use this to send both the story and the image into Arc XP.

Terminal window

```bash
curl --request POST \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/content/ans/bulk \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
  {
          "defaultPriority": "historical",
          "defaultWebsite": "my-website",
          "defaultGroupId": "ingested-on-march11",
          "content": [
      {
        "ANS": {
          "type": "story",
          "version": "10.0.7",
          "_id": "ANSIDAND26MORECHARACTERS",
          "headlines": {
            "basic": "The origin of the bicycle, a history"
          },
          "source": {
            "system": "alc",
            "source_id": "123"
          },
          "owner": {
            "id": "{{org}}"
          }
        },
        "circulation": [{
            "document_id": "ANSIDAND26MORECHARACTERS",
            "website_id": "cyclist-daily",
            "website_url": "/main/origin-of-bicycle-history/",
            "website_primary_section": {
                "type": "reference",
                "referent": {
                    "id": "/main",
                    "type": "section",
                    "website": "cyclist-daily"
                }
            },
            "website_sections": [
                {
                    "type": "reference",
                    "referent": {
                        "id": "/main",
                        "type": "section",
                        "website": "cyclist-daily"
                    }
                }
            ]
        }]
      },
      {
        "ANS": {
          "type": "image",
          "version": "0.10.7",
          "_id": "ANSIDFORANIMAGESTILL26CHARS",
          "owner": {
            "id": "{{org}}"
          },
          "source": {
            "system": "Unsplash",
            "source_id": "1555848960-c881e30379c"
          },
                "additional_properties": {
            "originalName": "olympic-medal.jpg",
            "version": 0,
            "originalUrl": "https://images.unsplash.com/photo-1555848960-c881e30379c0"
          }
        }
      }
    ]
  }
'
```

## Reporting on Status

Use the `/report` APIs to investigate status of the ANS items sent to the Arc XP services through the Migration Center APIs. No matter if the ANS items were sent through on the `/ans` or `/bulk` API endpoints, you must query the `/report` APIs to uncover what happened with ANS after having been POSTed.

With the ANS ID of the object that was POSTed and the Arc XP content type, you can query for the full Migration Center record at the `/report/detail` API endpoint. Both parameters are required.

Terminal window

```bash
// return the status details of the story
curl --request GET \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/report/detail
  ?ansType=story
  &ansId=ANSIDAND26MORECHARACTERS' \
  --header 'Authorization: Bearer <token>'

// return the status details of the image
curl --request GET \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/report/detail
  ?ansType=story
  &ansId=ANSIDFORANIMAGESTILL26CHARS' \
  --header 'Authorization: Bearer <token>'
```

With the filter values from the `/ans` endpoint’s query parameters, or included in the payload of the `/bulk` endpoint, you can query for a series of status records at the `/report/summary` API endpoint. The results include the ANS ID of each record that matches the filter terms. If necessary, you can take an ANS ID from the result and follow up with a query for its full detail at `/report/detail`. You can filter `/report/summary` by both `website` and `groupId` together, or filter individually.

Terminal window

```bash
curl --request GET \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/report/summary
  ?website=my-website
  &groupId=ingested-on-march11' \
  --header 'Authorization: Bearer <token>'
```

The `/report/summary` API endpoint also works with just a `status` query parameter. This filter will bring back results of all records with the `status` state.

Terminal window

```bash
curl --request GET \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/report/summary
  ?status=Success' \
  --header 'Authorization: Bearer <token>'
```

> **Statuses**: Pending, Queued, Processing, Success, Circulated, Published, ValidationFailed, FailStory

The `/report/status/count` API endpoint shows the raw counts of how many items you have of each kind in each status. You can filter this endpoint by `startDate` and `endDate` in YYYY-MM-DD format, and the endpoint accepts two optional query parameters to sort items inside the response.

Terminal window

```bash
curl --request GET \
  --url 'https://api.{{org}}.arcpublishing.com/migrations/v3/report/status/count
  ?startDate=2022-01-01
  &endDate=2023-01-01
  &sort=createDate
  &sortOrder=DESC' \
  --header 'Authorization: Bearer <token>'

{
        "historical": {
                "total": 11381,
                "ansTypes": {
                        "gallery": {
                                "FailGallery": 15,
                                "Success": 54,
                                "ValidationFailed": 9
                        },
                        "image": {
                                "FailPhoto": 309,
                                "Success": 6172,
                                "ValidationFailed": 51
                        },
                        "story": {
                                "Circulated": 8,
                                "FailStory": 176,
                                "Published": 4547,
                                "ValidationFailed": 38
                        },
                        "video": {
                                "FailVideo": 1,
                                "Success": 1
                        }
                }
        }
}
```
