EPCIS 2.0 Repository

📘

Enterprise feature

If you are interested in using this enterprise feature, please contact us.

📘

SDK : epcis2.js

epcis2.js, is our open-source SDK for building EPCIS clients. It eases the interactions with EPCIS repositories & APIs such as the one provided by the EVRYTHNG Product Cloud.

EPCIS is a GS1 standard for capturing and querying supply chain events. EPCIS is especially valuable to facilitate the seamless exchange of information in supply chains that span multiple organisations. The EPCIS 2.0 standard was ratified in July 2002 by the GS1 working group EVRYTHNG helped drive.

This tutorial will teach you how to use the EPCIS 2.0 APIs to capture supply chain events and leverage them in your EVRYTHNG Product Cloud account for traceability, consumer engagement or brand integrity applications.

By adding support for EPCIS, your Product Cloud account becomes the platform for a frictionless integration of your business processes in complex supply chain information systems as well as consumer facing apps. A related topic is the Digital Link, which turns the humble QR code on product packages and labels into the bridge between business-facing IT systems and consumer-facing consumer apps.


EPCIS Events and EPCIS Repository

EPCIS systems communicate by sending events. EPCIS supports five event types, namely ObjectEvent, AggregationEvent, AssociationEvent, TransformationEvent and TransactionEvent. But you can also specify your own type, if necessary. EPCIS events are snapshots of supply chain transactions, describing the following:

  • What: One or more items (pallet, individual products, etc...) that are concerned
  • When: At what time did this event occur
  • Where: The place where items are being shipped, received and where items are being expected
  • Why: The business context that describes the process-related information
  • How: This dimension was added in 2.0 and is used to capture IoT data (sensor information) from and about events.

An EPCIS repository is an append-only database, because events are snapshots of the state of a supply chain. This is important to ensure transparency, accountability and traceability. If for example a supplier ships 10 pallets to a manufacturer and that shipment only contains 5 pallets on arrival, the manufacturer will not ask the supplier to change the event. Instead, the manufacturer will create a new EPCIS event that captures the discrepancy.

Unlike previous versions which were XML based, by default EPCIS 2.0 encodes EPCIS events as JSON (JSON-LD) objects. A JSON-Schema is available to formalise the EPCIS data definition.

{
  // Event Type
  "type": "ObjectEvent",

  // When
  "eventTime": "2005-04-03T20:33:31.116-06:00",
  "eventTimeZoneOffset": "-06:00",

  // What
  "epcList": [
    "urn:epc:id:sgtin:0614141.107346.2017",
    "urn:epc:id:sgtin:0614141.107346.2018"
  ],

  // Where
  "readPoint": "urn:epc:id:sgln:0614141.07346.1234",

  // Why
  "action": "OBSERVE",
  "bizStep": "shipping",
  "disposition": "in_transit",
  "bizTransactionList": [
    {
      "type": "po",
      "bizTransaction": "http://transaction.acme.com/po/12345678"
    }
  ]
}

Using EPCIS 2.0 with the Product Cloud

The Product Cloud features an EPCIS 2.0 which is responsible for storing raw EPCIS events as well as way to map these events to Product Cloud data via the Reactor (e.g., mapping events to Actions).
This means you can keep using the Product Cloud to build consumer-facing applications and at the same time seamlessly leverage the EPCIS 2.0 standard.

23002300

Capturing EPCIS Events

To create your first ObjectEvent, take for instance one of the official examples from The GS1 Github and try:

