W3C
Editor's
Draft
Group
Note
29
Copyright © 2020-2025 World Wide Web Consortium . W3C ® liability , trademark and permissive document license rules apply.
This specification defines a Profiling Mechanism and a set of Profiles which enable out-of-the-box interoperability between Web Things and their Consumers on the Web of Things .
Being out-of-the-box interoperable means that any Consumer which conforms with a given Profile can interact with any Thing which conforms with the same profile, without additional customization.
A Profile is a technical specification which provides a set of assertions to which conformant Consumers and Things must conform.
The
Profiling
Mechanism
provides
a
means
to
denote
that
a
given
Thing
conforms
to
one
or
more
Profiles,
by
referring
to
the
identifiers
of
those
Profiles
in
the
profile
member
of
its
Thing
Description
.
The specification defines three profiles:
The Profiles defined in this specification share a set of Common Constraints to which implementations of those Profiles must also conform. This includes constraints on units, date formats, security mechanisms, discovery mechanisms, link relations and errors.
Future versions of this specification, or extension specifications, may define additional Profiles.
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C standards and drafts index .
This
document
was
published
by
initially
on
the
Web
of
Things
Working
Group
W3C
Recommendation
Track
and
published
as
an
Editor's
Draft.
Publication
as
an
Editor's
a
Working
Draft
does
on
18
January
2023.
The
WoT
Working
Group
later
decided
not
imply
endorsement
by
to
continue
to
pursue
the
document
to
W3C
Recommendation
status
and
its
Members.
This
is
instead
to
publish
it
as
a
Group
Note
,
as
a
useful
point
of
reference
for
use
with
the
WoT
1.x
family
of
specifications.
A
Group
Note
provides
a
stable
reference
for
a
draft
document
and
may
be
updated,
replaced,
or
obsoleted
by
other
documents
at
any
time.
It
that
is
inappropriate
not
intended
to
cite
be
a
formal
standard.
Software
MAY
implement
this
document
as
other
than
specification
at
their
own
risk.
Following
the
publication
of
this
Note,
the
Working
Group
intends
to
switch
their
attention
to
a
work
in
progress.
new
recommendation
track
WoT
Profiles
2.0
specification
for
use
with
the
WoT
2.x
family
of
specifications.
This
document
was
produced
published
by
a
group
operating
under
the
W3C
Patent
Policy
.
W3C
maintains
a
public
list
Web
of
any
patent
disclosures
Things
Working
Group
made
in
connection
with
the
deliverables
of
the
group;
that
page
also
includes
instructions
for
disclosing
a
patent.
An
individual
who
has
actual
knowledge
of
as
a
patent
that
Group
Note
using
the
individual
believes
contains
Essential
Claim(s)
must
disclose
Note
track
.
This
Group
Note
is
endorsed
by
the
information
in
accordance
with
section
6
Web
of
the
Things
Working
Group
,
but
is
not
endorsed
by
W3C
itself
nor
its
Members.
The
W3C
Patent
Policy
.
does
not
carry
any
licensing
requirements
or
commitments
on
this
document.
This document is governed by the 03 November 2023 W3C Process Document .
The Web of Things (WoT) seeks to counter the fragmentation of the Internet of Things (IoT) by using and extending existing, standardized web technologies.
The W3C WoT Thing Description [ wot-thing-description11 ] specification defines an information model and JSON-based representation format for describing the capabilities of connected devices and the interfaces with which to communicate with them. Thing Descriptions are designed to be protocol-agnostic and flexible enough to describe a wide range of existing ("brownfield") IoT devices.
In order to provide this level of flexibility the Thing Description specification includes a number of extension points including protocol bindings, payload bindings, security mechanisms, link relations and semantic contexts. As long as all of the capabilities of a device can be described using a Thing Description and a Consumer implements all of the extensions used, the Consumer should be able to interoperate with that device. However, the result of this extensible architecture is that any given Consumer can only interoperate with a subset of possible Web Things .
This specification is designed to complement the Thing Description [ wot-thing-description11 ] specification, by enabling ad-hoc interoperability through the use of "profiles". A profile prescribes a finite set of extensions and defaults that a Thing can be constrained to in order to guarantee out-of-the-box interoperability with any Consumer which implements that profile.
Profiles are designed specifically for new ("greenfield") implementations where developers have the freedom to conform to a prescriptive protocol binding and set of common constraints, in order to benefit from this additional level of interoperability.
Future versions of this specification, or extension specifications, may define additional Profiles.
The Web of Things Interest Group collected use cases for the Web of Things from stakeholders representing various different industries. This includes both vertical domain-specific use cases and horizontal use cases which apply to multiple application domains [ wot-usecases ].
Several of the domain-specific use cases refer to the need for easy integration of devices from multiple vendors. This is especially important for cross-domain use cases which require "multi-vendor system integration" and "out-of-the-box interoperability".
A set of requirements for Profiles were derived from these use cases.
At a high level, out-of-the-box interoperability means that a Consumer is guaranteed to be able to use every capability of a Thing , without Thing-specific customization.
The full definition of out-of-the-box interoperability used in this specification includes multiple layers. The following classification adopts terminology from the "H2020 – CREATE-IoT Project - Recommendations for commonalities and interoperability profiles of IoT platforms" [ H2020-CREATE-IoT ] report. The definitions below have been adapted to reflect the scope of the WoT profile.
Technical Interoperability is usually associated with communication protocols and the infrastructure needed for those protocols to operate. This implies agreeing on a common protocol (e.g. HTTP / TCP/IP) and providing additional clarifications, where required.
Syntactic Interoperability is usually associated with data formats and encodings along with techniques for compressing them. Examples for these formats and encodings in the WoT are JSON, XML, JSON-LD, UTF-8 payloads.
Semantic Interoperability is associated with a common understanding of the behavior of communication partners. In the profile context, it includes a common interpretation of (synchronous and asynchronous) action semantics, a common event model, how to set/get multiple properties, writable properties, a common error model and error messages.
Domain specific ontologies, e.g. semantic interop of automotive and medical devices exceed the scope of the this specification.
Organisational Interoperability in the profile context implies that any Consumer which conforms with a given profile can interact with any Thing which conforms with the same profile, without additional customization.
Organisational Interoperability also requires commonly agreed approaches to security, trust and privacy, i.e. a consumer is provided access to Things only when these common terms and conditions are applied.
Devices created by various engineers, vendors and SDOs that satisfy the requirements of the profile specification can be integrated with compliant consumers without additional customization. This works across infrastructures, regions and cultures.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY , MUST , MUST NOT , OPTIONAL , RECOMMENDED , SHOULD , and SHOULD NOT in this document are to be interpreted as described in BCP 14 [ RFC2119 ] [ RFC8174 ] when, and only when, they appear in all capitals, as shown here.
A device or consumer implementation complies with this specification if it follows the normative statements in the present document.
The fundamental WoT terminology such as Thing , Web Thing , Consumer , Thing Description ( TD ), WoT Thing Description , Partial TD , Thing Model ( TM ), Interaction Model , Interaction Affordance , Property , Action , Event , Protocol Binding , Servient , Vocabulary , Term , Vocabulary Term , WoT Interface , and WoT Runtime are defined in Section 3 of the WoT Architecture specification [ WOT-ARCHITECTURE ].
For convenience of the reader, we use the terms keyword and field for the linguistic notion vocabulary term as defined in the Thing Description Specification.
We use the terms device and thing in an interchangeable manner.
In order to conform with a profile, a Web Thing MUST conform with all the normative statements in the profile's specification.
In
order
to
denote
that
a
given
Web
Thing
conforms
to
one
or
more
profiles,
its
Thing
Description
MUST
include
a
profile
member
[
wot-thing-description11
].
The
value
of
the
profile
member
MUST
be
set
to
either
a
valid
URI
[
RFC3986
]
identifying
a
single
profile,
or
an
array
of
valid
URIs
identifying
multiple
profiles.
In
order
to
use
a
profile
member
in
a
Thing
Description,
the
@context
member
MUST
contain
the
anyURI
https://www.w3.org/2022/wot/td/v1.1
in
order
to
denote
that
the
document
is
using
version
1.1
of
the
Thing
Description
specification.
[
wot-thing-description11
].
All
Things
and
Consumers
conforming
to
a
profile
MUST
satisfy
the
assertions
specified
in
the
[
wot-thing-description11
],
except
for
the
assertion
td-context-ns-td10-namespacev10
with
text
TD
1.1
consumers
MUST
accept
TDs
satisfying
the
W3C
WoT
Thing
Description
1.0
[wot-thing-description]
specification.
{
"@context": "https://www.w3.org/2022/wot/td/v1.1",
"id": "urn:dev:ops:32473-WoTLamp-1234",
"profile": "https://www.w3.org/2022/wot/profile/http-basic/v1",
"title": "My Lamp",
"description": "A web connected lamp",
...
}
{
"@context": "https://www.w3.org/2022/wot/td/v1.1",
"id": "urn:dev:ops:32473-WoTLamp-1234",
"profile": [
"https://www.w3.org/2022/wot/profile/http-basic/v1",
"https://www.w3.org/2022/wot/profile/http-sse/v1"
],
"title": "My Lamp",
"description": "A web connected lamp",
...
}
Conforming to a Profile does not prevent a Web Thing from describing additional capabilities and protocol bindings in their Thing Description beyond those described in the Profile, as long as they conform with all of the normative assertions of the Profile.
The following sections are applicable for profiles defined by this document.
Authors of Thing Descriptions should be aware that units that are common in their geographic region are not globally applicable and may lead to misinterpretation with drastic consequences.
It
is
highly
RECOMMENDED
to
provide
a
unit
,
if
a
value
has
a
physical
quantity.
It is highly RECOMMENDED to use the metric system (SI units) for devices that are used in global deployments.
Unless
otherwise
specified,
all
date
and
time
values
MUST
use
the
date-time
format
defined
in
[
RFC3339
].
2022-09-21T23:20:50.52Z
In order to reduce ambiguity, RFC 3339 only permits an hour with a value between 00 and 23 (not 24), and time zones expressed as a numerical offset relative to UTC. The suffix "Z" when applied to a time denotes a UTC offset of 00:00.
Below is a list of security schemes [ wot-thing-description11 ] which conformant Web Things MAY use:
Conformant Consumers MUST support at least all of these security schemes.
A Thing MAY implement multiple security schemes.
A Thing MUST support at least one of the above security schemes.
For
the
BasicSecurityScheme
the
"in"
field
MUST
be
either
omitted
or
be
given
its
default
value
of
"header"
as
defined
in
[[wot-thing-description11].
For
the
BasicSecurityScheme
the
"name"
field
MUST
be
provided
using
the
value
"Authorization"
if
a
"proxy"
endpoint
is
not
given.
For
the
BasicSecurityScheme
the
"name"
field
MUST
be
provided
using
the
value
"Proxy-Authorization"
if
a"proxy"
endpoint
is
given.
Conformant Consumers MUST support security bootstrapping for all implemented security schemes, as defined in Security Bootstrapping in the WoT Discovery [ wot-discovery ] specification.
Conformant Things which require authentication in order to retrieve their Thing Description MUST implement security bootstrapping, as defined in Security Bootstrapping in the WoT Discovery [ wot-discovery ] specification.
A Web Thing's Thing Description [ wot-thing-description11 ] MUST be retrievable from a Thing Description Server [ wot-architecture11 ] using an HTTP [ HTTP11 ] URL provided by a Direct Introduction Mechanism [ wot-discovery ].
links
member
that
provide
hyperlinks
to
other
web
resources.
This
section
defines
specific
combinations
of
rel
and
type
members
of
a
Link
which
conformant
Consumers
are
expected
to
interpret
in
a
particular
way.
rel | type | Meaning |
---|---|---|
icon
|
image/*
|
An icon representing the Thing |
alternate
|
text/html
|
A user interface to interact with the Thing |
service-doc
|
text/plain
or
text/html
or
text/pdf
|
A user manual for the Thing |
item
|
application/td+json
|
The target Thing is a component of this Thing or a member of a collection of Things that this Thing represents |
collection
|
application/td+json
|
This Thing is a component of the target Thing or a group of Things that the target Thing represents |
If a Consumer encounters a link with "rel": "icon" and "type": "image/*" and it is capable of rendering images in the provided format, then it SHOULD interpret the link as an icon for the Thing and display it to the user.
If a Consumer encounters a link with "rel": "alternate" and "type": "text/html" and it is capable of rendering an HTML page and accepting user input, then it SHOULD interpret the link as a user interface for the Thing and provide a means for the user to follow that link and view and interact with the HTML page.
If a Consumer encounters a link with "rel": "service-doc" and "type": "text/plain", "type": "text/html" or "type": "text/pdf", and is capable of rendering documents in the provided format, then it SHOULD interpret the link as a user manual for the Thing and provide a means for the user to follow that link and read the user manual.
If a Consumer encounters a link with "rel": "item" and "type": "application/td+json" and is capable of rendering a hierarchical tree of Things, then it should interpret the link as an indication that the target is a sub-Thing of the current Thing and render this in a meaningful way to the user.
If a Consumer encounters a link with "rel": "collection" and "type": "application/td+json" and is capable of rendering a hierarchical tree of Things, then it should interpret the link as an indication that the target describes a Thing (e.g. a group, system of Things or Thing Directory) which contains the current Thing and render this in a meaningful way to the user.
If any of the operations defined in the protocol bindings of HTTP profiles are unsuccessful then the Web Thing MUST send an HTTP response with an HTTP error code which describes the reason for the failure.
It is RECOMMENDED that error responses use one of the following HTTP error codes:
400
Bad
Request
401
Unauthorized
403
Forbidden
404
Not
Found
500
Internal
Server
Error
503
Service
Unavailable
A
Web
Thing
MAY
respond
with
3xx
status
codes
for
the
purposes
of
redirection,
caching
or
authentication.
A
Web
Thing
MUST
NOT
respond
with
a
300
Multiple
Choices
status
code.
Web
Things
MAY
respond
with
other
valid
HTTP
error
codes
(e.g.
418
I'm
a
teapot
).
Consumers
MAY
interpret
other
valid
HTTP
error
codes
as
a
generic
4xx
or
5xx
error
with
no
special
defined
behaviour.
If an HTTP error response contains a body, the content of that body MUST conform with the Problem Details format [ RFC7807 ].
This section defines the HTTP Basic Profile, which includes a Protocol Binding for reading and writing properties and invoking, querying and cancelling actions.
This profile may be used in conjunction with the HTTP SSE Profile or the HTTP Webhook Profile in order to provide operations for observing properties and listening for events.
In order to conform with the HTTP Basic Profile, Web Things and Consumers MUST also conform with all of the assertions in the Common Constraints section.
In
order
to
denote
that
a
given
Web
Thing
conforms
to
the
HTTP
Basic
Profile,
its
Thing
Description
MUST
have
a
profile
member
[
wot-thing-description11
]
with
a
value
of
https://www.w3.org/2022/wot/profile/http-basic/v1
.
This section defines a protocol binding which describes how a Consumer communicates with a Web Thing [ wot-architecture11 ] using JSON [ JSON ] payloads over the HTTP [ HTTP11 ] protocol.
A Consumer or Web Thing conforming to the HTTP Basic Profile MUST implement this protocol binding.
The examples provided throughout this section describe how a Consumer would communicate with a Web Thing which produces the following Thing Description:
{
"@context": "https://www.w3.org/2022/wot/td/v1.1",
"id": "https://mywebthingserver.com/things/lamp",
"profile": "https://www.w3.org/2022/wot/profile/http-basic/v1",
"base": "https://mywebthingserver.com/things/lamp/",
"title": "My Lamp",
"description": "A web connected lamp",
"securityDefinitions": {
"oauth2": {
"scheme": "oauth2",
"flow": "code",
"authorization": "https://mywebthingserver.com/oauth/authorize",
"token": "https://mywebthingserver.com/oauth/token"
}
},
"security": "oauth2",
"properties": {
"on": {
"type": "boolean",
"title": "On/Off",
"description": "Whether the lamp is turned on",
"forms": [{"href": "properties/on"}]
},
"level" : {
"type": "integer",
"title": "Brightness",
"description": "The level of light from 0-100",
"unit": "percent",
"minimum" : 0,
"maximum" : 100,
"forms": [{"href": "properties/level"}]
}
},
"actions": {
"fade": {
"title": "Fade",
"description": "Fade the lamp to a given level",
"synchronous": false,
"input": {
"type": "object",
"properties": {
"level": {
"title": "Brightness",
"type": "integer",
"minimum": 0,
"maximum": 100,
"unit": "percent"
},
"duration": {
"title": "Duration",
"type": "integer",
"minimum": 0,
"unit": "milliseconds"
}
}
},
"forms": [{"href": "actions/fade"}]
}
},
"forms": [
{
"op": ["readallproperties", "writemultipleproperties"],
"href": "properties"
},
{
"op": "queryallactions",
"href": "actions"
}
]
}
The
URL
of
a
Property
resource
to
be
used
when
reading
the
value
of
a
property
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
corresponding
PropertyAffordance
for
which:
op
member
contains
the
value
readproperty
href
member
is
http
or
https
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Property
resource.
In order to read the value of a property, a Consumer MUST send an HTTP request to a Web Thing with:
GET
Property
resource
Accept
header
set
to
application/json
GET /things/lamp/properties/on HTTP/1.1
Host: mythingserver.com
Accept
:
application/json
If a Web Thing receives an HTTP request following the format above and the Consumer has permission to read the corresponding property, then upon successfully reading the value of the property it MUST send an HTTP response with:
200
Content-Type
header
set
to
application/json
HTTP/1.1 200 OK
Content-Type: application/json
false
The
URL
of
a
Property
resource
to
be
used
when
writing
the
value
of
a
property
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
corresponding
PropertyAffordance
for
which:
op
member
contains
the
value
writeproperty
href
member
is
http
or
https
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Property
resource.
In order to write the value of a property, a Consumer MUST send an HTTP request to a Web Thing with:
PUT
Property
resource
Content-Type
header
set
to
application/json
PUT /things/lamp/properties/on HTTP/1.1
Host: mythingserver.com
Content-Type: application/json
true
If a Web Thing receives an HTTP request following the format above and the Consumer has permission to write the corresponding property, then upon successfully writing the value of the property it MUST send an HTTP response with:
204
HTTP/1.1
204
No
Content
The
URL
of
a
Properties
resource
to
be
used
when
reading
the
value
of
all
properties
at
once
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
top
level
forms
member
for
which:
op
member
contains
the
value
readallproperties
href
member
is
http
or
https
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Properties
resource.
In order to read the value of all properties, a Consumer MUST send an HTTP request to a Web Thing with:
GET
Properties
resource
Accept
header
set
to
application/json
GET /things/lamp/properties HTTP/1.1
Host: mythingserver.com
Accept
:
application/json
If a Web Thing receives an HTTP request following the format above, then upon successfully reading the values of all the readable properties to which the Consumer has permission to access, it MUST send an HTTP response with:
200
Content-Type
header
set
to
application/json
HTTP/1.1 200 OK
Content-Type: application/json
{
"on": false,
"level": 100
}
The
URL
of
a
Properties
resource
to
be
used
when
writing
the
value
of
multiple
properties
at
once
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
top
level
forms
member
for
which:
op
member
contains
the
value
writemultipleproperties
href
member
is
http
or
https
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Properties
resource.
In order to write the value of multiple properties at once, a Consumer MUST send an HTTP request to a Web Thing with:
PUT
Properties
resource
Content-Type
header
set
to
application/json
PUT /things/lamp/properties HTTP/1.1
Host: mythingserver.com
Content-Type: application/json
{
"on": true,
"level": 50
}
If a Web Thing receives an HTTP request following the format above, then upon successfully writing the values of the requested writable properties it MUST send an HTTP response with:
204
HTTP/1.1
204
No
Content
The
readmultipleproperties
operation
is
excluded
due
to
the
complexities
of
the
request
payload
format
and
because
it
doesn't
add
much
functionality
over
readproperty
and
readallproperties
.
writeallproperties
is
excluded
because
it
is
just
a
special
case
of
writemultipleproperties
.
The
URL
of
an
Action
resource
to
be
used
when
invoking
an
action
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
corresponding
ActionAffordance
for
which:
op
member
is
invokeaction
href
member
is
http
or
https
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Action
resource.
In order to invoke an action on a Web Thing, a Consumer MUST send an HTTP request to the Web Thing with:
POST
Action
resource
Accept
header
set
to
application/json
Content-Type
header
set
to
application/json
POST /things/lamp/actions/fade HTTP/1.1
Host: mythingserver.com
Content-Type: application/json
Accept: application/json
{
"level": 100,
"duration": 5
}
If a Web Thing receives an HTTP request following the format above then it MUST respond with one of three response formats:
The
synchronous
member
of
an
ActionAffordance
MUST
be
set
to
true
or
false
.
If
the
synchronous
member
of
the
ActionAffordance
[
wot-thing-description11
]
is
set
to
true
then
the
Web
Thing
MUST
respond
with
a
Synchronous
Action
Response
.
If
the
synchronous
member
of
the
ActionAffordance
[
wot-thing-description11
]
is
set
to
false
then
the
Web
Thing
MUST
respond
with
an
Asynchronous
Action
Response
.
For
long-running
actions
which
are
not
expected
to
finish
executing
within
the
timeout
period
of
an
HTTP
request
(e.g.
30
to
120
seconds),
it
is
RECOMMENDED
that
a
Web
Thing
respond
with
an
Asynchronous
Action
Response
so
that
a
Consumer
may
continue
to
monitor
the
status
of
an
action
request
with
a
queryaction
operation
on
a
dynamically
created
ActionStatus
resource,
after
the
initial
invokeaction
response.
For short-lived actions which are expected to finish executing within the timeout period of an HTTP request, a Web Thing MAY wait until the action has completed to send a Synchronous Action Response.
If
a
Web
Thing
encounters
an
error
in
attempting
to
execute
an
action
before
responding
to
the
invokeaction
request,
then
it
MUST
send
an
Error
Response.
Conforming
Consumers
MUST
support
all
three
types
of
response
to
the
initial
invokeaction
request.
After
the
initial
request,
support
for
subsequent
operations
on
an
ActionStatus
resource
is
OPTIONAL
.
The
status
of
an
asynchronous
action
invocation
request
is
represented
by
an
ActionStatus
object
which
includes
the
following
members:
Member | Description | Assignment | Type |
---|---|---|---|
status
|
The status of the action request. | mandatory |
string
(one
of
pending
,
running
,
completed
or
failed
)
|
output
|
The
output
data,
if
any,
of
a
completed
action
which
MUST
conform
with
the
output
data
schema
of
the
corresponding
ActionAffordance
.
|
optional | any type |
error
|
An
error
message,
if
any,
associated
with
a
failed
action
which
MUST
use
the
JSON
serialization
of
the
Problem
Details
format
[
RFC7807
]
(only
needed
in
response
to
a
queryaction
operation).
|
optional |
object
|
href
|
The
[
URL
]
of
an
ActionStatus
resource
which
can
be
used
by
queryaction
and
cancelaction
operations,
the
URI
scheme
[
RFC3986
]
of
which
MUST
resolve
to
http
or
https
(only
needed
for
an
Asynchronous
Action
Response
).
|
optional |
string
|
timeRequested
|
A timestamp indicating the time at which the Thing received the request to execute the action. (See Date Format for date format constraints). | optional |
string
|
timeEnded
|
A timestamp indicating the time at which the Thing successfully completed executing the action, or failed to execute the action. (See Date Format for date format constraints). | optional |
string
|
It
is
possible
that
a
Thing's
clock
may
not
be
set
to
the
correct
time.
If
timings
are
important
then
a
Consumer
may
therefore
choose
to
treat
the
timeEnded
member
of
an
ActionStatus
object
as
being
relative
to
the
timeRequested
member,
but
not
necessarily
as
relative
to
its
own
internal
clock,
or
the
clocks
of
other
Things.
If providing a Synchronous Action Response, a Web Thing MUST send an HTTP response with:
200
Content-Type
header
set
to
application/json
HTTP/1.1 200 OK
Content-Type
:
application/json
If
providing
an
Asynchronous
Action
Response,
a
Web
Thing
MUST
send
an
HTTP
response
containing
the
URL
of
an
ActionStatus
resource,
the
URI
scheme
[
RFC3986
]
of
which
MUST
resolve
to
http
or
https
.
The
response
MUST
have:
201
Content-Type
header
set
to
application/json
Location
header
set
to
the
URL
of
the
ActionStatus
resource
ActionStatus
object
serialized
in
JSON,
with
its
href
member
set
to
the
URL
of
the
ActionStatus
resource
HTTP/1.1 201 CREATED
Content-Type: application/json
Location: /things/lamp/actions/fade/123e4567-e89b-12d3-a456-426655
{
"status": "pending",
"href": "/things/lamp/actions/fade/123e4567-e89b-12d3-a456-426655",
"timeRequested": "2021-11-10T11:43:19.135Z"
}
In resource constrained environments, the ActionStatus objects of older completed/failed actions MAY be deleted to make room for newly invoked actions.
A
Web
Thing
SHOULD
return
a
503
error
response
if
the
invocation
cannot
be
accepted
because
the
action
is
unavailable,
e.g.
because
the
Thing
is
overloaded.
A
queryaction
operation
is
used
to
query
the
current
state
of
an
ongoing
action
request.
A
Web
Thing
which
provides
Asynchronous
Action
Response
s
to
an
invokeaction
operation
on
an
Action
MUST
also
support
queryaction
operations
on
that
same
Action
.
A
Web
Thing
which
only
provides
Synchronous
Action
Response
s
to
an
invokeaction
operation
on
an
Action
SHOULD
NOT
support
queryaction
operations
on
that
same
Action
.
The
URL
of
an
ActionStatus
resource
to
be
used
in
a
queryaction
operation
MUST
be
obtained
from
the
Location
header
of
an
Asynchronous
Action
Response
,
or
the
href
member
of
the
ActionStatus
object
in
its
body.
In order to query the status of an action request, a Consumer MUST send an HTTP request to a Web Thing with:
GET
ActionStatus
resource
Accept
header
set
to
application/json
GET /things/lamp/actions/fade/123e4567-e89b-12d3-a456-426655
Host: mythingserver.com
Accept:
application/json
If
a
Web
Thing
receives
an
HTTP
request
following
the
format
above
and
the
Consumer
has
permission
to
query
the
corresponding
ActionStatus
resource,
then
upon
successfully
reading
the
status
of
the
action
request
it
MUST
send
an
HTTP
response
with:
200
Content-Type
header
set
to
application/json
ActionStatus
object
representing
the
current
status
of
the
action
request,
serialized
in
JSON
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "running",
"timeRequested": "2021-11-10T11:43:19.135Z"
}
If
the
queried
action
failed
to
execute,
then
the
status
member
of
the
ActionStatus
object
MUST
be
set
to
"failed"
.
If
the
queried
action
failed
to
execute,
then
the
error
member
MAY
provide
additional
error
information
conforming
to
the
Problem
Details
format
[
RFC7807
].
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "failed",
"error": {
"type": "https://mythingserver.com/docs/errors/invalid-level",
"title": "Invalid value for level provided",
"invalid-params": [
{
"name": "level",
"reason": "Must be a valid number between 0 and 100"
}
]
},
"timeRequested": "2021-11-10T11:43:19.135Z",
"timeEnded": "2021-11-10T11:43:20.513Z"
}
A
cancelaction
operation
is
used
to
cancel
an
ongoing
Action
request.
A
Web
Thing
which
provides
Asynchronous
Action
Response
s
to
an
invokeaction
operation
on
an
Action
MAY
also
support
cancelaction
operations
on
that
same
Action
.
A
Web
Thing
which
only
provides
Synchronous
Action
Response
s
to
an
invokeaction
operation
on
an
Action
SHOULD
NOT
support
cancelaction
operations
on
that
same
Action
.
The
URL
of
an
ActionStatus
resource
to
be
used
in
a
cancelaction
operation
MUST
be
obtained
from
the
Location
header
of
an
Asynchronous
Action
Response
,
or
the
href
member
of
the
ActionStatus
object
in
its
body.
In order to cancel an action request, a Consumer MUST send an HTTP request to a Web Thing with:
DELETE
ActionStatus
resource
DELETE /things/lamp/actions/fade/123e4567-e89b-12d3-a456-426655 HTTP/1.1
Host
:
mythingserver.com
If
a
Web
Thing
receives
an
HTTP
request
following
the
format
above
and
the
Consumer
has
permission
to
cancel
the
corresponding
Action
request,
then
upon
successfully
cancelling
Action
it
MUST
send
an
HTTP
response
with:
204
HTTP/1.1
204
No
Content
The
URL
of
an
Actions
resource
to
be
used
when
querying
the
status
of
all
ongoing
action
requests
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
top
level
forms
member
for
which:
op
member
contains
the
value
queryallactions
href
member
is
http
or
https
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Actions
resource.
In order to query the status of all ongoing action requests, a Consumer MUST send an HTTP request to a Web Thing with:
GET
Actions
resource
Accept
header
set
to
application/json
GET /things/lamp/actions HTTP/1.1
Host: mythingserver.com
Accept
:
application/json
If a Web Thing receives an HTTP request following the format above, then upon successfully retreiving the status of all ongoing action requests to which the Consumer has permission to access, it MUST send an HTTP response with:
200
Content-Type
header
set
to
application/json
Action
name,
with
the
value
of
each
object
member
being
an
array
of
ActionStatus
objects
representing
the
action
requests,
serialized
in
JSON.
Each array in the result object MUST be sorted in reverse chronological order such that the most recent action request appears first.
HTTP/1.1 200 OK
Content-Type: application/json
{
"fade": [
{
"status": "completed",
"href": "/things/lamp/actions/fade/123e4567-e89b-12d3-a456-426655",
"timeRequested": "2021-11-10T11:43:19.135Z",
"timeEnded": "2021-11-10T11:43:20.513Z"
},
{
"status": "failed",
"href": "/things/lamp/actions/fade/123e4567-e89b-12d3-a456-558329",
"timeRequested": "2021-11-10T11:42:15.133Z",
"timeEnded": "2021-11-10T11:42:22.524Z"
},
{
"status": "running",
"href": "/things/lamp/actions/fade/123e4567-e89b-12d3-a457-434656",
"timeRequested": "2021-11-10T11:41:53.351Z"
},
{
"status": "pending",
"href": "/things/lamp/actions/fade/123e4567-e89b-12d3-a457-ea9519",
"timeRequested": "2021-11-10T11:39:53.651Z"
}
]
}
Action
request
is
cancelled
with
a
cancelaction
operation,
its
ActionStatus
object
is
deleted
and
need
not
be
retained.
For
all
other
Action
requests
it
is
assumed
that
a
Web
Thing
will
store
the
ActionStatus
object
so
that
its
status
may
later
be
queried
with
a
queryaction
or
queryallactions
operation.
It
is
not
expected
that
ActionStatus
objects
should
be
retained
indefinitely,
they
may
be
stored
in
volatile
memory
and/or
periodically
pruned.
The
length
of
time
for
which
to
retain
ActionStatus
objects
is
expected
to
be
implementation-specific
and
may
depend
on
application-specific
requirements
or
resource
constraints.
This section defines the HTTP SSE Profile, including a Protocol Binding for observing properties and listening for events using Server-Sent Events [ EVENTSOURCE ].
This profile may be used in conjunction with the HTTP Basic Profile in order to provide operations to read and write properties and invoke, query and cancel actions.
In order to conform with the HTTP SSE Profile, Web Things and Consumers MUST also conform with all of the assertions in the Common Constraints section.
In
order
to
denote
that
a
given
Web
Thing
conforms
to
the
HTTP
SSE
Profile,
its
Thing
Description
MUST
have
a
profile
member
[
wot-thing-description11
]
with
a
value
of
https://www.w3.org/2022/wot/profile/http-sse/v1
.
This section defines a protocol binding which describes how a Consumer communicates with a Web Thing [ wot-architecture11 ] using Server-Sent Events [ EVENTSOURCE ].
A Consumer or Web Thing conforming to the HTTP SSE Profile MUST implement this protocol binding.
The examples provided throughout this section describe how a Consumer would communicate with a Web Thing which produces the following Thing Description:
{
"@context": "https://www.w3.org/2022/wot/td/v1.1",
"id": "https://mywebthingserver.com/things/lamp",
"profile": [
"https://www.w3.org/2022/wot/profile/http-basic/v1",
"https://www.w3.org/2022/wot/profile/http-sse/v1",
],
"base": "https://mywebthingserver.com/things/lamp/",
"title": "My Lamp",
"description": "A web connected lamp",
"securityDefinitions": {
"oauth2": {
"scheme": "oauth2",
"flow": "code",
"authorization": "https://mywebthingserver.com/oauth/authorize",
"token": "https://mywebthingserver.com/oauth/token"
}
},
"security": "oauth2",
"properties": {
"on": {
"type": "boolean",
"title": "On/Off",
"description": "Whether the lamp is turned on",
"forms": [
{
"href": "properties/on",
"op": ["readproperty", "writeproperty"],
},
{
"href": "properties/on",
"op": ["observeproperty", "unobserveproperty"],
"subprotocol": "sse"
}
]
},
"level" : {
"type": "integer",
"title": "Brightness",
"description": "The level of light from 0-100",
"unit": "percent",
"minimum" : 0,
"maximum" : 100,
"forms": [
{
"href": "properties/level",
"op": ["readproperty", "writeproperty"],
},
{
"href": "properties/level",
"op": ["observeproperty", "unobserveproperty"],
"subprotocol": "sse"
}
]
},
}
},
"actions": {
"fade": {
"title": "Fade",
"description": "Fade the lamp to a given level",
"synchronous": false,
"input": {
"type": "object",
"properties": {
"level": {
"title": "Brightness",
"type": "integer",
"minimum": 0,
"maximum": 100,
"unit": "percent"
},
"duration": {
"title": "Duration",
"type": "integer",
"minimum": 0,
"unit": "milliseconds"
}
}
},
"forms": [{"href": "actions/fade"}]
}
},
"events": {
"overheated": {
"title": "Overheated",
"data": {
"type": "number",
"unit": "degree celsius"
},
"description": "The lamp has exceeded its safe operating temperature",
"forms": [{
"href": "events/overheated",
"subprotocol": "sse"
}]
}
},
"forms": [
{
"op": ["readallproperties", "writemultipleproperties"],
"href": "properties"
},
{
"op": ["observeallproperties", "unobserveallproperties"],
"href": "properties",
"subprotocol": "sse"
},
{
"op": "queryallactions",
"href": "actions"
},
{
"op": ["subscribeallevents", "unsubscribeallevents"],
"href": "events",
"subprotocol": "sse"
}
]
}
The
URL
of
a
Property
resource
to
be
used
when
observing
the
value
of
a
property
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
corresponding
PropertyAffordance
for
which:
op
member
contains
the
value
observeproperty
href
member
is
http
or
https
subprotocol
member
has
a
value
of
sse
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Property
resource.
In
order
to
observe
a
property,
a
Consumer
MUST
follow
the
Server-Sent
Events
[
EVENTSOURCE
]
specification
to
open
a
connection
with
the
Web
Thing
at
the
URL
of
the
Property
resource.
This involves the Consumer sending an HTTP request to the Web Thing with:
GET
Property
resource
Accept
header
set
to
text/event-stream
Connection
header
set
to
keep-alive
GET /things/lamp/properties/level HTTP/1.1
Host: mythingserver.com
Accept: text/event-stream
Connection
:
keep-alive
For
Consumers
implemented
in
JavaScript
[
ECMASCRIPT
]
and
executed
in
a
runtime
which
exposes
the
EventSource
interface,
a
Server-Sent
Events
connection
can
be
initiated
using
the
EventSource
constructor.
const
levelSource
=
new
EventSource
(
'/things/lamp/properties/level'
);
If a Web Thing receives an HTTP request following the format above and the Consumer has permission to observe the corresponding property, then it MUST follow the Server-Sent Events [ EVENTSOURCE ] specification to maintain an open connection with the Consumer and push a property value to the Consumer each time the value of the specified property changes.
This involves the Web Thing initially sending an HTTP response to the Consumer with:
200
Content-Type
header
set
to
text/event-stream
HTTP/1.1 200 OK
Content-Type
:
text/event-stream
Whenever
the
value
of
the
specified
property
changes
while
the
Web
Thing
has
an
open
connection
with
a
Consumer,
the
Web
Thing
MUST
send
a
property
value
to
the
Consumer
using
the
event
stream
format
in
the
Server-Sent
Events
[
EVENTSOURCE
]
specification.
For
each
message
sent,
the
Web
Thing
MUST
set
the
event
field
to
the
name
of
the
PropertyAffordance
and
populate
the
data
field
with
the
property
value,
serialized
in
JSON
and
following
the
data
schema
specified
in
the
PropertyAffordance
.
The
id
field
SHOULD
be
set
to
a
unique
identifier
for
the
property
change,
for
use
when
re-establishing
a
dropped
connection
(see
below).
It
is
RECOMMENDED
that
the
identifier
is
a
timestamp
representing
the
time
at
which
the
property
changed
(see
Date
Format
for
date
format
constraints).
event: level\n
data: 42\n
id:
2021-11-17T15:33:20.827Z
\n\n
If
the
connection
between
the
Consumer
and
Web
Thing
drops
(except
as
a
result
of
the
unobserve
operation
defined
below),
the
Consumer
MUST
re-establish
the
connection
following
the
steps
outlined
in
the
Server-Sent
Events
specification
[
EVENTSOURCE
].
Once
the
connection
is
re-established
the
Web
Thing
SHOULD
,
if
possible,
send
any
missed
property
changes
which
occurred
since
the
last
change
specified
by
the
Consumer
in
a
Last-Event-ID
header.
Property
values
are
serialised
in
JSON
and
provided
in
the
data
field
of
a
Server-Sent
Event
serialised
in
text/event-stream
format.
The
text/event-stream
content
type
used
in
HTTP
headers
is
assumed
to
be
implied
by
the
sse
subprotocol,
and
the
embedded
application/json
content
type
is
indicated
in
contentType
member
of
the
Form
(with
defaults
applied).
In order to stop observing a property, a Consumer MUST terminate the corresponding Server-Sent Events connection with the Web Thing as specified in the Server-Sent Events specification [ EVENTSOURCE ].
For
Consumers
implemented
in
JavaScript
[
ECMASCRIPT
]
and
executed
in
a
runtime
which
exposes
the
EventSource
interface,
a
Server-Sent
Events
connection
can
be
terminated
using
the
close()
method
on
an
EventSource
[
EVENTSOURCE
]
object.
levelSource.close()
;
The
URL
of
a
properties
resource
to
be
used
when
observing
changes
to
all
properties
of
a
Web
Thing
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
top
level
forms
member
of
a
Thing
Description
for
which:
op
member
contains
the
value
observeallproperties
href
member
is
http
or
https
subprotocol
member
has
a
value
of
sse
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
properties
resource.
In order to observe changes to all properties of a Web Thing, a Consumer MUST follow the Server-Sent Events [ EVENTSOURCE ] specification to open a connection with the Web Thing at the URL of the properties resource.
This involves the Consumer sending an HTTP request to the Web Thing with:
GET
Accept
header
set
to
text/event-stream
Connection
header
set
to
keep-alive
GET /things/lamp/properties HTTP/1.1
Host: mythingserver.com
Accept: text/event-stream
Connection
:
keep-alive
For
Consumers
implemented
in
JavaScript
[
ECMASCRIPT
]
and
executed
in
a
runtime
which
exposes
the
EventSource
interface,
a
Server-Sent
Events
connection
can
be
initiated
using
the
EventSource
constructor.
const
lampPropertiesSource
=
new
EventSource
(
'/things/lamp/properties'
);
If a Web Thing receives an HTTP request following the format above then it MUST follow the Server-Sent Events [ EVENTSOURCE ] specification to maintain an open connection with the Consumer and push new property values to the Consumer for all properties for which it has permission to observe.
This involves the Web Thing initially sending an HTTP response to the Consumer with:
200
Content-Type
header
set
to
text/event-stream
HTTP/1.1 200 OK
Content-Type
:
text/event-stream
Whenever
a
property
changes
while
the
Web
Thing
has
an
open
connection
with
a
Consumer,
the
Web
Thing
MUST
send
the
new
property
value
to
the
Consumer
using
the
event
stream
format
in
the
Server-Sent
Events
[
EVENTSOURCE
]
specification.
For
each
message
sent,
the
Web
Thing
MUST
set
the
event
field
to
the
name
of
the
PropertyAffordance
and
populate
the
data
field
with
the
new
property
value.
The
property
data
MUST
follow
the
data
schema
specified
in
the
PropertyAffordance
and
MUST
be
serialized
in
JSON.
The
id
field
SHOULD
be
set
to
a
unique
identifier
for
the
event,
for
use
when
re-establishing
a
dropped
connection
(see
below).
It
is
RECOMMENDED
that
the
identifier
is
a
timestamp
representing
the
time
at
which
the
property
changed
(see
Date
Format
for
date
format
constraints).
event: level\n
data: 42\n
id:
2021-11-17T15:33:20.827Z
\n\n
If
the
connection
between
the
Consumer
and
Web
Thing
drops
(except
as
a
result
of
the
unobserveallproperties
operation
defined
below),
the
Consumer
MUST
re-establish
the
connection
following
the
steps
outlined
in
the
Server-Sent
Events
specification
[
EVENTSOURCE
].
Once
the
connection
is
re-established
the
Web
Thing
SHOULD
,
if
possible,
send
any
missed
property
changes
which
occurred
since
the
last
change
specified
by
the
Consumer
in
a
Last-Event-ID
header.
Property
values
are
serialised
in
JSON
and
provided
in
the
data
field
of
a
Server-Sent
Event
serialised
in
text/event-stream
format.
The
text/event-stream
content
type
used
in
HTTP
headers
is
assumed
to
be
implied
by
the
sse
subprotocol,
and
the
embedded
application/json
content
type
is
indicated
in
contentType
member
of
the
Form
(with
defaults
applied).
In order to unobserve all properties, a Consumer MUST terminate the corresponding Server-Sent Events connection with the properties endpoint of the Web Thing, following the steps specified in the Server-Sent Events specification [ EVENTSOURCE ].
For
Consumers
implemented
in
JavaScript
[
ECMASCRIPT
]
and
executed
in
a
runtime
which
exposes
the
EventSource
interface,
a
Server-Sent
Events
connection
can
be
terminated
using
the
close()
method
on
an
EventSource
[
EVENTSOURCE
]
object.
lampPropertiesSource.close()
;
The HTTP SSE Profile uses Server-Sent Events [ EVENTSOURCE ] as a mechanism for Consumers to subscribe to events emitted by a Web Thing.
Consumers
are
not
required
to
implement
the
EventSource
JavaScript
API
from
the
Server-Sent
Events
specification
in
order
to
conform
with
this
profile.
Any
programming
language
may
be
used
to
consume
an
event
stream.
The
URL
of
an
Event
resource
to
be
used
when
subscribing
to
an
event
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
corresponding
EventAffordance
for
which:
op
member
contains
the
value
subscribeevent
href
member
is
http
or
https
subprotocol
member
has
a
value
of
sse
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Event
resource.
In
order
to
subscribe
to
an
event,
a
Consumer
MUST
follow
the
Server-Sent
Events
[
EVENTSOURCE
]
specification
to
open
a
connection
with
the
Web
Thing
at
the
URL
of
the
Event
resource.
This involves the Consumer sending an HTTP request to the Web Thing with:
GET
Event
resource
Accept
header
set
to
text/event-stream
Connection
header
set
to
keep-alive
GET /things/lamp/events/overheated HTTP/1.1
Host: mythingserver.com
Accept: text/event-stream
Connection
:
keep-alive
For
Consumers
implemented
in
JavaScript
[
ECMASCRIPT
]
and
executed
in
a
runtime
which
exposes
the
EventSource
interface,
a
Server-Sent
Events
connection
can
be
initiated
using
the
EventSource
constructor.
const
overheatedEventSource
=
new
EventSource
(
'/things/lamp/events/overheated'
);
If a Web Thing receives an HTTP request following the format above and the Consumer has permission to subscribe to the corresponding event, then it MUST follow the Server-Sent Events [ EVENTSOURCE ] specification to maintain an open connection with the Consumer and push event data to the Consumer as events of the specified type are emitted.
This involves the Web Thing initially sending an HTTP response to the Consumer with:
200
Content-Type
header
set
to
text/event-stream
HTTP/1.1 200 OK
Content-Type
:
text/event-stream
Whenever
an
event
of
the
specified
type
occurs
while
the
Web
Thing
has
an
open
connection
with
a
Consumer,
the
Web
Thing
MUST
send
event
data
to
the
Consumer
using
the
event
stream
format
in
the
Server-Sent
Events
[
EVENTSOURCE
]
specification.
For
each
message
sent,
the
Web
Thing
MUST
set
the
event
field
to
the
name
of
the
EventAffordance
and
populate
the
data
field
with
event
data,
if
any.
The
event
data
MUST
follow
the
data
schema
specified
in
the
EventAffordance
and
be
serialized
in
JSON.
The
id
field
SHOULD
be
set
to
a
unique
identifier
for
the
event,
for
use
when
re-establishing
a
dropped
connection
(see
below).
It
is
RECOMMENDED
that
the
identifier
is
a
timestamp
representing
the
time
at
which
the
event
ocurred
(see
Date
Format
for
date
format
constraints).
event: overheated\n
data: 90\n
id:
2021-11-16T16:53:50.817Z
\n\n
If
the
connection
between
the
Consumer
and
Web
Thing
drops
(except
as
a
result
of
the
unsubscribeevent
operation
defined
below),
the
Consumer
MUST
re-establish
the
connection
following
the
steps
outlined
in
the
Server-Sent
Events
specification
[
EVENTSOURCE
].
Once
the
connection
is
re-established
the
Web
Thing
SHOULD
,
if
possible,
send
any
missed
events
which
occurred
since
the
last
event
specified
by
the
Consumer
in
a
Last-Event-ID
header.
Event
payloads
are
serialised
in
JSON
and
provided
in
the
data
field
of
a
Server-Sent
Event
serialised
in
text/event-stream
format.
The
text/event-stream
content
type
used
in
HTTP
headers
is
assumed
to
be
implied
by
the
sse
subprotocol,
and
the
embedded
application/json
content
type
is
indicated
in
contentType
member
of
the
Form
(with
defaults
applied).
In order to unsubscribe from an event, a Consumer MUST terminate the corresponding Server-Sent Events connection with the Web Thing as specified in the Server-Sent Events specification [ EVENTSOURCE ].
For
Consumers
implemented
in
JavaScript
[
ECMASCRIPT
]
and
executed
in
a
runtime
which
exposes
the
EventSource
interface,
a
Server-Sent
Events
connection
can
be
terminated
using
the
close()
method
on
an
EventSource
[
EVENTSOURCE
]
object.
overheatedEventSource.close()
;
The
URL
of
an
events
resource
to
be
used
when
subscribing
to
all
events
emitted
by
a
Web
Thing
MUST
be
obtained
from
a
Thing
Description
by
locating
a
Form
inside
the
top
level
forms
member
of
a
Thing
Description
for
which:
op
member
contains
the
value
subscribeallevents
href
member
is
http
or
https
subprotocol
member
has
a
value
of
sse
contentType
member
is
application/json
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
events
resource.
In order to subscribe to all events emitted by a Web Thing, a Consumer MUST follow the Server-Sent Events [ EVENTSOURCE ] specification to open a connection with the Web Thing at the URL of the events resource.
This involves the Consumer sending an HTTP request to the Web Thing with:
GET
Accept
header
set
to
text/event-stream
Connection
header
set
to
keep-alive
GET /things/lamp/events HTTP/1.1
Host: mythingserver.com
Accept: text/event-stream
Connection
:
keep-alive
For
Consumers
implemented
in
JavaScript
[
ECMASCRIPT
]
and
executed
in
a
runtime
which
exposes
the
EventSource
interface,
a
Server-Sent
Events
connection
can
be
initiated
using
the
EventSource
constructor.
const
lampEventsSource
=
new
EventSource
(
'/things/lamp/events'
);
If a Web Thing receives an HTTP request following the format above then it MUST follow the Server-Sent Events [ EVENTSOURCE ] specification to maintain an open connection with the Consumer and push event data to the Consumer for all event types for which it has permission to subscribe.
This involves the Web Thing initially sending an HTTP response to the Consumer with:
200
Content-Type
header
set
to
text/event-stream
HTTP/1.1 200 OK
Content-Type
:
text/event-stream
Whenever
an
event
occurs
while
the
Web
Thing
has
an
open
connection
with
a
Consumer,
the
Web
Thing
MUST
send
event
data
to
the
Consumer
using
the
event
stream
format
in
the
Server-Sent
Events
[
EVENTSOURCE
]
specification.
For
each
message
sent,
the
Web
Thing
MUST
set
the
event
field
to
the
name
of
the
EventAffordance
and
populate
the
data
field
with
event
data,
if
any.
The
event
data
MUST
follow
the
data
schema
specified
in
the
EventAffordance
and
be
serialized
in
JSON.
The
id
field
SHOULD
be
set
to
a
unique
identifier
for
the
event,
for
use
when
re-establishing
a
dropped
connection
(see
below).
It
is
RECOMMENDED
that
the
identifier
is
a
timestamp
representing
the
time
at
which
the
event
ocurred
(see
Date
Format
for
date
format
constraints).
event: overheated\n
data: 90\n
id:
2021-11-16T16:53:50.817Z
\n\n
If
the
connection
between
the
Consumer
and
Web
Thing
drops
(except
as
a
result
of
the
unsubscribeallevents
operation
defined
below),
the
Consumer
MUST
re-establish
the
connection
following
the
steps
outlined
in
the
Server-Sent
Events
specification
[
EVENTSOURCE
].
Once
the
connection
is
re-established
the
Web
Thing
SHOULD
,
if
possible,
send
any
missed
events
which
occurred
since
the
last
event
specified
by
the
Consumer
in
a
Last-Event-ID
header.
Event
payloads
are
serialised
in
JSON
and
provided
in
the
data
field
of
a
Server-Sent
Event
serialised
in
text/event-stream
format.
The
text/event-stream
content
type
used
in
HTTP
headers
is
assumed
to
be
implied
by
the
sse
subprotocol,
and
the
embedded
application/json
content
type
is
indicated
in
contentType
member
of
the
Form
(with
defaults
applied).
In order to unsubscribe from all events, a Consumer MUST terminate the corresponding Server-Sent Events connection with the events endpoint of the Web Thing, following the steps specified in the Server-Sent Events specification [ EVENTSOURCE ].
For
Consumers
implemented
in
JavaScript
[
ECMASCRIPT
]
and
executed
in
a
runtime
which
exposes
the
EventSource
interface,
a
Server-Sent
Events
connection
can
be
terminated
using
the
close()
method
on
an
EventSource
[
EVENTSOURCE
]
object.
lampEventsSource.close()
;
This section defines the HTTP Webhook Profile, including a Protocol Binding for observing properties and listening for events using Webhooks .
The HTTP Webhook profile MAY be used in conjunction with the HTTP Basic Profile in order to provide operations to read and write properties and invoke, query and cancel actions.
The HTTP Webhook profile MAY be used as an alternative event mechanism to the HTTP SSE Profile .
In order to conform with the HTTP Webhook Profile, Web Things and Consumers MUST also conform with all of the assertions in the Common Constraints section.
In order to implement the HTTP Webhook profile it must be possible for both the Thing and Consumer to act as both an HTTP client and HTTP server, accessible by each other over a network. This may not be possible in all deployment scenarios.
In
order
to
denote
that
a
given
Web
Thing
conforms
to
the
HTTP
Webhook
Profile,
its
Thing
Description
MUST
have
a
profile
member
[
wot-thing-description11
]
with
a
value
of
https://www.w3.org/2022/wot/profile/http-webhook/v1
.
Note
that
the
profile
member
is
an
array
that
may
contain
multiple
profile
entries,
which
indicates
that
a
Web
Thing
conforms
to
all
of
the
profiles
in
that
array.
This section defines a protocol binding which describes how a Consumer and a Web Thing communicate using Webhooks.
A Consumer or Web Thing conforming to the HTTP Webhook Profile MUST implement this protocol binding.
The examples provided throughout this section describe how a Consumer would communicate with a Web Thing which produces the following Thing Description [ wot-thing-description11 ]:
{
"@context": "https://www.w3.org/2022/wot/td/v1.1",
"id": "https://mywebthingserver.com/things/lamp",
"profile": [
"https://www.w3.org/2022/wot/profile/http-webhook/v1",
],
"base": "https://mywebthingserver.com/things/lamp/",
"title": "My Lamp",
"description": "A web connected lamp",
"securityDefinitions": {
"oauth2": {
"scheme": "oauth2",
"flow": "code",
"authorization": "https://mywebthingserver.com/oauth/authorize",
"token": "https://mywebthingserver.com/oauth/token"
}
},
"security": "oauth2",
"properties": {
"on": {
"type": "boolean",
"title": "On/Off",
"description": "Whether the lamp is turned on",
"forms": [
{
"op": "observeproperty",
"href": "properties/on",
"subprotocol": "webhook",
"contentType": "application/json",
"htv:methodName": "POST"
},
{
"op": "unobserveproperty",
"href": "properties/on/{subscriptionID}",
"subprotocol": "webhook",
"htv:methodName": "DELETE"
}
]
},
"level" : {
"type": "integer",
"title": "Brightness",
"description": "The level of light from 0-100",
"unit": "percent",
"minimum" : 0,
"maximum" : 100,
"forms": [
{
"op": "observeproperty",
"href": "properties/level",
"subprotocol": "webhook",
"contentType": "application/json",
"htv:methodName": "POST"
},
{
"op": "unobserveproperty",
"href": "properties/level/{subscriptionID}",
"subprotocol": "webhook",
"htv:methodName": "DELETE"
}
]
},
},
"events": {
"overheated": {
"title": "Overheated",
"data": {
"type": "number",
"unit": "degree celsius"
},
"description": "The lamp has exceeded its safe operating temperature",
"subscription": {
"type": "object",
"properties": {
"callbackURL": {
"type": "string",
"format": "uri",
"description": "Callback URL provided by subscriber for Webhook notifications."
}
}
}
"forms": [
{
"op": "subscribeevent",
"href": "events/overheated",
"subprotocol": "webhook",
"contentType": "application/json",
"htv:methodName": "POST"
},
{
"op": "unsubscribeevent",
"href": "events/overheated/{subscriptionID}",
"subprotocol": "webhook",
"htv:methodName": "DELETE"
}
]
}
},
"forms": [
{
"op": "observeallproperties",
"href": "properties",
"subprotocol": "webhook",
"htv:methodName": "POST"
},
{
"op": "unobserveallproperties",
"href": "properties/{subscriptionID}",
"suprotocol": "webhook",
"htv:methodName": "DELETE"
},
{
"op": "subscribeallevents",
"href": "events",
"subprotocol": "webhook",
"htv:methodName": "POST"
},
{
"op": "unsubscribeallevents",
"href": "events/{subscriptionID}",
"suprotocol": "webhook",
"htv:methodName": "DELETE"
}
]
}
The URL of a Property resource to be used when observing the value of a property MUST be obtained from a Thing Description [ wot-thing-description11 ] by locating a Form inside the corresponding PropertyAffordance for which:
op
member
contains
the
value
observeproperty
href
member
is
http
or
https
contentType
member
has
a
value
of
application/json
subprotocol
member
has
a
value
of
webhook
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Property
resource.
In order to observe a property, a Consumer MUST send an HTTP request to the Web Thing with:
POST
Content-Type
header
set
to
application/json
callbackURL
member
set
to
a
callback
URL
the
Thing
should
use
to
send
property
change
notifications
to
the
Consumer.
POST /things/lamp/properties/level HTTP/1.1
Host: mythingserver.com
Content-Type: application/json
{
callbackURL: "https://myconsumer.com/listeners/d629c54e-a919-463b-8680-602a21f91fe9"
}
If a Web Thing receives an HTTP request following the format above and the Consumer has permission to observe the corresponding property, then upon successfully registering a callback URL it MUST send an HTTP response to the Consumer with:
201
Created
Location
header
set
to
a
unique
URL
representing
the
individual
property
observation
subscription,
for
use
by
the
Consumer
when
later
cancelling
the
observation
of
the
Property.
HTTP/1.1 201 Created
Location
:
/things/properties/level/74353483-3997-437a-a4f5-84d03784e517
Whilst the Property observation subscription is registered, whenever a change in the value of the observed property occurs, the Web Thing MUST send an HTTP request to the observing Consumer with:
POST
Content-Type
header
set
to
application/json
Link
header
with
the
URL
set
to
the
URL
of
the
corresponding
Property
Affordance,
and
rel
set
to
self
Date
header
automatically
set
to
the
time
of
the
property
change
by
the
user
agent,
using
the
HTTP
Date
format
from
[
rfc9110
]
POST /listeners/d629c54e-a919-463b-8680-602a21f91fe9 HTTP/1.1
Host: myconsumer.com
Date: Fri, 4 Jul 2025 12:48:00 GMT
Content-type: application/json
Link: <https://mythingserver.com/things/mylamp1/properties/level>; rel="self"
90
When a Consumer receives an HTTP request following the format above to a valid callback URL, it MUST send an HTTP response to the Web Thing with:
200
OK
HTTP/1.1
200
OK
In order to cancel the observation subscription of a property, a Consumer MUST send an HTTP request to the Web Thing with:
DELETE
Location
header
of
the
HTTP
response
during
the
observeproperty
operation
DELETE /things/properties/level/74353483-3997-437a-a4f5-84d03784e517 HTTP/1.1
Host:
mythingserver.com
If a Web Thing receives an HTTP request following the format above, and a property observation subscription exists with the provided URL, then upon successfully cancelling the subscription the Web Thing MUST send an HTTP response to the Consumer with:
204
No
Content
HTTP/1.1
204
No
Content
The
URL
of
a
Properties
resource
to
be
used
when
observing
the
values
of
all
properties
of
a
Web
Thing
MUST
be
obtained
from
a
Thing
Description
[
wot-thing-description11
]
by
locating
a
Form
inside
the
top
level
forms
member
of
a
Thing
Description
for
which:
op
member
contains
the
value
observeallproperties
href
member
is
http
or
https
contentType
member
has
a
value
of
application/json
subprotocol
member
has
a
value
of
webhook
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Properties
resource.
In order to observe changes to all Properties of a Web Thing , a Consumer MUST send an HTTP request to the Web Thing with:
POST
Content-Type
header
set
to
application/json
callbackURL
member
set
to
a
callback
URL
the
Thing
should
use
to
send
property
change
notifications
to
the
Consumer.
POST /things/lamp/properties HTTP/1.1
Host: mythingserver.com
Content-Type: application/json
{
callbackURL: "https://myconsumer.com/listeners/aa2d8e1f-dc6a-4fe0-a5c0-a42d9f532699"
}
If a Web Thing receives an HTTP request following the format above and the Consumer has permission to observe properties of the Thing, then upon successfully registering a callback URL it MUST send an HTTP response to the Consumer with:
201
Created
Location
header
set
to
a
unique
URL
representing
the
individual
observation
subscription,
for
use
by
the
Consumer
when
later
cancelling
the
observation
of
all
properties.
HTTP/1.1 201 Created
Location
:
/things/properties/a84fc5df-2667-4db2-a767-feb4640f2cf7
Whilst the Properties observation subscription is registered, whenever a change in the value of any observeable property occurs, the Web Thing MUST send an HTTP request to the observing Consumer with:
POST
Content-Type
header
set
to
application/json
Link
header
with
the
URL
set
to
the
URL
of
the
corresponding
Property
Affordance,
and
rel
set
to
self
Date
header
automatically
set
to
the
time
of
the
property
change
by
the
user
agent,
using
the
HTTP
Date
format
from
[
rfc9110
]
POST /listeners/aa2d8e1f-dc6a-4fe0-a5c0-a42d9f532699 HTTP/1.1
Host: myconsumer.com
Date: Fri, 4 Jul 2025 12:56:00 GMT
Content-type: application/json
Link: <https://mythingserver.com/things/mylamp1/properties/level>; rel="self"
86
When a Consumer receives an HTTP request following the format above to a valid callback URL, it MUST send an HTTP response to the Web Thing with:
200
OK
HTTP/1.1
200
OK
In order to cancel the observation of all properties, a Consumer MUST send an HTTP request to the Web Thing with:
DELETE
Location
header
of
the
HTTP
response
during
the
observeallproperties
operation
DELETE /things/properties/a84fc5df-2667-4db2-a767-feb4640f2cf7 HTTP/1.1
Host:
mythingserver.com
If a Web Thing receives an HTTP request following the format above, and a properties observation subscription exists with the provided URL, then upon successfully cancelling the observation subscription the Web Thing MUST send an HTTP response to the Consumer with:
204
No
Content
HTTP/1.1
204
No
Content
The URL of an Event resource to be used when subscribing to an event MUST be obtained from a Thing Description [ wot-thing-description11 ] by locating a Form inside the corresponding EventAffordance for which:
op
member
contains
the
value
subscribeevent
href
member
is
http
or
https
contentType
member
has
a
value
of
application/json
subprotocol
member
has
a
value
of
webhook
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Event
resource.
POST /things/lamp/events/overheated HTTP/1.1
Host: mythingserver.com
Content-Type: application/json
{
callbackURL: "https://myconsumer.com/listeners/e79dd0a5-4537-4ded-a10f-bb4eb2aca28d"
}
If a Web Thing receives an HTTP request following the format above and the Consumer has permission to subscribe to the corresponding event, then upon successfully registering a callback URL it MUST send an HTTP response to the Consumer with:
201
Created
Location
header
set
to
a
unique
URL
representing
the
individual
event
subscription,
for
use
by
the
Consumer
when
later
cancelling
the
subscription.
HTTP/1.1 201 Created
Location
:
/things/events/overheated/ce527faa-a5ab-4f03-8f85-e4411d13edb5
Whilst the Event subscription is registered, whenever an instance of the monitored event occurs, the Web Thing MUST send an HTTP request to the subscribed Consumer with:
POST
Content-Type
header
set
to
application/json
Link
header
with
the
URL
set
to
the
URL
of
the
corresponding
Event
Affordance,
and
rel
set
to
self
Date
header
automatically
set
to
the
time
the
event
occurred
by
the
user
agent,
using
the
HTTP
Date
format
from
[
rfc9110
]
If
the
event
does
not
include
a
data
payload
then
the
Content-type
header
of
the
request
SHOULD
NOT
be
set,
and
the
body
should
be
empty.
POST /listeners/e79dd0a5-4537-4ded-a10f-bb4eb2aca28d HTTP/1.1
Host: myconsumer.com
Date: Fri, 4 Jul 2025 16:46:00 GMT
Content-type: application/json
Link: <https://mythingserver.com/things/mylamp1/events/overheated>; rel="self"
90
When a Consumer receives an HTTP request following the format above to a valid callback URL, it MUST send an HTTP response to the Web Thing with:
200
OK
HTTP/1.1
200
OK
In order to cancel the subscription to an event, a Consumer MUST send an HTTP request to the Web Thing with:
DELETE
Location
header
of
the
HTTP
response
during
the
subscribeevent
operation
DELETE /things/events/overheated/ce527faa-a5ab-4f03-8f85-e4411d13edb5 HTTP/1.1
Host:
mythingserver.com
If a Web Thing receives an HTTP request following the format above, and an event subscription exists with the provided URL, then upon successfully cancelling the subscription the Web Thing MUST send an HTTP response to the Consumer with:
204
No
Content
HTTP/1.1
204
No
Content
The
URL
of
an
Events
resource
to
be
used
when
subscribing
to
all
events
of
a
Web
Thing
MUST
be
obtained
from
a
Thing
Description
[
wot-thing-description11
]
by
locating
a
Form
inside
the
top
level
forms
member
of
the
Thing
Description
for
which:
op
member
contains
the
value
subscribeallevents
href
member
is
http
or
https
contentType
member
has
a
value
of
application/json
subprotocol
member
has
a
value
of
webhook
The
resolved
value
of
the
href
member
MUST
then
be
used
as
the
URL
of
the
Events
resource.
In order to subscribe to all Events of a Web Thing , a Consumer MUST send an HTTP request to the Web Thing with:
POST
Content-Type
header
set
to
application/json
callbackURL
member
set
to
a
callback
URL
the
Thing
should
use
to
send
event
notifications
to
the
Consumer
.
POST /things/lamp/events HTTP/1.1
Host: mythingserver.com
Content-Type: application/json
{
callbackURL: "https://myconsumer.com/listeners/bdd2aa13-387b-4c97-9725-52294a9fa5a9"
}
If a Web Thing receives an HTTP request following the format above and the Consumer has permission to subscribe to events of the Thing, then upon successfully registering a callback URL it MUST send an HTTP response to the Consumer with:
201
Created
Location
header
set
to
a
unique
URL
representing
the
individual
event
subscription,
for
use
by
the
Consumer
when
later
cancelling
the
subscription.
HTTP/1.1 201 Created
Location
:
/things/events/929dbb69-eb66-46df-a0fe-93701d82e7ea
Whilst the Events subscription is registered, whenever an event occurs, the Web Thing MUST send an HTTP request to the subscribed Consumer with:
POST
Content-Type
header
set
to
application/json
Link
header
with
the
URL
set
to
the
URL
of
the
corresponding
Event
Affordance,
and
rel
set
to
self
Date
header
automatically
set
to
the
time
the
event
occurred
by
the
user
agent,
using
the
HTTP
Date
format
from
[
rfc9110
]
If
the
event
does
not
include
a
data
payload
then
the
Content-type
header
of
the
request
SHOULD
NOT
be
set,
and
the
body
should
be
empty.
POST /listeners/bdd2aa13-387b-4c97-9725-52294a9fa5a9 HTTP/1.1
Host: myconsumer.com
Date: Fri, 4 Jul 2025 17:04:00 GMT
Content-type: application/json
Link: <https://mythingserver.com/things/mylamp1/events/overheated>; rel="self"
86
When a Consumer receives an HTTP request following the format above to a valid callback URL, it MUST send an HTTP response to the Web Thing with:
200
OK
HTTP/1.1
200
OK
In order to cancel the subscription to all events, a Consumer MUST send an HTTP request to the Web Thing with:
DELETE
Location
header
of
the
HTTP
response
during
the
subscribeallevents
operation
DELETE /things/events/929dbb69-eb66-46df-a0fe-93701d82e7ea HTTP/1.1
Host:
mythingserver.com
If a Web Thing receives an HTTP request following the format above, and an events subscription exists with the provided URL, then upon successfully cancelling the events subscription the Web Thing MUST send an HTTP response to the Consumer with:
204
No
Content
HTTP/1.1
204
No
Content
The privacy considerations of the WoT Architecture [ wot-architecture11 ] and WoT Thing Description [ wot-thing-description11 ] specifications SHOULD be taken into account.
Please also see WoT Security and Privacy Guidelines [ wot-security ] for implementation advice.
The security considerations of the WoT Architecture [ wot-architecture11 ] and WoT Thing Description [ wot-thing-description11 ] specifications SHOULD be taken into account.
Please also see WoT Security and Privacy Guidelines [ wot-security ] for implementation advice.
The
values
of
title
and
description
members
at
all
levels
of
a
Thing
Description
may
be
used
to
generate
a
user
interface
and
SHOULD
therefore
be
human
readable
strings
which
can
also
be
rendered
by
assistive
technologies
when
necessary.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: