ReferenceReference by module

Product types API

Every Product types action (14) and data model (8): endpoints, scopes, input, preconditions, events and examples.

Product types and reusable attributes such as colour, size and material.

Module code attributes · 14 actions · 8 data models · 10 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: attributes (everything), attributes:read (read only) or attributes:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
attribute_item_optionsattribute_item_option/api/v1/attribute_item_options
attribute_valuesattribute_value/api/v1/attribute_valuesattributes.save_attribute_valueattributes.delete_attribute_value
attributesattribute/api/v1/attributesattributes.save_attributeattributes.delete_attribute
product_attribute_valuesitem_attribute_value/api/v1/product_attribute_values
product_type_attributesproduct_type_attribute/api/v1/product_type_attributes
product_type_linksitem_product_type/api/v1/product_type_links
product_typesproduct_type/api/v1/product_typesattributes.save_product_typeattributes.delete_product_type
variant_attribute_valuesvariant_attribute_value/api/v1/variant_attribute_values

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
attributes.assign_attributesattributes:manageAdd attributes to a type
attributes.delete_attributeattributes:deleteDelete an attribute
attributes.delete_attribute_valueattributes:manageRemove a choice
attributes.delete_product_typeattributes:deleteDelete a product type
attributes.reorder_attribute_valuesattributes:manageReorder choices
attributes.reorder_type_attributesattributes:manageReorder a type’s attributes
attributes.save_attributeattributes:manageSave an attribute
attributes.save_attribute_valueattributes:manageSave a choice
attributes.save_product_typeattributes:manageSave a product type
attributes.set_item_attributesattributes:writeFill in an item’s attributes
attributes.set_item_typeattributes:writeGive an item its product type
attributes.set_variant_attributesattributes:writeFill in a variant’s attributes
attributes.unassign_attributeattributes:manageRemove an attribute from a type
attributes.update_assignmentattributes:manageSwitch the variant picker

attributes.assign_attributes

Add attributes to a type — At product level, or at variant level — optionally driving the variant picker.

Needs attributes:manage · changes data

POSThttps://app.getera.io/api/v1/attribute_item_options/actions/assign_attributes
API key or OAuth token · attributes:manage
  • Canonical address: POST /api/v1/actions/attributes.assign_attributes

Input

FieldTypeRequiredNotes
productTypeIduuidyesProduct type · id of product_type
attributeIdsobject / arrayyesAttributes
levelstring (enum)yesLevel · Allowed values: product, variant
variantSelectionbooleanDrives the variant picker

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe type and every attribute must exist.
attribute_already_assignedAn attribute sits on a type once, at one level.
variant_only_attributeA variant-only attribute cannot go on the product.
variant_selection_not_allowedOnly variant-level dropdown, yes/no, swatch or number attributes drive the picker.

Events it publishes: attributes.type_attributes_changed, attributes.variant_axes_synced

What it writes: attribute_item_option (upsert) — Maps a picker attribute onto the catalogue axis (item.md §9b); product_type_attribute (insert) — Assigns the attributes