curl --location --request POST 'https://api.evrythng.io/v2/epcis/capture' \
--header 'Authorization: API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
   "@context":[
      "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",
      {
         "example":"http://ns.example.com/epcis/"
      }
   ],
   "id":"https://id.example.org/document1",
   "type":"EPCISDocument",
   "schemaVersion":"2.0",
   "creationDate":"2005-07-11T11:30:47.0Z",
   "epcisBody":{
      "eventList":[
         {
            "eventID":"ni:///sha-256;df7bb3c352fef055578554f09f5e2aa41782150ced7bd0b8af24dd3ccb30ba69?ver=CBV2.0",
            "type":"ObjectEvent",
            "action":"OBSERVE",
            "bizStep":"shipping",
            "disposition":"in_transit",
            "epcList":[
               "urn:epc:id:sgtin:0614141.107346.2017",
               "urn:epc:id:sgtin:0614141.107346.2018"
            ],
            "eventTime":"2005-04-03T20:33:31.116000-06:00",
            "eventTimeZoneOffset":"-06:00",
            "readPoint":{
               "id":"urn:epc:id:sgln:0614141.07346.1234"
            },
            "bizTransactionList":[
               {
                  "type":"po",
                  "bizTransaction":"http://transaction.acme.com/po/12345678"
               }
            ]
         },
         {
            "eventID":"ni:///sha-256;00e1e6eba3a7cc6125be4793a631f0af50f8322e0ab5f2c0bab994a11cec1d79?ver=CBV2.0",
            "type":"ObjectEvent",
            "action":"OBSERVE",
            "bizStep":"receiving",
            "disposition":"in_progress",
            "epcList":[
               "urn:epc:id:sgtin:0614141.107346.2018"
            ],
            "eventTime":"2005-04-04T20:33:31.116-06:00",
            "eventTimeZoneOffset":"-06:00",
            "readPoint":{
               "id":"urn:epc:id:sgln:0012345.11111.400"
            },
            "bizLocation":{
               "id":"urn:epc:id:sgln:0012345.11111.0"
            },
            "bizTransactionList":[
               {
                  "type":"po",
                  "bizTransaction":"http://transaction.acme.com/po/12345678"
               },
               {
                  "type":"desadv",
                  "bizTransaction":"urn:epcglobal:cbv:bt:0614141073467:1152"
               }
            ],
            "example:myField":"Example of a vendor/user extension"
         }
      ]
   }
}'
setup({
  apiUrl: 'https://api.evrythng.io/v2/epcis/',
  EPCISDocumentSchemaVersion: '2.0',
  headers: {
    'content-type': 'application/json',
    authorization: 'API_KEY',
  },
});


const sendACaptureRequestExample = async () => {

  const epcisDocument = new EPCISDocument();
  const objectEvent1 = new ObjectEvent();
  const objectEvent2 = new ObjectEvent();
  
  objectEvent1
    .setEventID('ni:///sha-256;df7bb3c352fef055578554f09f5e2aa41782150ced7bd0b8af24dd3ccb30ba69?ver=CBV2.0')
    .setAction(cbv.actionTypes.observe)
    .addEPC('urn:epc:id:sgtin:0614141.107346.2017')
    .addEPC('urn:epc:id:sgtin:0614141.107346.2018')
    .setEventTime('2005-04-03T20:33:31.116000-06:00')
    .setEventTimeZoneOffset('-06:00')
    .setBizStep(cbv.bizSteps.shipping)
    .setDisposition(cbv.dispositions.in_transit)
    .setReadPoint( new ReadPoint().setId('urn:epc:id:sgln:0614141.07346.1234') ) 
    .addBizTransactionList([
      new BizTransactionElement ({
        "type": "po",
        "bizTransaction": "http://transaction.acme.com/po/12345678"
      }),
    ]);

  objectEvent2
  .setEventID('ni:///sha-256;00e1e6eba3a7cc6125be4793a631f0af50f8322e0ab5f2c0bab994a11cec1d79?ver=CBV2.0')
  .setAction(cbv.actionTypes.observe)
  .addEPC('urn:epc:id:sgtin:0614141.107346.2018')
  .setEventTime('2005-04-04T20:33:31.116-06:00')
  .setEventTimeZoneOffset('-06:00')
  .setBizStep(cbv.bizSteps.shipping)
  .setDisposition(cbv.dispositions.in_transit)
  .setReadPoint( new ReadPoint().setId('urn:epc:id:sgln:0012345.11111.400') )
  .setBizLocation({
    "id":"urn:epc:id:sgln:0012345.11111.0"
  })
  .addBizTransactionList([
    new BizTransactionElement ({
      "type": "po",
      "bizTransaction": "http://transaction.acme.com/po/12345678"
    }),
    new BizTransactionElement ({
      "type": "desadv",
      "bizTransaction": "urn:epcglobal:cbv:bt:0614141073467:1152"
    })
  ])
  .addExtension('example:myField','Example of a vendor/user extension');
      
  epcisDocument
    .setContext([
      "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",
      {
         "example":"http://ns.example.com/epcis/"
      }
   ])
    .setId('https://id.example.org/document1')
    .setCreationDate('2005-07-11T11:30:47.0Z')
    .addEvent(objectEvent1)
    .addEvent(objectEvent2);
  
  const res = await capture(epcisDocument);
  const text = await res.text();
  console.log(`Request status: ${res.status}`);
  console.log(`Request response: ${text}`);
};

