Ingestion API — Integration Guide

Last Updated: 2026-08-25  | 
The Ingestion API is designed for bulk content seeding, automated imports, and ad hoc content fixes. It provides three atomic upsert endpoints: one for complete site trees (site + all pages + containers + items), one for standalone page trees (page + all containers + all items), and one for themes (theme + all tokens). All support optional immediate publish or scheduled publish within the same request. Consumers integrate via the MobileContent.ApiClient.Ingest NuGet package (IIngestApiClient).
Auth: Ingestion endpoints should be secured with API key or service-to-service OAuth before production. Currently [AllowAnonymous] for development.

NuGet Setup

// Program.cs
services.AddHttpClient<IIngestApiClient, IngestApiClient>(client =>
{
    client.BaseAddress = new Uri("https://gatewayapi.alpa.org");
    // Add API key header or service-to-service auth
});

Ingest Page

Delivers a complete page tree in one atomic operation. If the pageKey already exists within the given site, the existing draft rows (all containers and items) are fully replaced. If the page does not exist, it is created fresh. Both paths result in the same normalized database rows.

POST  /api/mobilecontent/ingest/page   → PageIngestionResponse

PageIngestionRequest

FieldTypeRequiredNotes
siteKeystringYesParent site must already exist.
pageKeystringYesUnique within the site. Lowercase normalized.
titlestring?NoDisplay title.
sortOrderintNoDefault 0.
activeThemestring?NoPage-level theme override by key (e.g. brand-dark). Resolved to a GUID on save.
containersIngestContainerDto[]NoFull container+item tree. Replaces all existing containers on upsert.
publishImmediatelyboolNoDefault true. When true, page is snapshotted and set to Published within the same transaction. Ignored when scheduledPublishDate is a future time.
publishNotesstring?NoOptional note attached to the snapshot when published.
scheduledPublishDateDateTime?NoUTC. When set to a future time, overrides publishImmediately — the page lands as Draft and the background scheduler publishes it at the specified time.
previewUsersstring[]NoUser/group IDs for draft preview access. Replaces any existing preview users on upsert. Ignored when publishImmediately is true.

IngestContainerDto fields

FieldTypeRequiredNotes
containerTypestringYesMust be a valid ContainerType enum name.
titlestring?No
viewAllTextstring?No
viewAllLinkstring?No
columnsint?No
backgroundTokenstring?No
cornerRadiusTokenstring?No
paddingTokenstring?No
isSortableboolNoDefault true.
sortOrderintNo
itemsIngestItemDto[]NoItems nested within this container.

Each IngestItemDto carries the same fields as AdminItemRequest — see the Admin Portal guide for the full field list.

PageIngestionResponse

FieldTypeDescription
idGuidDatabase ID of the page.
keystringNormalized page key.
titlestring?Display title of the page.
activeThemeIdGuid?GUID of the resolved active theme override for this page, if any.
activeThemeKeystring?Key of the active theme override for this page, if any.
workflowStateintResulting state: 0=Draft, 1=Published.
wasUpsertedboolTrue when an existing page was replaced rather than created fresh.
snapshotVersionNumberint?Populated when the page was published immediately.
scheduledPublishDateDateTime?Populated when the page was deferred to a scheduled publish.
processedAtDateTimeUTC timestamp of the ingestion.

Example: Seed a page and publish immediately

POST /api/mobilecontent/ingest/page
{
  "siteKey": "ual",
  "pageKey": "ual-home",
  "title": "Welcome",
  "sortOrder": 1,
  "publishImmediately": true,
  "publishNotes": "Initial seed",
  "containers": [
    {
      "containerType": "VerticalStack",
      "sortOrder": 0,
      "items": [
        {
          "itemType": "TextBlock",
          "title": "Welcome to UAL",
          "description": "Your connection to the airline.",
          "sortOrder": 0
        }
      ]
    }
  ]
}

Example: Seed a page as draft only

POST /api/mobilecontent/ingest/page
{
  "siteKey": "ual",
  "pageKey": "ual-news",
  "title": "News",
  "publishImmediately": false,
  "containers": []
}

Ingest Site

Delivers a complete site tree in one atomic operation. If the siteKey already exists, its metadata (description, active theme) is updated. Each page in the payload is upserted — existing draft rows (containers and items) are fully replaced. Pages that previously belonged to the site but are absent from this payload are soft-deleted. Per-page publish flags are honoured within the same transaction.

POST  /api/mobilecontent/ingest/site   → SiteIngestionResponse

SiteIngestionRequest

