ShipEasy Docs

Publishing API

REST API reference for publishing label profiles to the CDN and managing drafts.

Publish a profile

Generates a content-addressed label file, uploads it to R2, and purges the Cloudflare CDN cache. After publishing, changes propagate globally in ~60 seconds.

POST /v1/profiles/:name/publish
Authorization: Bearer i18n_at_...
{
  "profile": "en:prod",
  "url": "https://cdn.i18n.shipeasy.ai/v1/labels/i18n_pk_abc123/en:prod/index.json",
  "hash": "sha256-abc123...",
  "keyCount": 142,
  "publishedAt": "2026-04-11T10:00:00Z"
}

Publish specific chunks

POST /v1/profiles/:name/publish
Authorization: Bearer i18n_at_...
Content-Type: application/json

{
  "chunks": ["index", "checkout"]
}

Omit chunks to publish all chunks.

Publish multiple profiles

POST /v1/publish/batch
Authorization: Bearer i18n_at_...
Content-Type: application/json

{
  "profiles": ["en:prod", "fr:prod", "de:prod"]
}

Profiles are published in parallel. Returns an array of publish results.

{
  "results": [
    { "profile": "en:prod", "status": "ok", "keyCount": 142 },
    { "profile": "fr:prod", "status": "ok", "keyCount": 118 },
    { "profile": "de:prod", "status": "error", "error": "profile_not_found" }
  ]
}

Drafts

Drafts let you stage changes to a profile before they go live. The in-browser editor creates drafts automatically. i18n translate also creates drafts.

List drafts

GET /v1/profiles/:name/drafts
Authorization: Bearer i18n_at_...
{
  "data": [
    {
      "id": "draft_abc123",
      "name": "Q1 marketing copy",
      "profile": "fr:prod",
      "keyCount": 24,
      "status": "pending",
      "createdAt": "2026-04-10T09:00:00Z",
      "createdBy": "user_xyz"
    }
  ]
}

Create a draft

POST /v1/profiles/:name/drafts
Authorization: Bearer i18n_at_...
Content-Type: application/json

{
  "name": "Spring promo copy",
  "keys": {
    "nav.home": "Accueil",
    "nav.signIn": "Se connecter",
    "checkout.submit": "Passer la commande"
  }
}
{
  "id": "draft_def456",
  "name": "Spring promo copy",
  "profile": "fr:prod",
  "keyCount": 3,
  "status": "pending",
  "previewUrl": "https://app.i18n.shipeasy.ai/dashboard/profiles/fr:prod?draft=draft_def456",
  "createdAt": "2026-04-11T10:00:00Z"
}

Get draft diff

Returns the keys changed by this draft relative to the live profile:

GET /v1/drafts/:id/diff
Authorization: Bearer i18n_at_...
{
  "id": "draft_def456",
  "profile": "fr:prod",
  "changes": [
    {
      "key": "nav.home",
      "before": "Maison",
      "after": "Accueil"
    },
    {
      "key": "nav.signIn",
      "before": null,
      "after": "Se connecter"
    }
  ]
}

before: null means the key had no value before (new translation).

Publish a draft

Merges draft values into the live profile and publishes:

POST /v1/drafts/:id/publish
Authorization: Bearer i18n_at_...
{
  "id": "draft_def456",
  "status": "published",
  "publishedAt": "2026-04-11T10:05:00Z",
  "keysUpdated": 3
}

Discard a draft

DELETE /v1/drafts/:id
Authorization: Bearer i18n_at_...
{ "deleted": true }

CDN label files

Published label files are served from the CDN at:

https://cdn.i18n.shipeasy.ai/v1/labels/{i18n_pk_key}/{profile}/{chunk}.json

These files are public and unauthenticated — they contain only your translated string values, not account metadata or credentials.

File format

{
  "v": 1,
  "profile": "en:prod",
  "chunk": "index",
  "hash": "sha256-abc123...",
  "publishedAt": "2026-04-11T10:00:00Z",
  "keys": {
    "nav.home": "Home",
    "nav.signIn": "Sign in",
    "footer.privacy": "Privacy Policy"
  }
}

Cache behavior

CDN files use Cache-Control: public, max-age=3600, stale-while-revalidate=86400. After a publish, the cache is purged via Cloudflare Cache API — changes propagate in ~60 seconds.

The loader script (cdn.i18n.shipeasy.ai/v1/loader.js) handles CDN fetching automatically. You only need to call the CDN directly if you're building a custom integration.