sendACaptureRequestExample();
HTTP/2 202 ACCEPTED

Capturing EPCIS event containing GS1 Digital links identifiers

Unlike previous versions of the standard, EPCIS 2.0 does not only support EPC identifiers as URNs but also identifiers supported by the GS1 Digital Link standard. Here is an example of a valid EPCIS capture request using GS1 Digital Links and EPC URNs:

curl --location --request POST 'https://api.evrythng.io/v2/epcis/capture' \
--header 'Authorization: API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
   "@context":[
      "https://ref.gs1.org/standards/epcis/2.0/epcis-context.jsonld",
      {
         "example":"http://ns.example.com/epcis/"
      }
   ],
   "id":"https://id.example.org/document1",
   "type":"EPCISDocument",
   "schemaVersion":"2.0",
   "creationDate":"2005-07-11T11:30:47.0Z",
   "epcisBody":{
      "eventList":[
         {
            "type":"ObjectEvent",
            "action":"OBSERVE",
            "bizStep":"shipping",
            "disposition":"in_transit",
            "epcList":[
               "https://dlnkd.tn.gg/01/9780345418913/21/123458",
               "urn:epc:id:sgtin:4000001.065432.99886655"
            ],
            "eventTime":"2005-04-03T20:33:31.116000-06:00",
            "eventTimeZoneOffset":"-06:00",
            "readPoint":{
               "id":"https://dlnkd.tn.gg/414/9780345418913"
            },
            "bizTransactionList":[
               {
                  "type":"po",
                  "bizTransaction":"http://transaction.acme.com/po/12345678"
               }
            ]
         },
      ]
   }
}'
setup({
  apiUrl: 'https://api.evrythng.io/v2/epcis/',
  EPCISDocumentContext: 'https://ref.gs1.org/standards/epcis/2.0/epcis-context.jsonld',
  EPCISDocumentSchemaVersion: '2.0',
  headers: {
    'content-type': 'application/json',
    authorization: 'MY_API_KEY',
  },
});


const sendACaptureRequestExample = async () => {

  const epcisDocument = new EPCISDocument();
  const objectEvent = new ObjectEvent();
  
  objectEvent
    .addEPC('https://dlnkd.tn.gg/01/9780345418913/21/123458')
    .addEPC('urn:epc:id:sgtin:4000001.065432.99886655')
    .setEventTime('2005-04-03T20:33:31.116000-06:00')
    .setEventTimeZoneOffset('-06:00')
    .setBizStep(cbv.bizSteps.shipping)
    .setDisposition(cbv.dispositions.in_transit)
    .setReadPoint( new ReadPoint().setId('https://dlnkd.tn.gg/414/9780345418913') ) 
    .addBizTransactionList([
      new BizTransactionElement ({
        "type": "po",
        "bizTransaction": "http://transaction.acme.com/po/12345678"
      }),
    ]);
      
  epcisDocument
    .setContext([
      "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",
      {
         "example":"http://ns.example.com/epcis/"
      }
   ])
    .setId('https://id.example.org/document1')
    .setCreationDate('2005-07-11T11:30:47.0Z')
    .addEvent(objectEvent);

  const res = await capture(epcisDocument);
  const text = await res.text();
  console.log(`Request status: ${res.status}`);
  console.log(`Request response: ${text}`);
};

sendACaptureRequestExample();
HTTP/2 202 ACCEPTED

