Download OpenAPI specification:Download
Sending a new MSI is two-phase (create then send). This is because the msiId value is a critical piece of information for the client (to be able to check status and/or cancel) and the API design must ensure that the client is safely in possession of msiID before a send happens. If the method was one phase then there would be no guarantee that the msiID was received (a failure could happen in any link in the return snetworking chain like a router, firewall, proxy server or indeed a problem at the client application end that prevented persistence of the msiID for later use). Moreover, if the method was one phase and a failure in the network chain occurred then not only would an orphan MSI be sent by the provider but the client would not have knowledge that the MSI had been successfully queued for sending and would naturally retry the send (multiple times even) and we end up with the same MSI being sent 2+ times.
To further clarify the problem being solved by a two phase send here is a discussion of the delivery guarantees of HTTP responses.
Note that a one phase call where the client generated a new unique id (using a UUID for instance) is a possible solution but is less desirable because it introduces a problematic edge case where the client accidentally uses the same id more than once. If two different messages are sent with the same id (concurrently even) then the service should ensure that only one message is accepted and that the service consumer is aware that the other message failed. To do this demands coordination with a single transactional resource (like a relational database) which also demands that that resource is highly available (relational databases are often not great at that during upgrade cycles). There are ways to get high availability (highly available cloud services like DynamoDB and many more can offer conditional updates) but there is a much simpler way with two-phase.
If instead of the one-phase call the server creates the msiId and communicates it to the client then the server side can potentially be scaled with ease if the msiID is a UUID for instance (which is effectively unique without coordination with other nodes).
For example, a highly available and scalable service could be constructed in AWS cloud using API Gateway with Lambda integrations that for the create message and send actions does this
A separate component then actions items on the queue(s). When both the send and create messages have been read then an actual send can take place. What is clear from this design is that many concurrent nodes could be receiving messages without coordinating with a central node/service to ensure id uniqueness.
Note also that to support two-phase send the status value of
CREATED
is included.
The List MSIs action uses a paginated response as the number of MSIs in a response can get large. Pagination can reduce server overhead and improve response times. Client-driven pagination is where the client specifies an offset (skip) field and that number of rows is skipped by the server to return the next page. This can be inefficient for the server-side (see discussion)) and it is preferred to use server-driven pagination which is where each page returned also includes a continuation token to be included in the next page call. The nice thing about this approach is that the server side can simply return an offset in the continuation token if desired but we enable more efficient techniques if wanted later.
Early versions of this API have suggested the inclusion of a
NationalSASId
field in the created MSI with the purpose of allowing
a client to correlate an MSI with its internal data.
This field is a convenience only and thus theoretically should not be included. A client should manage its correlations itself by storing the unique msiId returned by the service paired with its internal identifiers.
If something is required then it should be labelled something
like tag
and have arbitrary values so that the client can use it for
anything. Labelling it NationalSASId
suggests more meaning to the
field than it may have. TODO confirm.
Note that the api below allows for float precision locations for geographic circles and rectangles. An implementation of this API may choose to use the location with reduced precision (for example lat longs rounded to nearest integer).
A PUT to an /msi/[id}
path ]with content like {"isCancelled":true}
has been suggested as a way of cancelling a broadcast. This can be
achieved in a much simpler way with the DELETE verb without content
(a cancel action can be considered as a logical delete in the context
of this API). A cancelled broadcast cannot be changed in status but
can be queried.
Initial proposals for the API suggested a partial abstraction of C-Codes. In particular Priority, MsiType and AreaType were abstracted. This API demonstrates a full abstraction of C-Codes. It is equivalent to C-Codes but has an easier to read and process representation and the mapping to C-Codes then becomes a server-side implementation detail. By using the data modelling constructs of OpenAPI v3 and JSON Schema users can generate code for their API-consuming application that imposes compile-time checking (varies on language) instead of experiencing runtime failures.
TODO is there a requirement for full explicit C-Code support (zero abstraction)?
Initial proposals for this API included a re-authenticate method whereby a new token was returned if a currently valid token was supplied. This is a security hole in that anyone in possession of one valid token (but not the username and password) can stay authenticated forever. In the same vein, a sensible limit on validity duration of a token should be imposed so that a leaked token cannot be used for long. Given the likely usage of the API (in terms of the number of calls made in a time interval by a client) there should be no significant performance penalty forcing a refresh of the token each hour (or even less).
Bearer authentication is used (RFC6750).
Bearer authentication is carried in the Authorization
request header in this format:
Authorization: Bearer BASE64_ENCODED_TOKEN
TODO The encoded content of the token is not defined (for example, JWT could be used) but is left to the implementer. Should the authentication flow follow an existing standard like OAuth 2.0?
Previous API drafts used the field names startDate
and endDate
for an MSI.
Given that those fields refer to timestamps not just dates the names startTime
and endTime
have been used.
Iridium can at times provide receive and read acknowledgements. TODO get better documentation of the capability and a proper specification for their response from a list acks call.
There may be use cases for the following additional fields on an MSI:
A user could record in their own systems when they created or cancelled a broadcast but it might help problem diagnosis if that information was together.
TODO confirm
It would also be useful in some circumstances for users to know exactly when a message was broadcast by satellite. Although messages may be scheduled for immediate or later broadcast there may be significant delays till the broadcast occurs and the user should be able to see the actual broadcast times.
TODO discuss with satellite providers
Obtains a token that will be passed in a request header to calls to other paths on this API for authentication and authorization purposes.
username and password
username required | string non-empty |
password required | string non-empty |
validityMinutes | integer <int32> >= 1 The duration in minutes that the token will be valid,
capped by the maximum allowed server-decided duration. |
{- "username": "myrcc",
- "password": "a-nice-strong-password",
- "validityMinutes": 60
}
{- "token": "1/mZ1edKKACtPAb7zGlwSzvs72PvhAbGmB8K1ZrGxpcNM",
- "expiryTime": "2022-04-23T18:25:43.511Z"
}
Submits message content and returns a unique id (across all users) that is to be used in the send method. It is ok for a message to never be sent but the provider should have the freedom to clean up (delete) unsent messages after some reasonable period or after more than N unsent messages are created. (TODO ask providers what is reasonable minimum period and maximum number of unsent messages so it can be documented here).
Describes the message content
required | SARBroadcast (object) or MetBroadcast (object) or NavBroadcast (object) or PiracyBroadcast (object) (Broadcast) the details of the broadcast particular to the broadcast type |
startTime | string <date-time> the scheduled time of the initial broadcast. If omitted is assumed to be ASAP. A delayed start may not be supported by the service provider, check service provider documentation. TODO confirm |
endTime | string <date-time> the time after which no more broadcasts should be made of this MSI. This field may or may not be honoured by the service provider. The service provider may expect an explicit cancellation for ongoing broadcasts (like CAT-B). TODO confirm |
payload required | string (Payload) [ 1 .. 65535 ] characters the ASCII message text to broadcast. TODO what max length is appropriate? |
echo | boolean Default: false If the satellite provider supports echo then setting this field to true will request a repeat broadcast is made a short time after the first (Inmarsat applies a 6 minute interval). Consult the satellite provider documentation about under what circumstances the echo will be honoured. |
object (Repetition) | |
readAcksEnabled | boolean If the satellite provider supports read acknowledgements then setting this field to true will enable acknowledgements to the satellite provider that the message has been read by the receiving vessel. |
receiveAcksEnabled | boolean If the satellite provider supports receive acknowledgements then setting this field to true will enable acknowledgements to the satellite provider that the message has been received by the vessel. |
{- "broadcast": {
- "sarArea": {
- "lat": -34.5,
- "lon": 145.44,
- "radiusNm": 150
}, - "priority": "SAFETY"
}, - "startTime": "2022-04-23T10:30:43.511Z",
- "endTime": "2022-04-24T10:25:43.511Z",
- "payload": "a message to be broadcast",
- "echo": false,
- "repetition": {
- "number": "ONCE",
- "intervalHours": 1
}, - "readAcksEnabled": false,
- "receiveAcksEnabled": false
}
"289ee192-fdf5-4070-befc-3bf7291c1386"
Returns Maritime Safety Information broadcasts requested to be sent by the user.
Note that none of the parameters are required. If no parameters are supplied then all MSIs for the current user will be returned (paged).
The limit
field may not be honoured exactly by the server
side (in that it might exceed a maximum limit of the server).
The results of this query may return in any order and that order may vary in repeated calls (for example, the returned MSIs may not be ordered by timestamp). If the client requires an ordering by time then all pages should be requested and then sorted client-side. TODO confirm expectations
startTimeMin | string <date-time> Example: startTimeMin=2022-04-20T18:25:43.511Z If startTimeMinInclusive is true (the default value if not specified) then filters MSIs on startTime >= startTimeMin. If startTimeMinInclusive is false then filters MSIs on startTime > startTimeMin. |
startTimeMinInclusive | boolean Default: true Example: startTimeMinInclusive=true If startTimeMinInclusive is true (the default value if not specified) then filters MSIs on startTime >= startTimeMin. If startTimeMinInclusive is false then filters MSIs on startTime > startTimeMin. If startTimeMinInclusive not specified then has no effect. |
startTimeMax | string <date-time> Example: startTimeMax=2022-04-24T23:25:43.511Z If startTimeMaxInclusive is true (the default value if not specified) then filters MSIs on startTime <= startTimeMax. If startTimeMaxInclusive is false then filters MSIs on startTime < startTimeMax. |
startTimeMaxInclusive | boolean Default: true Example: startTimeMaxInclusive=true If startTimeMaxInclusive is true (the default value if not specified) then filters MSIs on startTime <= startTimeMax. If startTimeMaxInclusive is false then filters MSIs on startTime < startTimeMax. If startTimeMaxInclusive not specified then has no effect. |
endTimeMin | string <date-time> Example: endTimeMin=2022-04-21T18:25:43.511Z If endTimeMinInclusive is true (the default value if not specified) then filters MSIs on startTime >= startTimeMin. If startTimeMinInclusive is false then filters MSIs on startTime > startTimeMin. |
endTimeMinInclusive | boolean Example: endTimeMinInclusive=true If endTimeMinInclusive is true (the default value if not specified) then filters MSIs on endTime >= endTimeMin. If endTimeMinInclusive is false then filters MSIs on endTime > endTimeMin. If endTimeMinInclusive not specified then has no effect. |
endTimeMax | string <date-time> Example: endTimeMax=2022-04-25T14:18:23.000Z If endTimeMaxInclusive is true (the default value if not specified) then filters MSIs on endTime <= endTimeMax. If endTimeMaxInclusive is false then filters MSIs on endTime < endTimeMax. |
endTimeMaxInclusive | boolean Default: true Example: endTimeMaxInclusive=true If endTimeMaxInclusive is true (the default value if not specified) then filters MSIs on endTime <= endTimeMax. If endTimeMaxInclusive is false then filters MSIs on endTime < endTimeMax. If endTimeMaxInclusive not specified then has no effect. |
limit | integer <int32> >= 1 Default: 10 Requests that at most |
status | Array of strings (Status) Items Enum: "CREATED" "SCHEDULED" "ACTIVE" "FINISHED" "CANCELLING" "CANCELLED" "BROADCAST_ERROR" "CANCEL_ERROR" Example: status=CREATED&status=CANCELLED Only MSIs that have a status in the given list are returned. If the list is empty (or the parameter is not present) then no filtering on status occurs. TODO support multi-status filtering or just one? |
broadcastType | string (BroadcastType) Enum: "SARBroadcast" "MetBroadcast" "NavBroadcast" "PiracyBroadcast" Example: broadcastType=SARBroadcast the type of broadcast |
continuationToken | string (ContinuationToken) [ 1 .. 4096 ] characters Example: continuationToken=10 Describes to the server the starting point of the next page of results and is obtained from the current page. May contain an offset if desired but is at the discretion of implementer. Note that it is possible that a call specifying a continuation token may return en empty list (but an empty list return should not have a continuation token on it so at that point paging would stop). |
{- "msis": [
- {
- "id": "289ee192-fdf5-4070-befc-3bf7291c1386",
- "broadcast": {
- "sarArea": {
- "lat": -34.5,
- "lon": 145.44,
- "radiusNm": 150
}, - "priority": "SAFETY"
}, - "createdTime": "2022-04-23T10:25:43.511Z",
- "startTime": "2022-04-23T10:30:43.511Z",
- "endTime": "2022-04-24T10:25:43.511Z",
- "sentTime": "2022-04-23T10:26:40s.511Z",
- "cancellingTime": "2022-04-23T10:26:40s.511Z",
- "cancelledTime": "2022-04-24T13:28:43.511Z",
- "activeTime": "2022-04-24T13:29:47.511Z",
- "finishedTime": "2022-04-24T13:45:50.511Z",
- "errorTime": "2022-04-24T13:48:50.511Z",
- "payload": "a message to be broadcast",
- "status": "ACTIVE",
- "statusMessage": "string",
- "echo": false,
- "repetition": {
- "number": "ONCE",
- "intervalHours": 1
}, - "readAcksEnabled": false,
- "receiveAcksEnabled": false
}
], - "continuationToken": 10
}
Returns the details of an MSI broadcast using the unique MSI identifier.
id required | string (MsiId) [ 1 .. 255 ] characters Example: 289ee192-fdf5-4070-befc-3bf7291c1386 unique msi identifier |
{- "id": "289ee192-fdf5-4070-befc-3bf7291c1386",
- "broadcast": {
- "sarArea": {
- "lat": -34.5,
- "lon": 145.44,
- "radiusNm": 150
}, - "priority": "SAFETY"
}, - "createdTime": "2022-04-23T10:25:43.511Z",
- "startTime": "2022-04-23T10:30:43.511Z",
- "endTime": "2022-04-24T10:25:43.511Z",
- "sentTime": "2022-04-23T10:26:40s.511Z",
- "cancellingTime": "2022-04-23T10:26:40s.511Z",
- "cancelledTime": "2022-04-24T13:28:43.511Z",
- "activeTime": "2022-04-24T13:29:47.511Z",
- "finishedTime": "2022-04-24T13:45:50.511Z",
- "errorTime": "2022-04-24T13:48:50.511Z",
- "payload": "a message to be broadcast",
- "status": "ACTIVE",
- "statusMessage": "string",
- "echo": false,
- "repetition": {
- "number": "ONCE",
- "intervalHours": 1
}, - "readAcksEnabled": false,
- "receiveAcksEnabled": false
}
Requests that an existing unsent MSI be sent. If the MSI has already been sent or the MSI has been cancelled then nothing occurs (this method is idempotent).
id required | string (MsiId) [ 1 .. 255 ] characters Example: 289ee192-fdf5-4070-befc-3bf7291c1386 unique msi identifier |
{- "errorMessage": "an error occurred",
- "errorType": "SomethingWentWrongException"
}
This is a logical delete of a broadcast in that it prevents future broadcasts happening for this msiId (be it a single or repeating broadcast). Once cancelled an MSI cannot be resent. However, the broadcast details are still available to be queried.
id required | string (MsiId) [ 1 .. 255 ] characters Example: 289ee192-fdf5-4070-befc-3bf7291c1386 unique msi identifier |
{- "errorMessage": "an error occurred",
- "errorType": "SomethingWentWrongException"
}
Returns the status of an MSI broadcast using the unique MSI identifier.
id required | string (MsiId) [ 1 .. 255 ] characters Example: 289ee192-fdf5-4070-befc-3bf7291c1386 unique msi identifier |
{- "status": "ACTIVE"
}