Subscriptions and registrations
Subscriptions
What a subscription must hold
notification, notification.endpoint and notification.endpoint.uri are required. A new subscription also needs entities, watchedAttributes or both, unless localOnly is true, and entities is required whenever timeInterval is set.
type, when present, is Subscription. An id you choose is a URI, and one already in use gets 409 AlreadyExists.
Some members exclude each other, and these rules hold on creation and again after an update is merged with the stored subscription. timeInterval excludes watchedAttributes and throttling. timeInterval and throttling are both greater than zero, and watchedAttributes, notificationTrigger and entities can't be empty.
expiresAt is in the future, on creation and when an entity subscription is updated.
A member of the wrong JSON type is refused, on creation and in an update fragment alike. It is never ignored or defaulted.
POST /subscriptions takes no query parameters.
Where it delivers
Andromeda delivers to http, https, mqtt and mqtts, and the endpoint URI is an absolute URI with one of those schemes. An MQTT endpoint names a host and a topic without wildcards, and its MQTT-Version and MQTT-QoS take only the defined values. cooldown and timeout are positive.
notification.endpoint.accept is application/json, application/ld+json or application/geo+json, spelled exactly that way. Any other value gets 400 BadRequestData, and so does application/geo+json on a context source registration subscription.
What it notifies
notification.format is one of the four representations, matched case-sensitively. showChanges is refused with keyValues and simplified. pick, omit and attributes exclude each other, and joinLevel is positive.
lang is one BCP 47 tag.
jsonldContext is an absolute IRI, and Andromeda fetches it when the subscription is written. If it can't be fetched, the answer is 504 LdContextNotAvailable.
Names and filters
Every name a subscription carries expands under its @context. That covers entity types, watchedAttributes, notification.attributes, pick, omit, expandValues, jsonKeys, the terms of q and csf, and the geoproperty of geoQ. A name the context maps to nothing gets 400 BadRequestData, on creation and in an update fragment. Matching reads only expanded names, so a name kept as written would never match anything. An unreachable @context gets 504 LdContextNotAvailable.
q, geoQ and scopeQ are checked when the subscription is written, not when it first matches, so a malformed one is refused straight away. A q may be an existence test on its own (q=n), and it may follow Relationships into linked entities (see Linked entities).
A geoQ carries only geometry, coordinates, georel and geoproperty. No clause refuses an extra member there, so this is stricter than the specification asks. It stops a misspelt geoproperty from silently falling back to location.
temporalQ belongs to context source registration subscriptions, and it carries both timeAt and timerel. An entity subscription that sets one, on creation or in an update, gets 400 BadRequestData. Removing one with the NGSI-LD Null is still accepted.
Members it doesn't define
A subscription body, its notification and its notification.endpoint carry only the members the specification's tables define. Any other member gets 400 BadRequestData naming it, on creation and in an update fragment. No clause refuses an extra member here either, so this too is stricter than the specification asks. A registration keeps extra members as Context Source Properties, but a subscription has nowhere to keep one. The rule stops a misspelt watchedAttributes from turning into a subscription that watches every attribute.
A term your @context maps onto a member is that member, and it is read. The members Andromeda generates are accepted whatever they hold, and ignored (see Deliberate tolerances).
Update fragments
In an update fragment, a member written as the NGSI-LD Null removes the stored member. That works for every optional member, whatever its data type. A member that takes an array (entities, watchedAttributes, notificationTrigger or datasetId) also accepts an array holding only the Null. The Null is refused on notification and type, which are required, and anywhere in a creation body.
Context source registrations
type (ContextSourceRegistration), information and endpoint are required, and information can't be empty. Each RegistrationInfo names at least one of entities, propertyNames and relationshipNames, none of them empty, and every EntityInfo names a type.
endpoint and jsonldContext are absolute URIs, and mode and operations take only the defined values. refreshRate and cacheDuration are ISO 8601 durations. expiresAt is in the future, time intervals run in order, and geometries follow Geometry. management refuses members it doesn't define, and it needs a positive cooldown and timeout.
In contextSourceInfo, Accept and Content-Type are application/json or application/ld+json, jsonldContext is a URL, and ngsildConformance is written as major.minor.
An exclusive registration names its entities by id only and names at least one attribute. An auxiliary registration offers only retrieval operations.
A registration gets 409 Conflict when it overlaps an exclusive registration, a redirect registration, or local data it isn't allowed to cover.
Discovery (GET /csourceRegistrations) needs a type, attributes, q or geoQ, and its type names a single type.
In an update fragment, a member written as the NGSI-LD Null removes the stored member, whatever its data type. That covers every optional member, expiresAt, geometries and management among them, and every Context Source Property. A member that takes an array (datasetId, operations, scope, contextSourceInfo or information) also accepts an array holding only the Null. The Null is refused on type, information, endpoint and mode, and anywhere in a creation body, Context Source Properties included.