FieldTypeRequiredNotes
siteKeystringYesUnique site key. Created if it does not exist; updated if it does.
descriptionstringNoHuman-readable description of the site.
activeThemestring?NoSite-level theme key (e.g. brand-dark). Resolved to a GUID on save.
pagesSiteIngestionPageEntry[]NoFull page tree. Pages absent from this list that already exist in the site are soft-deleted.

SiteIngestionPageEntry fields

FieldTypeRequiredNotes
pageKeystringYesUnique within the site. Lowercase normalized.
titlestring?NoDisplay title.
sortOrderintNoDefault 0.
activeThemestring?NoPage-level theme override key. Resolved to a GUID on save.
containersIngestContainerDto[]NoFull container+item tree. Replaces all existing containers on upsert. See IngestContainerDto below.
publishImmediatelyboolNoDefault true. When true, page is snapshotted and set to Published within the same transaction. Ignored when scheduledPublishDate is a future time.
publishNotesstring?NoOptional note attached to the snapshot when published.
scheduledPublishDateDateTime?NoUTC. When set to a future time, overrides publishImmediately — the page lands as Draft and the background scheduler publishes it at the specified time.
previewUsersstring[]NoUser/group IDs for draft preview access. Replaces any existing preview users on upsert. Ignored when publishImmediately is true.

Container and item fields are identical to those used by Ingest Page — see IngestContainerDto fields below.

SiteIngestionResponse

FieldTypeDescription
idGuidDatabase ID of the site.
keystringNormalized site key.
descriptionstringSite description.
activeThemeIdGuid?GUID of the resolved active theme for the site, if any.
activeThemeKeystring?Key of the active theme for the site, if any.
wasUpsertedboolTrue when an existing site was updated rather than created fresh.
deletedPageKeysstring[]Keys of pages that were soft-deleted because they were absent from the payload.
pagesPageIngestionResponse[]Per-page result for every page entry in the request. See PageIngestionResponse.
processedAtDateTimeUTC timestamp of the ingestion.

Example: Seed a full site and publish all pages

POST /api/mobilecontent/ingest/site
{
  "siteKey": "ual",
  "description": "United Airlines",
  "activeTheme": "ual-default",
  "pages": [
    {
      "pageKey": "ual-home",
      "title": "Home",
      "sortOrder": 1,
      "publishImmediately": true,
      "publishNotes": "Initial seed",
      "containers": [
        {
          "containerType": "VerticalStack",
          "sortOrder": 0,
          "items": [
            {
              "itemType": "TextBlock",
              "title": "Welcome to UAL",
              "description": "Your connection to the airline.",
              "sortOrder": 0
            }
          ]
        }
      ]
    },
    {
      "pageKey": "ual-news",
      "title": "News",
      "sortOrder": 2,
      "publishImmediately": true,
      "containers": []
    }
  ]
}

Ingest Theme

Delivers a complete theme with all tokens in one atomic operation. If the key already exists, both the theme metadata and all tokens are fully replaced. Supports optional immediate publish within the same request.

POST  /api/mobilecontent/ingest/theme   → ThemeIngestionResponse

ThemeIngestionRequest

FieldTypeRequiredNotes
keystringYesUnique theme key. Lowercase normalized.
titlestring?NoDisplay title. On upsert, omitting this field preserves the existing title; passing a value always overwrites it.
descriptionstring?NoHuman-readable description. Always overwritten on upsert (set to null to clear).
tokensDictionary<string, string>NoToken path → value pairs (e.g. "Surface/Brand": "#005DAA"). Any valid path is accepted. Known paths are defined in MobDynThemeTokenRegistry; unknown paths are stored without validation. All 91 registry tokens are recommended for a complete theme.
publishImmediatelyboolNoDefault false. When true, theme is snapshotted and set to Published in the same transaction.
publishNotesstring?NoOptional note stored with the snapshot when published.

ThemeIngestionResponse

FieldTypeDescription
idGuidDatabase ID of the theme.
keystringNormalized theme key.
titlestring?Display title of the theme.
descriptionstring?Description of the theme.
wasUpsertedboolTrue when an existing theme was replaced rather than created fresh.
statusstringDraft or Published depending on publishImmediately.
versionNumberint?Snapshot version number. Populated when publishImmediately is true.
tokensDictionary<string, string?>All persisted tokens for the theme, in canonical registry order.

Example: Seed a theme and publish immediately

POST /api/mobilecontent/ingest/theme
{
  "key": "ual-default",
  "description": "United Airlines default theme",
  "publishImmediately": true,
  "publishNotes": "Initial seed from design handoff",
  "tokens": {
    "Surface/Brand":   "#005DAA",
    "Surface/Primary": "#FFFFFF",
    "Text/Primary":    "#1A1A1A",
    "Text/Secondary":  "#6B6B6B"
  }
}

Use Cases