// PARTNER API · PRIVATE BETA

Platform API

An HTTP surface over the engine that already runs behind the UCP Fluent Shopify app: catalog ingest from the Shopify Admin API, enrichment behind confidence gates, and publishing to Merchant Center, product-page JSON-LD and Shopify's agent catalog.

Private Beta

There is no public sandbox. Credentials and a base URL are issued per partner. The operations below — ingest, gated enrichment, three-rail publishing — run in production today inside the Shopify app. What is in beta is this HTTP surface over them, including the job callbacks, so treat these shapes as a working draft rather than a frozen contract. Request access: anri@ucpfluent.com · info@ucpfluent.com

headers
Authentication

Bearer token on every request. Tokens are issued per partner and scoped to the shops that have installed the app — a token cannot reach a merchant who has not consented.

Authorization: Bearer <partner-token> Idempotency-Key: <uuid> Content-Type: application/json

Base URL is issued with your credentials. All timestamps are ISO 8601, UTC.

POST/v1/catalog/ingestasync

Reads the full catalog from Shopify's Admin API — 250 products per page, cursor-paginated through the Link header — together with 90 days of orders, so per-variant sales aggregates land in the same snapshot.

A large catalog takes minutes to walk, so this returns 202 Accepted with a job_id rather than blocking. Poll the readiness endpoint, or supply callback_url and we POST once the job reaches a terminal state. Enrichment then runs behind confidence gates: high-confidence attributes are eligible to publish, uncertain ones are held for merchant review and counted in the readiness response. Nothing uncertain ships unreviewed.

Body
FieldTypeDescription
shopstring *The merchant’s myshopify.com domain. Must have UCP Fluent installed.
callback_urlstringHTTPS endpoint we POST the terminal job state to. Omit it to poll instead.
request.json
Request body
{
  "shop": "example-store.myshopify.com",
  "callback_url": "https://partner.example.com/hooks/ucp"
}
202_accepted.json
Response · 202 Accepted
{
  "job_id": "job_9f3c1a4e",
  "status": "queued",
  "shop": "example-store.myshopify.com",
  "submitted_at": "2026-08-26T09:14:22Z"
}
GET/v1/catalog/{shop}/readiness

The catalog's current state: the last ingest job, per-rail publish status, and how many attributes are still waiting on merchant approval.

readiness_score is our own 0–100 diagnostic, and pillars shows exactly how it is composed: identity 35, semantics 25, discovery 25, conversational 15. It is a number we compute to tell you where a catalog is weak — no search engine or agent reads it, and it is not a ranking signal. Each entry in surfaces carries a state of synced, publishing, stale or blocked.

Path
FieldTypeDescription
shopstring *The same myshopify.com domain used at ingest.
readiness.json
Response · 200 OK
{
  "shop": "example-store.myshopify.com",
  "last_ingest": {
    "job_id": "job_9f3c1a4e",
    "status": "complete",
    "variants_ingested": 1450,
    "completed_at": "2026-08-26T09:21:40Z"
  },
  "readiness_score": 82,
  "pillars": {
    "identity":       { "score": 31, "max": 35 },
    "semantics":      { "score": 22, "max": 25 },
    "discovery":      { "score": 25, "max": 25 },
    "conversational": { "score":  4, "max": 15 }
  },
  "surfaces": {
    "merchant_center": {
      "state": "synced",
      "last_published_at": "2026-08-26T09:22:05Z"
    },
    "jsonld_anchor":   { "state": "published" },
    "shopify_catalog": { "state": "synced" }
  },
  "attributes_held_for_review": 37
}
POST/v1/catalog/{shop}/publishasync

Pushes every approved, gate-passing value out to the rails you name. Writing back to Shopify goes through bulkOperationRunMutation — one staged JSONL upload and one bulk job, instead of thousands of per-variant mutations against the rate limit.

Shopify runs one bulk operation per shop at a time, so we check currentBulkOperation before submitting and return 409 rather than queue behind a job we did not start. Values still held for merchant review are never included; they come back as values_held.

