A product is the item you protect, such as a bottle of Lonafen, together with what a customer sees after a scan. Each product owns a set of tags, one per physical item. This API lists the products of your team, reads one, and changes the title, description, and images it shows.
Every request needs an API key. A key is limited to the products of its own team.
You still create a product, mint more tags, assign a category, and change where a scan lands on the dashboard. Documents stay there too. This API returns the product’s category so you can see which group it belongs to.
Use cases
- Keep an ERP catalogue in sync. Your product names and descriptions live in an ERP. Push a change to the product with one update, and every tag that shows the product’s title shows the new one on its next scan.
- Refresh images. Product photos move to a new CDN, or a pack design
changes. Write the new
image_urlsfrom the system that hosts them, and the verification page shows the new ones.
Fields
A product is a JSON:API resource of type products.
| Field | Type | Notes |
|---|---|---|
id |
string | prd_-prefixed. The same id the dashboard’s product URLs carry. |
title |
string | The product’s title, max 50 characters. |
description |
string or null |
The product’s description. |
image_urls |
array of strings | The images the verification page shows, as URLs, in order. |
verification_type |
string | internal when TAGBASE hosts the verification page, external when a scan redirects to your own domain. Read only. |
tag_count |
integer | How many tags the product has. Read only. |
website |
string or null |
The product’s own page, as a URL, when the product has one. Read only. |
category |
object or null |
The category the product belongs to, { "id", "name" }, or null when it belongs to none. Read only. A product belongs to one category at most. |
type |
null |
Unused. Always null. |
The relationships object is empty. Documents and links stay on the
dashboard.
A tag inherits from its product
A tag with no title or description of its own shows the product’s, so an edit here shows on every such tag at once. The Tags endpoints read and write the values of one tag.
List products
GET /api/productsLists the products of the team, ordered by title. Paging follows the shared pagination rules.
Query parameters
| Parameter | Type | Notes |
|---|---|---|
page |
integer | The page, counting from 1. Defaults to 1. |
page_size |
integer | Products per page. Defaults to 10, maximum 100. |
curl "https://verify.tagbase.io/api/products?page=1&page_size=100" \
-H "Authorization: Bearer $TAGBASE_API_KEY" \
-H "Accept: application/vnd.api+json"const res = await fetch(
"https://verify.tagbase.io/api/products?page=1&page_size=100",
{
headers: {
"Authorization": `Bearer ${process.env.TAGBASE_API_KEY}`,
"Accept": "application/vnd.api+json",
},
},
);
const { data, meta } = await res.json();$response = $client->get("https://verify.tagbase.io/api/products", [
"headers" => [
"Authorization" => "Bearer " . getenv("TAGBASE_API_KEY"),
"Accept" => "application/vnd.api+json",
],
"query" => ["page" => 1, "page_size" => 100],
]);
$page = json_decode((string) $response->getBody(), true);page =
Req.get!("https://verify.tagbase.io/api/products",
params: [page: 1, page_size: 100],
headers: [
{"authorization", "Bearer #{System.fetch_env!("TAGBASE_API_KEY")}"},
{"accept", "application/vnd.api+json"}
]
).bodyResponse: 200 OK
A data array of products, each in the shape of
Retrieve a product, plus a meta object that
describes the page:
{
"data": [
{
"type": "products",
"id": "prd_4fm3xUcsDEUK77WDBMed6U",
"attributes": {
"title": "Lonafen",
"description": "Sublingual fentanyl spray by Zanna Therapeutics.",
"image_urls": ["https://cdn.zanna.example/lonafen/front.jpg"],
"verification_type": "internal",
"tag_count": 2000,
"website": "https://zanna.example/lonafen",
"category": { "id": "tpl_7kQ2mN4pR8sT1uV6wX9yZa", "name": "Pharmaceuticals" },
"type": null
},
"relationships": {}
}
],
"meta": { "total_count": 1, "page": 1, "page_size": 100 }
}Errors
| Status | When |
|---|---|
401 |
Missing, invalid, or revoked key. |
Retrieve a product
GET /api/products/:idcurl https://verify.tagbase.io/api/products/prd_4fm3xUcsDEUK77WDBMed6U \
-H "Authorization: Bearer $TAGBASE_API_KEY" \
-H "Accept: application/vnd.api+json"const res = await fetch(
"https://verify.tagbase.io/api/products/prd_4fm3xUcsDEUK77WDBMed6U",
{
headers: {
"Authorization": `Bearer ${process.env.TAGBASE_API_KEY}`,
"Accept": "application/vnd.api+json",
},
},
);
const product = await res.json();$response = $client->get("https://verify.tagbase.io/api/products/prd_4fm3xUcsDEUK77WDBMed6U", [
"headers" => [
"Authorization" => "Bearer " . getenv("TAGBASE_API_KEY"),
"Accept" => "application/vnd.api+json",
],
]);
$product = json_decode((string) $response->getBody(), true);product =
Req.get!("https://verify.tagbase.io/api/products/prd_4fm3xUcsDEUK77WDBMed6U",
headers: [
{"authorization", "Bearer #{System.fetch_env!("TAGBASE_API_KEY")}"},
{"accept", "application/vnd.api+json"}
]
).bodyResponse: 200 OK
{
"data": {
"type": "products",
"id": "prd_4fm3xUcsDEUK77WDBMed6U",
"attributes": {
"title": "Lonafen",
"description": "Sublingual fentanyl spray by Zanna Therapeutics.",
"image_urls": ["https://cdn.zanna.example/lonafen/front.jpg"],
"verification_type": "internal",
"tag_count": 2000,
"website": "https://zanna.example/lonafen",
"category": { "id": "tpl_7kQ2mN4pR8sT1uV6wX9yZa", "name": "Pharmaceuticals" },
"type": null
},
"relationships": {}
}
}Errors
| Status | When |
|---|---|
401 |
Missing, invalid, or revoked key. |
404 |
No such product in your team. A product of another team and a malformed id get the same answer. |
Update a product
PATCH /api/products/:idWrites title, description, or image_urls. Send any of them, in any
combination. An attribute you send replaces the stored value as a whole, and
an attribute you leave out stays as it is. So send the full image_urls array
you want the product to show, with the URLs that did not change. The API
ignores any other attribute in the body.
Request
One resource under data, with the product’s id:
{
"data": {
"type": "products",
"id": "prd_4fm3xUcsDEUK77WDBMed6U",
"attributes": {
"title": "Lonafen 400 µg",
"image_urls": [
"https://cdn.zanna.example/lonafen/front.jpg",
"https://cdn.zanna.example/lonafen/back.jpg"
]
}
}
}curl https://verify.tagbase.io/api/products/prd_4fm3xUcsDEUK77WDBMed6U \
-X PATCH \
-H "Authorization: Bearer $TAGBASE_API_KEY" \
-H "Content-Type: application/vnd.api+json" \
-d '{ "data": { "type": "products", "id": "prd_4fm3xUcsDEUK77WDBMed6U", "attributes": { "title": "Lonafen 400 µg", "image_urls": [ "https://cdn.zanna.example/lonafen/front.jpg", "https://cdn.zanna.example/lonafen/back.jpg" ] } } }'const res = await fetch(
"https://verify.tagbase.io/api/products/prd_4fm3xUcsDEUK77WDBMed6U",
{
method: "PATCH",
headers: {
"Authorization": `Bearer ${process.env.TAGBASE_API_KEY}`,
"Content-Type": "application/vnd.api+json",
},
body: JSON.stringify({
data: {
type: "products",
id: "prd_4fm3xUcsDEUK77WDBMed6U",
attributes: {
title: "Lonafen 400 µg",
image_urls: [
"https://cdn.zanna.example/lonafen/front.jpg",
"https://cdn.zanna.example/lonafen/back.jpg",
],
},
},
}),
},
);
const product = await res.json();$response = $client->patch("https://verify.tagbase.io/api/products/prd_4fm3xUcsDEUK77WDBMed6U", [
"headers" => [
"Authorization" => "Bearer " . getenv("TAGBASE_API_KEY"),
"Content-Type" => "application/vnd.api+json",
],
"json" => [
"data" => [
"type" => "products",
"id" => "prd_4fm3xUcsDEUK77WDBMed6U",
"attributes" => [
"title" => "Lonafen 400 µg",
"image_urls" => [
"https://cdn.zanna.example/lonafen/front.jpg",
"https://cdn.zanna.example/lonafen/back.jpg",
],
],
],
],
]);
$product = json_decode((string) $response->getBody(), true);product =
Req.patch!("https://verify.tagbase.io/api/products/prd_4fm3xUcsDEUK77WDBMed6U",
headers: [
{"authorization", "Bearer #{System.fetch_env!("TAGBASE_API_KEY")}"},
{"content-type", "application/vnd.api+json"}
],
json: %{
data: %{
type: "products",
id: "prd_4fm3xUcsDEUK77WDBMed6U",
attributes: %{
title: "Lonafen 400 µg",
image_urls: [
"https://cdn.zanna.example/lonafen/front.jpg",
"https://cdn.zanna.example/lonafen/back.jpg"
]
}
}
}
).bodyResponse: 200 OK
The updated product, in the shape of Retrieve a product.
Errors
| Status | When |
|---|---|
400 |
The body has no data.attributes object. |
401 |
Missing, invalid, or revoked key. |
404 |
No such product in your team. |
422 |
A value failed validation. source.pointer names it, and detail says why. Nothing changed. |
A 422 for a title over 50 characters looks like this:
{
"errors": [
{
"status": "422",
"title": "Unprocessable Entity",
"detail": "should be at most 50 character(s)",
"source": { "pointer": "/data/attributes/title" }
}
]
}For an entry in image_urls that is not an http:// or https:// URL, the
pointer is /data/attributes/image_urls.
Next: read the scans of your products with the Verifications endpoints.