Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.frontic.com/llms.txt

Use this file to discover all available pages before exploring further.

The Custom Integration is for source systems that don’t have a first-party Frontic connector — or for cases where you want to push data straight into Frontic from your own code, scripts, or workflow tools. You define the payload shape, push it via the Ingest API, and Frontic stores it on the feed as-is. No normalization happens on the connector side; reshaping into your storage schema is the Data Sync’s job.
Auth
Ingest API token
Update method
Ingest API only
Resources
Content · Products · Categories
The Custom integration follows the standard integration model — see how integrations work for Connection, Channels, and Data Feeds. This page covers what’s specific to it.

Connection settings

There’s nothing to enter on the connection side — the Custom integration’s “connection” is the Ingest API. Authentication uses an Ingest API token.

Channels

Channels for a Custom integration are pure containers for translations and (optionally) source-side channel keys you reference in payloads. There’s no source system to validate against, so you define them yourself — Channel Name, Available Translations, Fallback Translation. See Channels in the overview for the framework-level fields.

Data Feeds

The Custom integration exposes three feed types:
FeedWhat it carries
ContentGeneric records with the structure you define.
ProductsRecords with optional parent/variant linking via the configured parent-source-id field.
CategoriesGeneric records intended for category data.
The standard Settings → Updates → Schema setup wizard applies — see Data Feeds in the overview. For Custom integrations specifically:

Per-feed config

Source ID Field
string
default:"id"
required
The name of the JSON key in your payload that carries the record’s Source ID. Defaults to id.
Parent Source ID Field
string
default:"parentId"
required
(Products feed only) The name of the JSON key in your payload that carries the parent product’s Source ID, used to link variants. Defaults to parentId.

Update methods

  • Ingest API only. Push records to the feed’s HTTPS endpoint using the Ingest API. Webhooks and scheduled polling don’t apply here — your code controls when records arrive.

Record structure

Records arrive as JSON. The connector recognizes three special keys for context-specific values: @channel, @translation, and @currency. You can use any combination on the same record — Frontic resolves them at sync time.
Reserved key prefixes. The @-prefix namespace above (@channel, @translation, @currency) and the $-prefix namespace used by other connectors ($rel, $options, $properties — see the overview) are both reserved for Frontic’s framework. Don’t use them as keys for your own custom data — they’ll be interpreted or overwritten.

Channel-specific data

Use @channel and the key of your integration’s channels to define data that differs per channel.
{
  "id": 1,
  "productNumber": "my-product-1234",
  "name": "My Product",
  "categoryIds": [14, 23, 30],
  "@channel": {
    "b2c": {
      "technicalProductName": "My Product (Revision 241)"
    },
    "b2b": {
      "technicalProductName": "AA-241-1234"
    }
  }
}
The value for name stays the same across channels; technicalProductName is per channel.

Translation-specific data

Use @translation and a locale key for per-locale values:
{
  "id": 1,
  "productNumber": "my-product-1234",
  "categoryIds": [14, 23, 30],
  "@translation":{
    "de-DE":{
      "name": "Produkt 1",
      "description":"Ein Text"
    },
    "en-GB":{
      "name": "Product 1",
      "description":"Some Text"
    }
  }
}

Currency-specific data

Use @currency and an ISO currency code for per-currency values (typically prices):
{
  "id": 1,
  "productNumber": "my-product-1234",
  "categoryIds": [14, 23, 30],
  "@currency": {
    "EUR": {
      "productPrice": {
        "gross": 19.99,
        "net": 16.79,
        "currency": "EUR",
        "precision": 2
      }
    },
    "USD": {
      "productPrice": {
        "gross": 19.99,
        "net": 19.99,
        "currency": "USD",
        "precision": 2
      }
    }
  }
}

Combining annotations

You can combine @channel, @translation, and @currency on the same record. Frontic resolves them in the order channel → currency → translation so per-channel currency overrides apply correctly.

Product variants

Products in a Custom integration support a parent-child structure. The variant relationship uses two field names from your payload: the Source ID field and the Parent Source ID field, both configurable on the feed. There are three product types, distinguished by how the two fields relate:
Set parent Source ID equal to the Source ID — the record is its own parent.
{
  "id": "my-product-123",
  "parentId": "my-product-123"
}
Records can arrive in any order — variants before their parents are fine; Frontic links them once both are present.

Bulk upserts

Push a JSON array to the Ingest API to upsert many records in one call:
[
  {
    "id": "my-first-product"
  },
  {
    "id": "my-second-product"
  }
]
Each array element is treated as a separate record with the same rules as a single-record push.

Troubleshooting

When records you’ve pushed aren’t where you expect them to be, work through these checks in order:

Confirm the records reached the feed

Open the Data Feed and click Recent Records. The last records the connector accepted appear with their Source ID, timestamp, and full payload. If your latest push isn’t there, the records didn’t make it past intake — check the Ingest API response for a 400 or 401, and confirm the Source ID field is present in every payload.

Confirm the payload looks the way you expect

Click into a record. Verify the field names and shapes match what your Data Sync expects — typos in keys, accidentally-stringified numbers, or missing context annotations (@channel, @translation, @currency) are the usual culprits.

Check the Data Sync setup

A feed without a Data Sync connecting it to a storage stays a feed — records never become storage records. Confirm the sync exists and points at the right feed.

Check the locale mapping on the sync

The Data Sync’s Channel → Scope mapping decides which translations land in which project locale. Make sure the integration’s channels are mapped to your scopes, and the channel’s translations are mapped to the project locales — including the fallback translation the channel was configured with. Skipping the fallback is the single most common cause of “translations not syncing” issues with custom integrations.

Look for transformation errors

If records reached the feed but a sync run produced a notification like Storage Record Transformation Error, the Value Composer chain hit a runtime issue on a specific record. Open the Record Debugger in the feed sync panel to walk the chain on the offending record and pinpoint which slot produced the wrong value — see Error handling for the kinds of failures it surfaces.

Good to know

  • You own the schema. No source-side normalization happens — what you push is what arrives on the feed. Reshape into your storage schema in the Value Composer.
  • Records without a Source ID are dropped. Confirm every payload carries the configured Source ID field; missing IDs are rejected silently at the feed level.
  • Change detection applies. Re-pushing an identical record short-circuits past intake — see change detection in the overview.

Ingest API

The HTTP endpoints, payload shape, and auth model.

n8n

Pushing into a Custom integration from an n8n workflow.