Body
FieldTypeDescription
railsarrayAny of merchant_center, jsonld_anchor, shopify_catalog. Omit to publish all three.
publish.json
Request body
{
  "rails": ["merchant_center", "shopify_catalog"]
}
202_accepted.json
Response · 202 Accepted
{
  "job_id": "job_5b81d240",
  "status": "queued",
  "rails": ["merchant_center", "shopify_catalog"],
  "values_queued": 1183,
  "values_held": 37
}
// STATUS CODES & LIMITS

Failure modes

StatusCodeWhen
202acceptedIngest queued. The body carries the job_id to poll.
400invalid_requestMalformed body, an unknown rail name, or a callback_url that is not HTTPS.
401invalid_tokenMissing, expired or malformed bearer token.
403app_not_installedThe shop has not installed UCP Fluent, or your token is not scoped to it.
404catalog_not_foundNo completed ingest exists for this shop yet.
409job_in_progressA job of the same kind is already running for this shop. On publish this is Shopify’s own limit — one bulk operation per shop — which we check via currentBulkOperation before submitting, and refuse rather than queue behind.
429rate_limitedRetry after the interval in the Retry-After header.
503upstream_unavailableShopify or Merchant Center rejected or throttled the call. Safe to retry with the same Idempotency-Key.
  • One job per shop, per kind. Shopify permits a single bulk operation per shop at a time, so a second publish returns 409 with the running job's id instead of queuing. Ingest is serialised the same way, by us rather than by Shopify.
  • Idempotency. A repeated Idempotency-Key on POST returns the original job rather than starting a second one.
  • Versioning. Breaking changes ship under a new path prefix. While the beta is open, /v1 shapes can still change and partners are told before they do.
  • Attribution scope. A hard receipt arms only when the visit carries our utm_source=ucp_fluent parameters — the tagging we add to links in the merchant's Merchant Center feed. A click from an assistant that does not carry them produces no receipt. We report that gap rather than estimate across it, and never bill on traffic we cannot evidence.
  • Merchant consent. Every call is bounded by the merchant's own Shopify install and the scopes they granted. There is no path to a catalog whose owner has not installed the app.
error.json
Error body · 409 Conflict
{
  "error": {
    "code": "job_in_progress",
    "message": "A bulk operation is already running.",
    "job_id": "job_9f3c1a4e"
  }
}
// BUILT ON GOOGLE CLOUD · US-CENTRAL1

Production infrastructure

Three planes, all in us-central1. This is the stack serving merchants today — the Platform API is a new entry point onto it, not a separate system.

CONTROL PLANE
CLOUD RUN

App & orchestration

  • Cloud Run
  • Cloud SQL · Postgres
  • Memorystore · Redis

Serves the embedded Shopify admin app, holds job state and merchant sessions in Postgres, and drives webhook-triggered re-sync. Redis carries the job queue and the enrichment cache.

ENRICHMENT PLANE
VERTEX AI

Extract, classify, gate

  • Cloud Run
  • Vertex AI · Gemini
  • GPC brick classification

Reads the product page and images, extracts attributes, classifies each product to a GPC brick, and scores every value. Values below the confidence gate are held for merchant review rather than published.

DATA & PUBLISHING
BIGQUERY

One record, three rails

  • BigQuery lakehouse
  • Merchant Center API
  • Theme app embed · metafields

The enriched record lands in BigQuery, then publishes out: Merchant Center through its API, JSON-LD onto the product page through the theme app embed, and catalog metafields onto Shopify’s agent surface.

// Founding Pilot

Apply for the founding pilot.

Founding pilot: free for selected merchants — full-catalog enrichment, direct Merchant Center integration, hands-on AI-commerce consulting. In exchange we publish the measured results. Applications reviewed personally, limited seats.

01

Enrichment

Full-catalog enrichment during the pilot — free for selected merchants.

02

Integration

Direct Merchant Center integration plus hands-on AI-commerce consulting from the founding team.

03

The trade

We publish the measured results as the case study.

30 minutes, your catalog, all three rails — plus the receipts you’d see in your own orders. Book a demo →

Manual review process. Zero automated spam.