Skip to content

Carrying your own IDs through: __meta

When results come back, you need to know where each translated field goes. The Eurotext item id doesn't tell you "this is the description of product X in en_US" — that mapping lives in your system.

__meta is the mechanism. It's a reserved key inside the item body for data that must not be translated. Whatever you put there rides along untouched and comes back inside translation.__meta when you fetch the result. The spec's own example says it out loud:

"__meta": { "id_in_your_system": 132 }

This is also the answer to "is there an external reference id?" — there's no dedicated field, __meta is it. Put your primary key here.

The one rule: flat key-value only

Every value inside __meta must be a simple key-value value — string, number, or boolean. Nested arrays, objects, null, and JSON-encoded structures are rejected. Split routing data into separate flat keys instead.

// rejected — nested array
'__meta' => [ 'attributes' => ['name', 'description'] ]

// rejected — JSON structure hidden in a string
'__meta' => [ 'attributes' => '["name","description"]' ]

// fine — flat key-value pairs
'__meta' => [ 'id_in_your_system' => 132, 'locale' => 'en_US', 'source' => 'akeneo' ]

The client checks this before it sends, so invalid meta throws an InvalidArgumentException with a clear message instead of an opaque 4xx from the API.

What an Akeneo item looks like

Translating a product's name and description into US English — text under your own field names, routing info under __meta:

$client->createItem(
    projectId: $projectId,
    sourceLanguage: LanguageMap::toEurotext('de-DE'),
    targetLanguage: LanguageMap::toEurotext('en-US'),
    textType: 'product',
    body: [
        'name'        => 'Roter Bürostuhl',
        'description' => 'Ergonomischer Stuhl mit verstellbarer Lehne.',
        '__meta'      => [
            'product_uuid' => $product->getUuid(),
            'locale'       => 'en_US',
            'source'       => 'akeneo',
        ],
    ],
);

Reading it back

$item = $client->getItem($projectId, $itemId);
$translation = $item['translation'];
$meta = $translation['__meta'];

$product = $repo->find($meta['product_uuid']);
$locale  = $meta['locale'];

foreach ($translation as $field => $value) {
    if ($field === '__meta') {
        continue;
    }
    // The body field names double as Akeneo attribute codes here. If yours
    // differ, keep that mapping in your own store (see 12-idempotency.md) —
    // not in __meta, which is flat scalars only.
    $product->setValue($field, $locale, $value);
}

What you put in __meta on the way out is exactly what you read on the way back — so make it carry everything you need to write the value home, and nothing you'd mind a translator seeing.

Don't rely on __meta being searchable or filterable server-side — treat it as round-trip payload only. If you need to look items up, keep your own index (your id → returned project id + item id); see 12-idempotency.md.