Capturing EPCIS event containing IoT sensor data

One of the innovations EPCIS 2.0 brings is the support for IoT sensor data. This is well aligned with the growing numbers of product tags that also have sensing capabilities.
Here is a capture example that leverages this feature to record temperature data as part of an inspection step:

curl --location --request POST 'https://api.evrythng.io/v2/epcis/capture' \
--header 'Authorization: API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
   "@context":[
      "https://ref.gs1.org/standards/epcis/2.0/epcis-context.jsonld",
      {
         "example":"http://ns.example.com/epcis/"
      }
   ],
   "id":"https://id.example.org/document1",
   "type":"EPCISDocument",
   "schemaVersion":"2.0",
   "creationDate":"2005-07-11T11:30:47.0Z",
   "epcisBody":{
      "eventList":[
         {
            "type":"ObjectEvent",
            "action":"OBSERVE",
            "bizStep":"inspecting",
            "epcList":[
               "urn:epc:id:sgtin:4012345.011111.9876"
            ],
            "eventTime":"2019-04-02T15:00:00.000+01:00",
            "eventTimeZoneOffset":"+01:00",
            "readPoint":{
               "id":"urn:epc:id:sgln:4012345.00005.0"
            },
            "sensorElementList":[
               {
                  "sensorMetadata":{
                     "startTime":"2019-04-01T15:00:00.000+01:00",
                     "endTime":"2019-04-02T14:59:59.999+01:00"
                  },
                  "sensorReport":[
                     {
                        "type":"Temperature",
                        "minValue":12.4,
                        "maxValue":13.8,
                        "uom":"CEL"
                     }
                  ]
               }
            ]
         }
      ]
   }
}'
setup({
  apiUrl: 'https://api.evrythng.io/v2/epcis/',
  EPCISDocumentContext: 'https://ref.gs1.org/standards/epcis/2.0/epcis-context.jsonld',
  EPCISDocumentSchemaVersion: '2.0',
  headers: {
    'content-type': 'application/json',
    authorization: 'MY_API_KEY',
  },
});


const sendACaptureRequestExample = async () => {

  const epcisDocument = new EPCISDocument();
  const objectEvent = new ObjectEvent();
  
  objectEvent
    .setAction(cbv.actionTypes.observe)
    .addEPC('urn:epc:id:sgtin:4012345.011111.9876')
    .setEventTime('2019-04-02T15:00:00.000+01:00')
    .setEventTimeZoneOffset('+01:00')
    .setBizStep(cbv.bizSteps.inspecting)
    .setReadPoint( new ReadPoint().setId('urn:epc:id:sgln:4012345.00005.0') ) 
    .addSensorElement(
      new SensorElement()
      .setSensorMetadata(
        new SensorMetadata()
          .setStartTime("2019-04-01T15:00:00.000+01:00")
          .setEndTime("2019-04-02T14:59:59.999+01:00")
        )
      .addSensorReport(
        new SensorReportElement()
          .setType(cbv.sensorMeasurementTypes.temperature)
          .setMinValue(12.4)
          .setMaxValue(13.8)
          .setUom('CEL')
      )
    );
      
  epcisDocument
    .setContext([
      "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",
      {
         "example":"http://ns.example.com/epcis/"
      }
   ])
    .setId('https://id.example.org/document1')
    .setCreationDate('2005-07-11T11:30:47.0Z')
    .addEvent(objectEvent);

  const res = await capture(epcisDocument);
  const text = await res.text();
  console.log(`Request status: ${res.status}`);
  console.log(`Request response: ${text}`);

  console.log(`EPCISDocument is valid ? ${epcisDocument.isValid()}`);
  console.log(`Event is valid ? ${epcisDocument.eventList[0].isValid()}`);
};

sendACaptureRequestExample();
HTTP/2 202 ACCEPTED

Return events of any type

The following request enables you to get a list of all events sent to the repository (and linked with your account):

curl --location --request GET 'https://api.evrythng.io/v2/epcis/eventTypes/all/events' \
--header 'Authorization: API_KEY'
HTTP/2 200 OK
Content-Type: application/json