curl -X POST https://app.getera.io/api/v1/attribute_item_options/actions/assign_attributes \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"productTypeId":"PRODUCT_TYPE_ID","attributeIds":{},"level":"product"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.type_attributes_changed",
    "attributes.variant_axes_synced"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributeItemOptions.assignAttributes({
  productTypeId: "PRODUCT_TYPE_ID",
  attributeIds: {},
  level: "product"
})
era attribute_item_options assign_attributes --data '{"productTypeId":"PRODUCT_TYPE_ID","attributeIds":{},"level":"product"}'
tools/call
{
  "name": "era__attributes__assign_attributes",
  "arguments": {
    "productTypeId": "PRODUCT_TYPE_ID",
    "attributeIds": {},
    "level": "product"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, attribute_already_assigned, variant_only_attribute, variant_selection_not_allowed · 429 slow down

attributes.delete_attribute

Delete an attribute — Its choices, its assignments and every product’s value for it go with it.

Needs attributes:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/attributes/{id}/actions/delete_attribute
API key or OAuth token · attributes:delete
  • REST alias: DELETE /api/v1/attributes/{id}
  • Canonical address: POST /api/v1/actions/attributes.delete_attribute

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Attribute · id of attribute

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe attribute must exist.

Events it publishes: attributes.attribute_deleted

What it writes: attribute (delete) — Removes it; the FKs remove what hangs off it

curl -X POST https://app.getera.io/api/v1/attributes/ATTRIBUTE_ID/actions/delete_attribute \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.attribute_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributes.deleteAttribute("ATTRIBUTE_ID")
era attributes delete_attribute ATTRIBUTE_ID
tools/call
{
  "name": "era__attributes__delete_attribute",
  "arguments": {
    "id": "ATTRIBUTE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

attributes.delete_attribute_value

Remove a choice — Products that had it chosen lose that value.

Needs attributes:manage · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/attribute_values/{id}/actions/delete_attribute_value
API key or OAuth token · attributes:manage
  • REST alias: DELETE /api/v1/attribute_values/{id}
  • Canonical address: POST /api/v1/actions/attributes.delete_attribute_value

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Choice · id of attribute_value

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe choice must exist.

Events it publishes: attributes.attribute_values_changed

What it writes: attribute_value (delete) — Removes the choice

curl -X POST https://app.getera.io/api/v1/attribute_values/ATTRIBUTE_VALUE_ID/actions/delete_attribute_value \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.attribute_values_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributeValues.deleteAttributeValue("ATTRIBUTE_VALUE_ID")
era attribute_values delete_attribute_value ATTRIBUTE_VALUE_ID
tools/call
{
  "name": "era__attributes__delete_attribute_value",
  "arguments": {
    "id": "ATTRIBUTE_VALUE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

attributes.delete_product_type

Delete a product type — Only while no item is of the type. Saleor would delete the products too; this refuses.

Needs attributes:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/product_types/{id}/actions/delete_product_type
API key or OAuth token · attributes:delete
  • REST alias: DELETE /api/v1/product_types/{id}
  • Canonical address: POST /api/v1/actions/attributes.delete_product_type

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Product type · id of product_type

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe type must exist.
product_type_in_useNo item may be of the type.

Events it publishes: attributes.product_type_deleted

What it writes: product_type (delete) — Removes the type and its assignments

curl -X POST https://app.getera.io/api/v1/product_types/PRODUCT_TYPE_ID/actions/delete_product_type \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.product_type_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.productTypes.deleteProductType("PRODUCT_TYPE_ID")
era product_types delete_product_type PRODUCT_TYPE_ID
tools/call
{
  "name": "era__attributes__delete_product_type",
  "arguments": {
    "id": "PRODUCT_TYPE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, product_type_in_use · 429 slow down

attributes.reorder_attribute_values

Reorder choices — The order a picker lists them in.

Needs attributes:manage · changes data

POSThttps://app.getera.io/api/v1/attribute_values/actions/reorder_attribute_values
API key or OAuth token · attributes:manage
  • Canonical address: POST /api/v1/actions/attributes.reorder_attribute_values

Input

FieldTypeRequiredNotes
attributeIduuidyesAttribute · id of attribute
valueIdsobject / arrayyesChoices

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe attribute must exist.
value_not_of_attributeEvery choice must be this attribute’s.

Events it publishes: attributes.attribute_values_changed

What it writes: attribute_value (update) — Rewrites sort_order

curl -X POST https://app.getera.io/api/v1/attribute_values/actions/reorder_attribute_values \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"attributeId":"ATTRIBUTE_ID","valueIds":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.attribute_values_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributeValues.reorderAttributeValues({
  attributeId: "ATTRIBUTE_ID",
  valueIds: {}
})
era attribute_values reorder_attribute_values --data '{"attributeId":"ATTRIBUTE_ID","valueIds":{}}'
tools/call
{
  "name": "era__attributes__reorder_attribute_values",
  "arguments": {
    "attributeId": "ATTRIBUTE_ID",
    "valueIds": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, value_not_of_attribute · 429 slow down

attributes.reorder_type_attributes

Reorder a type’s attributes — The order the product and variant forms show them in.

Needs attributes:manage · changes data

POSThttps://app.getera.io/api/v1/product_type_attributes/actions/reorder_type_attributes
API key or OAuth token · attributes:manage
  • Canonical address: POST /api/v1/actions/attributes.reorder_type_attributes

Input

FieldTypeRequiredNotes
productTypeIduuidyesProduct type · id of product_type
levelstring (enum)yesLevel · Allowed values: product, variant
attributeIdsobject / arrayyesAttributes

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe type must exist.
attribute_not_on_typeEvery attribute must be on the type at that level.

Events it publishes: attributes.type_attributes_changed

What it writes: product_type_attribute (update) — Rewrites sort_order

curl -X POST https://app.getera.io/api/v1/product_type_attributes/actions/reorder_type_attributes \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"productTypeId":"PRODUCT_TYPE_ID","level":"product","attributeIds":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.type_attributes_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.productTypeAttributes.reorderTypeAttributes({
  productTypeId: "PRODUCT_TYPE_ID",
  level: "product",
  attributeIds: {}
})
era product_type_attributes reorder_type_attributes --data '{"productTypeId":"PRODUCT_TYPE_ID","level":"product","attributeIds":{}}'
tools/call
{
  "name": "era__attributes__reorder_type_attributes",
  "arguments": {
    "productTypeId": "PRODUCT_TYPE_ID",
    "level": "product",
    "attributeIds": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, attribute_not_on_type · 429 slow down

attributes.save_attribute

Save an attribute — A reusable property — colour, size, material — and how it is entered and shown.

Needs attributes:manage · changes data

POSThttps://app.getera.io/api/v1/attributes/{id}/actions/save_attribute
API key or OAuth token · attributes:manage
  • REST alias: PATCH /api/v1/attributes/{id}
  • Canonical address: POST /api/v1/actions/attributes.save_attribute

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Attribute · id of attribute
namestringyesName · max 255
slugstringCode · max 250
inputTypestring (enum)Type · Allowed values: dropdown, multiselect, file, reference, single-reference, numeric, rich-text, plain-text, swatch, boolean, date, date-time
entityTypestringPoints at · max 40
unitstringUnit · max 40
valueRequiredbooleanRequired
isVariantOnlybooleanVariants only
visibleInStorefrontbooleanShown on the storefront
filterableInStorefrontbooleanFilter on the storefront
filterableInDashboardbooleanFilter in lists
storefrontSearchPositionnumberSearch position
availableInGridbooleanColumn in lists
valuesobject / arrayChoices

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_nameThe name must produce a usable code.
not_foundAn edited attribute must exist.
input_type_lockedThe type is chosen once.
slug_takenThe code must be free in this workspace.
entity_type_requiredA reference must say what it points at.
entity_type_not_allowedOnly a reference points at something, and only at a product, variant or category.
unit_not_allowedOnly a number has a unit, and only a known one.
property_not_allowedFiltering, grid and search position only on types that support them.
attribute_has_no_choicesOnly dropdown, multi select and swatch have choices.
value_name_takenA choice may be given once.

Events it publishes: attributes.attribute_saved

What it writes: attribute (upsert) — Creates or edits the attribute; attribute_value (insert) — Writes the first choices on create

curl -X POST https://app.getera.io/api/v1/attributes/ATTRIBUTE_ID/actions/save_attribute \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.attribute_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributes.saveAttribute("ATTRIBUTE_ID", {
  name: "Name"
})
era attributes save_attribute ATTRIBUTE_ID \
  --name "Name"
tools/call
{
  "name": "era__attributes__save_attribute",
  "arguments": {
    "id": "ATTRIBUTE_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_name, not_found, input_type_locked, slug_taken, entity_type_required, entity_type_not_allowed, unit_not_allowed, property_not_allowed, attribute_has_no_choices, value_name_taken · 429 slow down

attributes.save_attribute_value

Save a choice — One option of a dropdown, multi select or swatch.

Needs attributes:manage · changes data

POSThttps://app.getera.io/api/v1/attribute_values/{id}/actions/save_attribute_value
API key or OAuth token · attributes:manage
  • REST alias: PATCH /api/v1/attribute_values/{id}
  • Canonical address: POST /api/v1/actions/attributes.save_attribute_value

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Choice · id of attribute_value
attributeIduuidyesAttribute · id of attribute
namestringyesName · max 250
valuestringColour · #RRGGBB or #RRGGBBAA — swatches only. · max 9
fileIduuidPicture · id of file

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe attribute and an edited choice must exist.
attribute_has_no_choicesThe attribute must be a dropdown, multi select or swatch.
invalid_nameA choice needs a name.
swatch_only_fieldOnly a swatch choice carries a colour or picture.
invalid_swatchA swatch is one valid colour or one picture.
value_name_takenChoice names are unique within the attribute, ignoring case.

Events it publishes: attributes.attribute_values_changed, attributes.variant_axes_synced

What it writes: attribute_item_option (upsert) — Maps a picker attribute onto the catalogue axis (item.md §9b); attribute_value (upsert) — Creates or edits the choice

curl -X POST https://app.getera.io/api/v1/attribute_values/ATTRIBUTE_VALUE_ID/actions/save_attribute_value \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"attributeId":"ATTRIBUTE_ID","name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.attribute_values_changed",
    "attributes.variant_axes_synced"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributeValues.saveAttributeValue("ATTRIBUTE_VALUE_ID", {
  attributeId: "ATTRIBUTE_ID",
  name: "Name"
})
era attribute_values save_attribute_value ATTRIBUTE_VALUE_ID \
  --attribute-id "ATTRIBUTE_ID" \
  --name "Name"
tools/call
{
  "name": "era__attributes__save_attribute_value",
  "arguments": {
    "id": "ATTRIBUTE_VALUE_ID",
    "attributeId": "ATTRIBUTE_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, attribute_has_no_choices, invalid_name, swatch_only_field, invalid_swatch, value_name_taken · 429 slow down

attributes.save_product_type

Save a product type — A kind of product, and the attribute set its products carry.

Needs attributes:manage · changes data

POSThttps://app.getera.io/api/v1/product_types/{id}/actions/save_product_type
API key or OAuth token · attributes:manage
  • REST alias: PATCH /api/v1/product_types/{id}
  • Canonical address: POST /api/v1/actions/attributes.save_product_type

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Product type · id of product_type
namestringyesName · max 250
slugstringAddress · max 255
kindstring (enum)Kind · Allowed values: normal, gift_card
isShippingRequiredbooleanShips
weightGramsnumberWeight (grams) · min 0
taxClassIduuidTax class

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_nameThe name must produce a usable address.
slug_takenThe address must be free in this workspace.
not_foundAn edited type must exist.
product_type_in_useThe kind cannot change while items are of the type.

Events it publishes: attributes.product_type_saved

What it writes: product_type (upsert) — Creates or edits the type

curl -X POST https://app.getera.io/api/v1/product_types/PRODUCT_TYPE_ID/actions/save_product_type \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.product_type_saved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.productTypes.saveProductType("PRODUCT_TYPE_ID", {
  name: "Name"
})
era product_types save_product_type PRODUCT_TYPE_ID \
  --name "Name"
tools/call
{
  "name": "era__attributes__save_product_type",
  "arguments": {
    "id": "PRODUCT_TYPE_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_name, slug_taken, not_found, product_type_in_use · 429 slow down

attributes.set_item_attributes

Fill in an item’s attributes — The product-level values — material, brand line, care instructions.

Needs attributes:write · changes data

POSThttps://app.getera.io/api/v1/product_attribute_values/actions/set_item_attributes
API key or OAuth token · attributes:write
  • Canonical address: POST /api/v1/actions/attributes.set_item_attributes

Input

FieldTypeRequiredNotes
itemIduuidyesItem · id of item
valuesobject / arrayyesValues

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
item_not_foundThe item must exist.
item_has_no_typeThe item must have a product type.
attribute_not_on_typeEvery attribute must be on the type at this level.
attribute_value_invalidA value must match its attribute’s type and choices.
attribute_value_requiredRequired attributes must end up with a value.

Events it publishes: attributes.item_attributes_changed

What it writes: item_attribute_value (upsert) — Replaces the values of each attribute sent

curl -X POST https://app.getera.io/api/v1/product_attribute_values/actions/set_item_attributes \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemId":"ITEM_ID","values":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.item_attributes_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.productAttributeValues.setItemAttributes({
  itemId: "ITEM_ID",
  values: {}
})
era product_attribute_values set_item_attributes --data '{"itemId":"ITEM_ID","values":{}}'
tools/call
{
  "name": "era__attributes__set_item_attributes",
  "arguments": {
    "itemId": "ITEM_ID",
    "values": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 item_not_found, item_has_no_type, attribute_not_on_type, attribute_value_invalid, attribute_value_required · 429 slow down

attributes.set_item_type

Give an item its product type — Chosen once, as in Saleor — it decides which attributes the item carries.

Needs attributes:write · changes data

POSThttps://app.getera.io/api/v1/attribute_item_options/actions/set_item_type
API key or OAuth token · attributes:write
  • Canonical address: POST /api/v1/actions/attributes.set_item_type

Input

FieldTypeRequiredNotes
itemIduuidyesItem · id of item
productTypeIduuidyesProduct type · id of product_type

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
item_not_foundThe item must exist.
not_foundThe type must exist.
item_type_lockedAn item’s type is chosen once.
type_does_not_fit_itemShipping and gift-card kind must agree with the item.

Events it publishes: attributes.item_type_set, attributes.variant_axes_synced

What it writes: attribute_item_option (upsert) — Maps a picker attribute onto the catalogue axis (item.md §9b); item_product_type (insert) — Records the item’s type

curl -X POST https://app.getera.io/api/v1/attribute_item_options/actions/set_item_type \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemId":"ITEM_ID","productTypeId":"PRODUCT_TYPE_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.item_type_set",
    "attributes.variant_axes_synced"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributeItemOptions.setItemType({
  itemId: "ITEM_ID",
  productTypeId: "PRODUCT_TYPE_ID"
})
era attribute_item_options set_item_type \
  --item-id "ITEM_ID" \
  --product-type-id "PRODUCT_TYPE_ID"
tools/call
{
  "name": "era__attributes__set_item_type",
  "arguments": {
    "itemId": "ITEM_ID",
    "productTypeId": "PRODUCT_TYPE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 item_not_found, not_found, item_type_locked, type_does_not_fit_item · 429 slow down

attributes.set_variant_attributes

Fill in a variant’s attributes — The variant-level values — size, colour — including the ones that drive the picker.

Needs attributes:write · changes data

POSThttps://app.getera.io/api/v1/attribute_item_options/actions/set_variant_attributes
API key or OAuth token · attributes:write
  • Canonical address: POST /api/v1/actions/attributes.set_variant_attributes

Input

FieldTypeRequiredNotes
itemVariantIduuidyesVariant · id of item_variant
valuesobject / arrayyesValues

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
variant_not_foundThe variant must exist.
item_has_no_typeThe item must have a product type.
attribute_not_on_typeEvery attribute must be on the type at this level.
attribute_value_invalidA value must match its attribute’s type and choices.
attribute_value_requiredRequired attributes must end up with a value.

Events it publishes: attributes.variant_attributes_changed, attributes.variant_axes_synced

What it writes: attribute_item_option (upsert) — Maps a picker attribute onto the catalogue axis (item.md §9b); variant_attribute_value (upsert) — Replaces the values of each attribute sent

curl -X POST https://app.getera.io/api/v1/attribute_item_options/actions/set_variant_attributes \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"itemVariantId":"ITEM_VARIANT_ID","values":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.variant_attributes_changed",
    "attributes.variant_axes_synced"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributeItemOptions.setVariantAttributes({
  itemVariantId: "ITEM_VARIANT_ID",
  values: {}
})
era attribute_item_options set_variant_attributes --data '{"itemVariantId":"ITEM_VARIANT_ID","values":{}}'
tools/call
{
  "name": "era__attributes__set_variant_attributes",
  "arguments": {
    "itemVariantId": "ITEM_VARIANT_ID",
    "values": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 variant_not_found, item_has_no_type, attribute_not_on_type, attribute_value_invalid, attribute_value_required · 429 slow down

attributes.unassign_attribute

Remove an attribute from a type — The values that type’s products carried for it go too.

Needs attributes:manage · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/product_type_attributes/actions/unassign_attribute
API key or OAuth token · attributes:manage
  • Canonical address: POST /api/v1/actions/attributes.unassign_attribute

Input

FieldTypeRequiredNotes
productTypeIduuidyesProduct type · id of product_type
attributeIduuidyesAttribute · id of attribute

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe type and the attribute must exist.
attribute_not_on_typeThe attribute must be on the type.

Events it publishes: attributes.type_attributes_changed

What it writes: product_type_attribute (delete) — Removes the assignment; item_attribute_value (delete) — Removes products’ values for it; variant_attribute_value (delete) — Removes variants’ values for it

curl -X POST https://app.getera.io/api/v1/product_type_attributes/actions/unassign_attribute \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"productTypeId":"PRODUCT_TYPE_ID","attributeId":"ATTRIBUTE_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.type_attributes_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.productTypeAttributes.unassignAttribute({
  productTypeId: "PRODUCT_TYPE_ID",
  attributeId: "ATTRIBUTE_ID"
})
era product_type_attributes unassign_attribute \
  --product-type-id "PRODUCT_TYPE_ID" \
  --attribute-id "ATTRIBUTE_ID"
tools/call
{
  "name": "era__attributes__unassign_attribute",
  "arguments": {
    "productTypeId": "PRODUCT_TYPE_ID",
    "attributeId": "ATTRIBUTE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, attribute_not_on_type · 429 slow down

attributes.update_assignment

Switch the variant picker — Whether a variant attribute appears as the storefront’s “Size: S M L” buttons.

Needs attributes:manage · changes data

POSThttps://app.getera.io/api/v1/attribute_item_options/actions/update_assignment
API key or OAuth token · attributes:manage
  • Canonical address: POST /api/v1/actions/attributes.update_assignment

Input

FieldTypeRequiredNotes
productTypeIduuidyesProduct type · id of product_type
attributeIduuidyesAttribute · id of attribute
variantSelectionbooleanyesDrives the variant picker

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe type and the attribute must exist.
attribute_not_on_typeIt must be a variant attribute of the type.
variant_selection_not_allowedOnly dropdown, yes/no, swatch or number drive the picker.

Events it publishes: attributes.type_attributes_changed, attributes.variant_axes_synced

What it writes: attribute_item_option (upsert) — Maps a picker attribute onto the catalogue axis (item.md §9b); product_type_attribute (update) — Sets variant_selection

curl -X POST https://app.getera.io/api/v1/attribute_item_options/actions/update_assignment \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"productTypeId":"PRODUCT_TYPE_ID","attributeId":"ATTRIBUTE_ID","variantSelection":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "attributes.type_attributes_changed",
    "attributes.variant_axes_synced"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.attributeItemOptions.updateAssignment({
  productTypeId: "PRODUCT_TYPE_ID",
  attributeId: "ATTRIBUTE_ID",
  variantSelection: true
})
era attribute_item_options update_assignment \
  --product-type-id "PRODUCT_TYPE_ID" \
  --attribute-id "ATTRIBUTE_ID" \
  --variant-selection true
tools/call
{
  "name": "era__attributes__update_assignment",
  "arguments": {
    "productTypeId": "PRODUCT_TYPE_ID",
    "attributeId": "ATTRIBUTE_ID",
    "variantSelection": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold attributes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, attribute_not_on_type, variant_selection_not_allowed · 429 slow down

Data models

AttributeItemOption

Table attribute_item_option · Resource attribute_item_options

  • GET /api/v1/attribute_item_options
  • GET /api/v1/attribute_item_options/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_idstring (uuid) · uuiditem
attribute_idstring (uuid) · uuidattribute
item_option_idstring (uuid) · uuiditem_option
created_atstring (date-time) · timestamptz

Primary key: id

Unique: item_id, attribute_id · item_option_id

AttributeValue

Table attribute_value · Resource attribute_values

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
attribute_idstring (uuid) · uuidattribute
namestring · text
slugstring · text
valuestring · text
file_idstring (uuid) · uuidyesfile
sort_orderinteger · int4
external_referencestring · textyes
created_atstring (date-time) · timestamptz

Primary key: id

Unique: attribute_id, slug

Checks:

  • CHECK (((value = ''::text) OR (file_id IS NULL)))

Attribute

Table attribute · Resource attributes

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
slugstring · text
input_typestring · textdropdown, multiselect, file, reference, single-reference, numeric, rich-text, plain-text, swatch, boolean, date, date-time
entity_typestring · textyesProduct, ProductVariant, Category
unitstring · textyesmm, cm, dm, m, km, ft, yd, inch, sq_mm, sq_cm, sq_dm, sq_m, sq_km, sq_ft, sq_yd, sq_inch, cubic_millimeter, cubic_centimeter, cubic_decimeter, cubic_meter, liter, cubic_foot, cubic_inch, cubic_yard, qt, pint, fl_oz, acre_in, acre_ft, g, lb, oz, kg, tonne
value_requiredboolean · bool
is_variant_onlyboolean · bool
visible_in_storefrontboolean · bool
filterable_in_storefrontboolean · bool
filterable_in_dashboardboolean · bool
storefront_search_positioninteger · int4
available_in_gridboolean · bool
external_referencestring · textyes
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK (((input_type = ANY (ARRAY['reference'::text, 'single-reference'::text])) = (entity_type IS NOT NULL)))
  • CHECK (((unit IS NULL) OR (input_type = 'numeric'::text)))

ItemAttributeValue

Table item_attribute_value · Resource product_attribute_values

  • GET /api/v1/product_attribute_values
  • GET /api/v1/product_attribute_values/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_idstring (uuid) · uuiditem
attribute_idstring (uuid) · uuidattribute
value_idstring (uuid) · uuidyesattribute_value
text_valuestring · textyes
numeric_valuenumber · float8yes
boolean_valueboolean · boolyes
date_valuestring (date-time) · timestamptzyes
file_idstring (uuid) · uuidyesfile
reference_item_idstring (uuid) · uuidyesitem
reference_variant_idstring (uuid) · uuidyesitem_variant
reference_category_idstring (uuid) · uuidyesitem_category
sort_orderinteger · int4
created_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((num_nonnulls(value_id, text_value, numeric_value, boolean_value, date_value, file_id, reference_item_id, reference_variant_id, reference_category_id) = 1))

ProductTypeAttribute

Table product_type_attribute · Resource product_type_attributes

  • GET /api/v1/product_type_attributes
  • GET /api/v1/product_type_attributes/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
product_type_idstring (uuid) · uuidproduct_type
attribute_idstring (uuid) · uuidattribute
levelstring · textproduct, variant
variant_selectionboolean · bool
sort_orderinteger · int4

Primary key: id

Unique: product_type_id, attribute_id

Checks:

  • CHECK (((level = 'variant'::text) OR (NOT variant_selection)))

ItemProductType

Table item_product_type · Resource product_type_links

  • GET /api/v1/product_type_links
  • GET /api/v1/product_type_links/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_idstring (uuid) · uuiditem
product_type_idstring (uuid) · uuidproduct_type
created_atstring (date-time) · timestamptz

Primary key: id

Unique: item_id

ProductType

Table product_type · Resource product_types

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
slugstring · text
kindstring · textnormal, gift_card
is_shipping_requiredboolean · bool
weight_gramsstring (int64) · int8
tax_class_idstring (uuid) · uuidyes
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((weight_grams >= 0))

VariantAttributeValue

Table variant_attribute_value · Resource variant_attribute_values

  • GET /api/v1/variant_attribute_values
  • GET /api/v1/variant_attribute_values/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
item_variant_idstring (uuid) · uuiditem_variant
attribute_idstring (uuid) · uuidattribute
value_idstring (uuid) · uuidyesattribute_value
text_valuestring · textyes
numeric_valuenumber · float8yes
boolean_valueboolean · boolyes
date_valuestring (date-time) · timestamptzyes
file_idstring (uuid) · uuidyesfile
reference_item_idstring (uuid) · uuidyesitem
reference_variant_idstring (uuid) · uuidyesitem_variant
reference_category_idstring (uuid) · uuidyesitem_category
sort_orderinteger · int4
created_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((num_nonnulls(value_id, text_value, numeric_value, boolean_value, date_value, file_id, reference_item_id, reference_variant_id, reference_category_id) = 1))

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
attributes.attribute_deletedAn attribute was removed.id
attributes.attribute_savedAn attribute was created or edited.id, slug, inputType
attributes.attribute_values_changedAn attribute’s choices changed.attributeId
attributes.item_attributes_changedAn item’s attribute values changed.itemId, count
attributes.item_type_setAn item was given its product type.itemId, productTypeId
attributes.product_type_deletedA product type was removed.id
attributes.product_type_savedA product type was created or edited.id, slug
attributes.type_attributes_changedA type’s attribute set changed.productTypeId, count
attributes.variant_attributes_changedA variant’s attribute values changed.itemVariantId, itemId, count
attributes.variant_axes_syncedPicker attributes were mapped onto catalogue variant axes.count, itemId
Was this page helpful?