Message Service API
This page describes how to integrate with the Message Service on a technical level. The Foundation API Guide provides a higher level overview of what messages are.
REST resources
The resources of message service are Messages, Message Filters, and Event Sources. This section discusses those resources.
Message
Messages enable asynchronous communication between components of the Banqup platform.
An example of a message as it will be received by listeners:
{
"id": "41b86461-2c30-4cc6-8892-ea342d2e546b",
"audience": "someAudience",
"category": "myMessageCategory",
"type": "typeInCategory",
"scope": "myScope",
"subject": "mySubject",
"resourceId": "d6a10e10-17c9-4081-9f54-8a218f00eba8",
"channel": "d6a10e10-17c9-4081-9f54-8a218f00eba8/bb23bbff-7326-462f-80bc-4a3c5d66567e",
"data": {
"paymentSuccessful": true,
"relatedDocumentId" : "bb23bbff-7326-462f-80bc-4a3c5d66567e"
}
}
Most of the fields of a message are optional and therefore only available if set by the sender. Refer to the documentation about Sending a message for more information about the fields. The messages sent by the different Banqup's services are in their respective API specifications.
Message Filter
Message Filters are applied before a message is delivered to a message listener. In other words, a Message Filter limits what messages are delivered to a message listener. Message senders, as well as message listeners, can register Message Filters.
Senders will usually configure Message Filters for security reasons. For example, "this message must only be published to subjects who hold a certain permission". To configure such a Message Filter, the sender will configure a Message Authorizer. A Message Authorizer returns Message Filters when called. For more information, refer to the guide on message authorizers.
Message listeners will usually configure Message Filters because they only have a limited interest in messages of a certain category.
For example, "only deliver messages if they are of category myCategory
and of type DocumentCreated
" .
These Message Filters are configured the moment a message listener registers itself as a listener.
Message Filter set by sender (Message Authorizer)
Message Filters can be defined on any of the field of a message.
Example - user/permission filter
This is the most common Message Filter used by senders:
{
"permissionFilterList": [
{
"type": "PERMISSION",
"subject": "ba2c8c09-3e43-4650-94dd-a80e0257b201"
}
]
}
The above permission filter, when applied, will only allow for messages to be received by message listeners for whom a specific permission exists.
That permission is the combination of the subjectId that was used to register the message listener, i.e. ba2c8c09-3e43-4650-94dd-a80e0257b201, the scope
specified on the message that is to be sent, and the resource
specified in the message.
Therefore this filter only works if the message sender sends messages that have the fields scope
and resource
set.
For more information on permissions, see the guide on permissions.
The subjectId of a message listener will be read from the oauth token that is passed to Plugin Service when a message listener is registered.
If the message sender has a permission filter configured, such as the one above, this subjectId will be used to filter messages before they are sent to the receiver.
In this case, because the permission filter checks is a permission, which is the 3-tuple (<subjectId>,<resourceId>,<scope>)
, all messages that are sent, must have the fields resourceId
and scope
defined in order for the permission filter to do its work.
An example of a message that will be permitted by the above Message Filter, assuming the subject's permissions are configured as described:
{
"messageId": "41b86461-2c30-4cc6-8892-ea342d2e546b",
"category" : "myCategory",
"resourceId": "3716a9f4-0a36-4a51-a784-b6cfe466a51e",
"scope": "904e1f90-7cd8-4dfe-bd10-34ed8f81fb81",
"data": {
"documentId": "bb23bbff-7326-462f-80bc-4a3c5d66567e"
}
}
The message in the above example will only be sent to message listeners that were registered with a subjectId for which the permission 3-tuple (ba2c8c09-3e43-4650-94dd-a80e0257b201,3716a9f4-0a36-4a51-a784-b6cfe466a51e,904e1f90-7cd8-4dfe-bd10-34ed8f81fb81)
exists in the specified UMA-audience.
Because these this Message Filters commonly occurs, Message Service has an available endpoint that will return this Message Filter when called.
Example - subject filter
Another common Message Filter is a subject filter:
{
"permissionFilterList": [
{
"type": "SUBJECT",
"subject": "mySubjectId"
}
]
}
This Message Filter, when applied, will only allow for messages to be received by message listeners that were registered by subjects whose subjectId is equal to mySubjectId
.
The subjectId of a message listener will be read from the oauth token that is passed to Plugin Service when a message listener is registered.
An example. Assuming the listener's subjectId is ba2c8c09-3e43-4650-94dd-a80e0257b201
.
Let's also assume that a message sender has configured the following Message Filter:
{
"permissionFilterList": [
{
"type": "SUBJECT",
"subject": "ba2c8c09-3e43-4650-94dd-a80e0257b201"
}
]
}
When the message sender sends the following message, only message listeners that were registered by the subject with id ba2c8c09-3e43-4650-94dd-a80e0257b201
will receive it:
{
"messageId": "41b86461-2c30-4cc6-8892-ea342d2e546b",
"category": "myCategory",
"subject": "ba2c8c09-3e43-4650-94dd-a80e0257b201",
"data": {
"documentId": "bb23bbff-7326-462f-80bc-4a3c5d66567e"
}
}
Because these this Message Filters commonly occurs, Message Service has an available endpoint that will return this Message Filter when called.
Event Sources
Event sources work as described in Server Sent Events (SSE), see MDN docs for more information. An event source has a set of subscriptions, see below. Calling the receive events endpoint of an event source opens an SSE stream which will deliver the desired messages as SSE-events. A typical usecase for event sources is a frontend web/mobile application that wants to update what it displays as soon as possible with little overhead.
Contrary to regular REST delivery, the events of event sources have a strict order.
As a consequence, event sources support the Last-EventID
header.
This header will let the event source replay messages in case the receiver missed any.
The number of messages that can be replayed is limited.
If a Last-EventID
is submitted that the event source does not know, or if the ID is too old, the event source will return a HTTP 404 status code.
To create a new event source, see the documentation on the create event source endpoint.
Subscriptions
Subscriptions determine which events will be delivered when someone calls the receive events endpoint of the event source they belong to. In order to do so, each subscription has a set of Message Filters. All Message Filters of a single subscription are combined with boolean AND-logic. Event sources will deliver messages of all subscriptions. In other words, subscriptions are combined with boolean OR-logic. In typical use cases, a subscription will filter on a message category and/or type first, and then on a channel.
Example: An application that wants to subscribe to events for messages of type myType
, category myCategory
in channel myChannel
, will register the following subscription:
{
"subscriptions": [
{
"filters": [
{
"type": "CATEGORY",
"test": [
"myCategory"
]
},
{
"type": "TYPE",
"test": [
"myType"
]
},
{
"type": "CHANNEL",
"test": [
"myChannel"
]
}
]
}
}
Example: If that same application wants to also receive events for message of type myOtherType
, category myOtherCategory
in channel myOtherchannel
, it can create a second subscription in the same request as follows:
{
"subscriptions": [
{
"filters": [
{
"type": "CATEGORY",
"test": [
"myCategory"
]
},
{
"type": "TYPE",
"test": [
"myType"
]
},
{
"type": "CHANNEL",
"test": [
"myChannel"
]
}
]
},
{
"filters": [
{
"type": "CATEGORY",
"test": [
"myOtherCategory"
]
},
{
"type": "TYPE",
"test": [
"myOtherType"
]
},
{
"type": "CHANNEL",
"test": [
"myOtherChannel"
]
}
]
}
}
Message Authorizer
Please refer to the guide on message authorizers for more information.
Listening to Messages
This section shows how an application can receive messages that are sent on the Banqup Platform. Roughly speaking, that will require the following steps:
- Create an endpoint that the Message Service can deliver messages to.
- Register the application as a Plugin of the Message Listener Plugin Interface.
- (Optional) configure your Plugin with Message Filters.
Registering a Message Listener
Check out the recipe Set Up A Message Listener to learn how to register a message listener.
Filtering messages
Message listeners may request to not receive all messages of a certain category. This type of receiver side filtering can be configured when an application registers itself with the Plugin Service as a listener. Consequently, it can also be updated at any point in time by calling the Plugin Service API.
For message listeners, the most useful filters are category
and type
.
One additional filter channel
can be interesting in specific use cases as well.
A channel is a string that the sender can use to relate the message to some other object.
Channel filters can filter messages that start with a specific value, so channels are often hierarchical.
For a DocumentUpdated
event for example, the channel value is the spaceId followed by the document's id.
This allows listeners to filter messages related to a specific space or to a specific document.
A few examples of how Message Filters may be used follow.
Example: an application with the following Message Filter would only receive messages of category myCategory
and myOtherCategory
.
It therefore registers itself with the following Message Filter:
{
"type": "CATEGORY",
"test": [
"myCategory",
"myOtherCategory"
]
}
Example: an application that wants to register itself as a message listener with the Plugin Service would then submit a request body like:
{
"data": {
"basePath": "https://example.com/my/callback/url",
"filters": [
{
"type": "CATEGORY",
"test": [
"myCategory"
]
}
]
}
}
Example: an application with the the following filter will only receive messages of type myType
:
{
"type": "TYPE",
"test": [
"myType"
]
}
Example: an application that wants to register itself as a message listener with the Plugin Service would then submit a request body like:
{
"data": {
"basePath": "https://example.com/my/callback/url",
"filters": [
{
"type": "TYPE",
"test" : [
"myType"
]
}
]
}
}
Multiple filters can also be configured at the same time. At this time, these filters are applied with boolean AND logic exclusively.
Example: An application that only wants to receive messages of type myType
if they originate from category myCategory
, would register with the Plugin Service with the following request body:
{
"data": {
"basePath": "https://example.com/my/callback/url",
"filters": [
{
"type": "CATEGORY",
"test": [
"myCategory"
]
},
{
"type" : "TYPE",
"test": [
"myType"
]
}
]
}
}
Example: Likewise, an application that wants to receive messages of type myType
, category myCategory
in channel myChannel
, would register with the Plugin Service with the following request body:
{
"data": {
"basePath": "https://example.com/my/callback/url",
"filters": [
{
"type": "CATEGORY",
"test": [
"myCategory"
]
},
{
"type" : "TYPE",
"test": [
"myType"
]
},
{
"type": "CHANNEL",
"test": [
"myChannel"
]
}
]
}
}
Ordered vs unordered message delivery
Messages can be delivered in any order, or in the exact order the message service received requests to send them. The former is done exclusively by REST endpoints. The latter is done exclusively by Google Cloud PubSub.
Regular (unordered) delivery / REST
To register a listener that receives messages from the category myCategory
, register a new plugin of the message listener plugin interface in the Plugin Service with the following request body:
{
"data" : {
"basePath": "https://example.com/messageListener",
"filters": [
{
"type": "CATEGORY",
"test": [
"myCategory"
]
}
]
}
}
When a message is sent for myCategory
, the Message Service will perform a POST on https://example.com/messageListener/messages with the content of the message it wants to deliver.
Note the /messages subpath.
The delivery is considered successful when the REST endpoint the message is delivered to returns a HTTP 2xx status code.
In the above example, the endpoint https://example.com/messageListener/messages will need to implement an endpoint that adheres to the message listener OpenAPI spec, available here.
Retries
Unordered deliveries are retried for up to 48 hours.
During development, services like ngrok or webhook.site may be used. Since these endpoints are temporary in nature, listeners that return error response codes upon delivery will no longer be retried after 2 hours instead of the usual 48 hours. Furthermore ngrok and webhook.site listeners are removed after 2 hours of unsuccessful deliveries alltogether. Users will not receive a notification of this removal.
Ordered delivery / PubSub
A regular delivery is considered successful when the destination Google PubSub Topic accepts the delivery (HTTP 2xx status code).
Ordered deliveries are never retried.
If they fail, the message listener is de-registered immediately.
If the message listener configured an ownerEmail
when they registered their message listener, the owner will receive an e-mail notifying them about removal.
Therefore the request body of an message listener with ordered delivery that wants to be notified when it is automatically removed will look like:
{
"data": {
"ownerEmail": "owneremail@example.com",
"topicName": "projects/my-google-cloud-project/topics/topic-name",
"filters": [
{
"type": "CATEGORY",
"test": [
"myCategory"
]
}
]
}
}
Sending messages
This REST call sends notifications related to events performed on the platform to other listening components that are registered with one or more plugin interfaces.
Request
To send a message, perform POST on /core/message/v2/messages:send. The request body of this request must be a message and will be sent as such to message listeners.
Request body (application/json):
{
"audience": "someAudience",
"category": "myMessageCategory",
"type": "typeInCategory",
"scope": "document_read",
"subject": "ba2c8c09-3e43-4650-94dd-a80e0257b201",
"resourceId": "d6a10e10-17c9-4081-9f54-8a218f00eba8",
"channel" : "d6a10e10-17c9-4081-9f54-8a218f00eba8/bb23bbff-7326-462f-80bc-4a3c5d66567e",
"orderGroup": "myOrderGroup",
"data": {
"paymentSuccessful": true,
"relatedDocumentId": "bb23bbff-7326-462f-80bc-4a3c5d66567e"
}
}
Refer to the documentation about Sending a message for more information about the meaning of these fields.
Response A successful 202 response returns the message ID, confirming that the message has been sent and will be sent to all subscribed message listeners.
{
"id" : "41b86461-2c30-4cc6-8892-ea342d2e546b"
}
This ID can be used as a correlation ID. Applications can safely use it to determine whether or not a message has already been received.
Security
In order to send a message, the sender must hold the permission (<subject>,<resource>,<scope>)
= (<sender subjectId>, <name of value of the category propery in the message >, message_category_send)
.
Once you hold this permission, and without any further steps, any message that is sent by the sender will be delivered to any application that has registered itself as a message listener.
Of course, this assumes that the Message Filters are configured correctly.
To limit who can receive messages of a certain category, implement the message authorizer plugin interface. They can then apply filters at will, see also Message Filter set by sender (Message Authorizer).
Right before a message is published to a listener, any Message Filters created by the Message Authorizer are applied. If those Message Filters do not block the message, the receiver will receive it. Changes to the authorization of a listener propagate through the system after a brief delay (<1min).
Authentication
- OAuth 2.0: message
Security Scheme Type: | oauth2 |
---|---|
OAuth Flow (authorizationCode): | Authorization URL: https://api.btx.fr.banqup.com/v1/oauth20/authorization Scopes: |