{
   "type":"EPCISDocument",
   "@context":"https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",
   "schemaVersion":"2.0",
   "creationDate":"2022-07-01T14:26:21.317Z",
   "epcisBody":{
      "eventList":[
         {
            "eventID":"ni:///sha-256;df7bb3c352fef055578554f09f5e2aa41782150ced7bd0b8af24dd3ccb30ba69?ver=CBV2.0",
            "type":"ObjectEvent",
            "action":"OBSERVE",
            "bizStep":"shipping",
            "disposition":"in_transit",
            "epcList":[
               "urn:epc:id:sgtin:0614141.107346.2017",
               "urn:epc:id:sgtin:0614141.107346.2018"
            ],
            "eventTime":"2005-04-03T20:33:31.116000-06:00",
            "eventTimeZoneOffset":"-06:00",
            "readPoint":{
               "id":"urn:epc:id:sgln:0614141.07346.1234"
            },
            "bizTransactionList":[
               {
                  "type":"po",
                  "bizTransaction":"http://transaction.acme.com/po/12345678"
               }
            ]
         },
         
         // ... other events
      ]
   }
}

Return all object events

The following request enables you to get a list of all ObjectEvents sent to the repository (and linked with your account). You can obviously replace ObjectEvent with any supported event type.

curl --location --request GET 'https://api.evrythng.io/v2/epcis/eventTypes/ObjectEvent/events' \
--header 'Authorization: API_KEY'
HTTP/2 200 OK
Content-Type:application/json

{
   "type":"EPCISDocument",
   "@context":"https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld",
   "schemaVersion":"2.0",
   "creationDate":"2022-07-01T14:26:21.317Z",
   "epcisBody":{
      "eventList":[
         {
            "eventID":"ni:///sha-256;df7bb3c352fef055578554f09f5e2aa41782150ced7bd0b8af24dd3ccb30ba69?ver=CBV2.0",
            "type":"ObjectEvent",
            "action":"OBSERVE",
            "bizStep":"shipping",
            "disposition":"in_transit",
            "epcList":[
               "urn:epc:id:sgtin:0614141.107346.2017",
               "urn:epc:id:sgtin:0614141.107346.2018"
            ],
            "eventTime":"2005-04-03T20:33:31.116000-06:00",
            "eventTimeZoneOffset":"-06:00",
            "readPoint":{
               "id":"urn:epc:id:sgln:0614141.07346.1234"
            },
            "bizTransactionList":[
               {
                  "type":"po",
                  "bizTransaction":"http://transaction.acme.com/po/12345678"
               }
            ]
         },
         
         // ... other events
      ]
   }
}

Retrieve a single event

Now, let’s retrieve the event we previously captured. The unique event ID is ni:///sha-256;df7bb3c352fef055578554f09f5e2aa41782150ced7bd0b8af24dd3ccb30ba69?ver=CBV2.0. In order to use it in a URL, we need to encode it. You can use a tool like https://www.urlencoder.org/ to do so. You should get ni%3A%2F%2F%2Fsha-256%3Bdf7bb3c352fef055578554f09f5e2aa41782150ced7bd0b8af24dd3ccb30ba69%3Fver%3DCBV2.0

curl --location --request GET 'https://api.evrythng.io/v2/epcis/eventTypes/ObjectEvent/events/ni%3A%2F%2F%2Fsha-256%3Bdf7bb3c352fef055578554f09f5e2aa41782150ced7bd0b8af24dd3ccb30ba69%3Fver%3DCBV2.0' \
--header 'Authorization: API_KEY'

To Summarise

In this tutorial, we introduced the EPCIS 2.0 standard for the exchange of messages in a supply chain environment. You’ve learned how EPCIS events can be translated into Product Cloud events back and forth. Allowing your business to create product experiences that can talk to all stakeholders in a supply chain: suppliers, manufacturers, logistics companies - and consumers! And all this using the tools your developers already know.

To go to the next level and learn more about the technical details and capabilities of the Product Cloud EPCIS 2.0 support please have a look at our EPCIS API documentation