diff --git a/docs/apis/plugintypes/sms/index.md b/docs/apis/plugintypes/sms/index.md
new file mode 100644
index 0000000000..62869357d4
--- /dev/null
+++ b/docs/apis/plugintypes/sms/index.md
@@ -0,0 +1,145 @@
+---
+title: SMS gateway
+tags:
+ - SMS
+ - Gateway
+ - Notification
+---
+
+
+
+SMS gateway plugins allow you to create SMS gateway providers.
+Providers are an interface between the [SMS API](/apis/subsystems/sms/index.md) and an external SMS provider (for example Amazon Web Services).
+This allows for the sending of SMS notifications to users from your Moodle instance.
+
+:::info Example
+
+You can set up Multi-Factor Authentication (MFA)) in Moodle and choose 'AWS' as your SMS gateway provider.
+
+This enables users to receive SMS notifications as part of the authentication process.
+
+:::
+
+## File structure
+
+SMS gateway plugins are located in the `/sms/gateway` directory. A plugin should not include any custom files outside its own plugin folder.
+
+Each plugin is placed in a separate subdirectory and consists of a number of mandatory files and any other files the developer is going to use. See the [common plugin files](/apis/commonfiles/index.mdx) documentation for other files which may be useful in your plugin.
+
+
+ The directory layout for the `smsgateway` plugin.
+
+```console
+sms/gateway/example
+├── classes
+│ ├── gateway.php
+│ ├── hook_listener.php
+│ └── privacy
+│ └── provider.php
+├── db
+│ └── hooks.php
+├── lang
+│ └── en
+│ └── smsgateway_example.php
+├── settings.php
+└── version.php
+```
+
+
+
+## Key files
+
+There are a number of key files within the SMS gateway plugin which will need to be configured for correct functionality.
+
+- `gateway.php`
+- `hook_listener.php`
+
+### gateway.php
+
+Each plugin must create a class called `gateway` which extends the `\core_sms\gateway` class.
+The SMS API will use the extended methods from this class.
+
+```php title="Implementing the base SMS gateway"
+get_gateway_service($config);
+ $recipientnumber = manager::format_number(
+ phonenumber: $message->recipientnumber,
+ countrycode: isset($config->countrycode) ?? null,
+ );
+
+ $status = call_user_func(
+ [$class, 'send_sms_message'],
+ $message->content,
+ $recipientnumber,
+ $config,
+ );
+
+ return $message->with(
+ status: $status,
+ );
+ }
+
+ private function get_gateway_service(\stdClass $config): string {
+ return match ($config->gateway) {
+ 'aws_sns' => aws_sns::class,
+ default => throw new moodle_exception("Unknown Message Handler {$config->gateway}"),
+ };
+ }
+
+ #[\Override]
+ public function get_send_priority(message $message): int {
+ return 50;
+ }
+}
+
+```
+
+### hook_listener.php
+
+[Hooks](/apis/core/hooks/index.md) can be dispatched from the SMS API which the plugin can then listened to.
+It is necessary for plugins developers to assess these hooks and implement accordingly.
+
+#### after_sms_gateway_form_hook
+
+This hook will allow plugins to add required form fields to assist users in configuring their SMS gateway.
+
+```php title="Listener method for after_sms_gateway_form_hook"
+public static function set_form_definition_for_aws_sms_gateway(after_sms_gateway_form_hook $hook): void {
+ if ($hook->plugin !== 'smsgateway_example') {
+ return;
+ }
+
+ $gateways = [
+ 'smsgateway_example' => get_string('list', 'smsgateway_example'),
+ ];
+ $mform->addElement(
+ 'select',
+ 'gateway',
+ get_string('gateway', 'smsgateway_example'),
+ $gateways,
+ );
+}
+
+```
+
+:::info
+
+For an example of a production plugin example, see the [AWS SMS Gateway plugin](https://github.com/moodle/moodle/tree/main/sms/gateway/aws).
+
+:::
diff --git a/docs/apis/subsystems/sms/index.md b/docs/apis/subsystems/sms/index.md
index c8680cbedd..7537c6edeb 100644
--- a/docs/apis/subsystems/sms/index.md
+++ b/docs/apis/subsystems/sms/index.md
@@ -1,10 +1,24 @@
---
title: SMS API
+tags:
+ - SMS
---
-The SMS API lets you send SMS messages using configured gateways, fetch messages that were previously sent, and check on their status.
+The SMS API allows developers to implement SMS-related features into their plugins.
+The subsystem contains an SMS Manager class `\core_sms\manager` which facilitates the actions performed by the API.
+
+Some of the actions made possible are:
+
+- Sending messages
+- Fetching messages
+- Checking the status of a message
+- Getting SMS gateways.
+
+Currently, the design of the SMS API features the following plugin types:
+
+- [SMS gateway](/apis/plugintypes/sms/index.md)
## Sending an SMS
@@ -25,12 +39,24 @@ $message = \core\di::get(\core_sms\manager::class)
:::info Message lengths
-A single SMS sent by the API may consist of up to 480 UTF-8 characters. It is up to the message _gateway_ plugin to determine how this message is sent to the recipient.
+A single SMS sent by the API may consist of up to 480 UTF-8 characters. It is up to the message _gateway plugin_ to determine how this message is sent to the recipient.
Any message longer than the maximum length will be immediately rejected.
:::
+### Parameter consideration while sending messages
+
+When sending a message it's important to add the correct `component` (for example `tool_mfa`) and `messagetype` (for example `mfa code`) for record keeping purposes.
+
+One component can have many different types of messages and those types should be clearly mentioned while sending the messages so that they are clear in reporting and other locations.
+
+:::info
+
+In future reporting will be available for messages status. See MDL-80963 for further information
+
+:::
+
### Sending messages containing sensitive information
When sending a message containing something like a 2FA login token, you should make use of the `issensitive` flag.
@@ -39,9 +65,25 @@ Passing this flag prevents the SMS subsystem from storing the content of the mes
The `send()` method return an instance of `\core_sms\message` which can be used to check on the message status.
+:::warning
+
+Messages containing sensitive information cannot be sent asynchronously.
+
+Sensitive content is not persisted to the database and is therefore not available in a separate PHP process.
+
+:::
+
+:::info Availability of asynchronous message handling
+
+The ability to send messages asynchronously has not yet been implemented. The parameter is included for future compatibility.
+
+See MDL-81015 for more information on this feature.
+
+:::
+
## Fetching messages
-Every sent message is stored in the database for subsequent reporting, and to check statuses.
+Every sent message is stored in the database to support status checks, and for subsequent reporting.
Messages can be fetched from the database by calling the `\core_sms\manager::get_message()` and `\core_sms\manager::get_messages()` methods and supplying a filter.
@@ -122,3 +164,47 @@ graph TD
GQ --> |Gateway failed to send the message| GF
end
```
+
+## Getting SMS gateways
+
+[SMS gateways](/apis/plugintypes/sms/index.md) are plugins that provide a way to interface with external SMS providers.
+Once a gateway is configured, any component implementing the SMS API can get a list of gateways.
+
+```php title="Getting the list of enabled gateways"
+$manager = \core\di::get(\core_sms\manager::class);
+$gatewayrecords = $manager->get_gateway_records();
+
+// It is also possible to filter the request.
+$gatewayrecords = $manager->get_gateway_records(['id' => $id]);
+
+// To get all the enabled gateway instances.
+$gatewayrecords = $manager->get_enabled_gateway_instances();
+```
+
+## Important hooks
+
+The SMS API dispatches some [hooks](/apis/core/hooks/index.md) which should be considered when implemented by a plugin/component.
+
+- before_gateway_deleted
+- before_gateway_disabled
+
+Before deleting or disabling an [SMS gateways](/apis/plugintypes/sms/index.md), these two hooks are dispatched from the SMS API.
+This allows components that are actively using that gateway to stop the action, or do necessary cleanup.
+Listening to these hooks is crucial to avoid data loss or accidental deletion when disabling an active gateway.
+
+```php title="Implement the hooks to check for usage before deletion or deactivation"
+
+public static function check_gateway_usage_in_example_plugin(
+ before_gateway_deleted|before_gateway_disabled $hook,
+): void {
+ try {
+ $smsgatewayid = (int)get_config('example_plugin', 'smsgateway');
+ if ($smsgatewayid && $smsgatewayid === (int)$hook->gateway->id) {
+ $hook->stop_propagation();
+ }
+ } catch (\dml_exception $exception) {
+ $hook->stop_propagation();
+ }
+}
+
+```
diff --git a/versioned_docs/version-4.5/apis/plugintypes/sms/index.md b/versioned_docs/version-4.5/apis/plugintypes/sms/index.md
new file mode 100644
index 0000000000..62869357d4
--- /dev/null
+++ b/versioned_docs/version-4.5/apis/plugintypes/sms/index.md
@@ -0,0 +1,145 @@
+---
+title: SMS gateway
+tags:
+ - SMS
+ - Gateway
+ - Notification
+---
+
+
+
+SMS gateway plugins allow you to create SMS gateway providers.
+Providers are an interface between the [SMS API](/apis/subsystems/sms/index.md) and an external SMS provider (for example Amazon Web Services).
+This allows for the sending of SMS notifications to users from your Moodle instance.
+
+:::info Example
+
+You can set up Multi-Factor Authentication (MFA)) in Moodle and choose 'AWS' as your SMS gateway provider.
+
+This enables users to receive SMS notifications as part of the authentication process.
+
+:::
+
+## File structure
+
+SMS gateway plugins are located in the `/sms/gateway` directory. A plugin should not include any custom files outside its own plugin folder.
+
+Each plugin is placed in a separate subdirectory and consists of a number of mandatory files and any other files the developer is going to use. See the [common plugin files](/apis/commonfiles/index.mdx) documentation for other files which may be useful in your plugin.
+
+
+ The directory layout for the `smsgateway` plugin.
+
+```console
+sms/gateway/example
+├── classes
+│ ├── gateway.php
+│ ├── hook_listener.php
+│ └── privacy
+│ └── provider.php
+├── db
+│ └── hooks.php
+├── lang
+│ └── en
+│ └── smsgateway_example.php
+├── settings.php
+└── version.php
+```
+
+
+
+## Key files
+
+There are a number of key files within the SMS gateway plugin which will need to be configured for correct functionality.
+
+- `gateway.php`
+- `hook_listener.php`
+
+### gateway.php
+
+Each plugin must create a class called `gateway` which extends the `\core_sms\gateway` class.
+The SMS API will use the extended methods from this class.
+
+```php title="Implementing the base SMS gateway"
+get_gateway_service($config);
+ $recipientnumber = manager::format_number(
+ phonenumber: $message->recipientnumber,
+ countrycode: isset($config->countrycode) ?? null,
+ );
+
+ $status = call_user_func(
+ [$class, 'send_sms_message'],
+ $message->content,
+ $recipientnumber,
+ $config,
+ );
+
+ return $message->with(
+ status: $status,
+ );
+ }
+
+ private function get_gateway_service(\stdClass $config): string {
+ return match ($config->gateway) {
+ 'aws_sns' => aws_sns::class,
+ default => throw new moodle_exception("Unknown Message Handler {$config->gateway}"),
+ };
+ }
+
+ #[\Override]
+ public function get_send_priority(message $message): int {
+ return 50;
+ }
+}
+
+```
+
+### hook_listener.php
+
+[Hooks](/apis/core/hooks/index.md) can be dispatched from the SMS API which the plugin can then listened to.
+It is necessary for plugins developers to assess these hooks and implement accordingly.
+
+#### after_sms_gateway_form_hook
+
+This hook will allow plugins to add required form fields to assist users in configuring their SMS gateway.
+
+```php title="Listener method for after_sms_gateway_form_hook"
+public static function set_form_definition_for_aws_sms_gateway(after_sms_gateway_form_hook $hook): void {
+ if ($hook->plugin !== 'smsgateway_example') {
+ return;
+ }
+
+ $gateways = [
+ 'smsgateway_example' => get_string('list', 'smsgateway_example'),
+ ];
+ $mform->addElement(
+ 'select',
+ 'gateway',
+ get_string('gateway', 'smsgateway_example'),
+ $gateways,
+ );
+}
+
+```
+
+:::info
+
+For an example of a production plugin example, see the [AWS SMS Gateway plugin](https://github.com/moodle/moodle/tree/main/sms/gateway/aws).
+
+:::
diff --git a/versioned_docs/version-4.5/apis/subsystems/sms/index.md b/versioned_docs/version-4.5/apis/subsystems/sms/index.md
index c8680cbedd..7537c6edeb 100644
--- a/versioned_docs/version-4.5/apis/subsystems/sms/index.md
+++ b/versioned_docs/version-4.5/apis/subsystems/sms/index.md
@@ -1,10 +1,24 @@
---
title: SMS API
+tags:
+ - SMS
---
-The SMS API lets you send SMS messages using configured gateways, fetch messages that were previously sent, and check on their status.
+The SMS API allows developers to implement SMS-related features into their plugins.
+The subsystem contains an SMS Manager class `\core_sms\manager` which facilitates the actions performed by the API.
+
+Some of the actions made possible are:
+
+- Sending messages
+- Fetching messages
+- Checking the status of a message
+- Getting SMS gateways.
+
+Currently, the design of the SMS API features the following plugin types:
+
+- [SMS gateway](/apis/plugintypes/sms/index.md)
## Sending an SMS
@@ -25,12 +39,24 @@ $message = \core\di::get(\core_sms\manager::class)
:::info Message lengths
-A single SMS sent by the API may consist of up to 480 UTF-8 characters. It is up to the message _gateway_ plugin to determine how this message is sent to the recipient.
+A single SMS sent by the API may consist of up to 480 UTF-8 characters. It is up to the message _gateway plugin_ to determine how this message is sent to the recipient.
Any message longer than the maximum length will be immediately rejected.
:::
+### Parameter consideration while sending messages
+
+When sending a message it's important to add the correct `component` (for example `tool_mfa`) and `messagetype` (for example `mfa code`) for record keeping purposes.
+
+One component can have many different types of messages and those types should be clearly mentioned while sending the messages so that they are clear in reporting and other locations.
+
+:::info
+
+In future reporting will be available for messages status. See MDL-80963 for further information
+
+:::
+
### Sending messages containing sensitive information
When sending a message containing something like a 2FA login token, you should make use of the `issensitive` flag.
@@ -39,9 +65,25 @@ Passing this flag prevents the SMS subsystem from storing the content of the mes
The `send()` method return an instance of `\core_sms\message` which can be used to check on the message status.
+:::warning
+
+Messages containing sensitive information cannot be sent asynchronously.
+
+Sensitive content is not persisted to the database and is therefore not available in a separate PHP process.
+
+:::
+
+:::info Availability of asynchronous message handling
+
+The ability to send messages asynchronously has not yet been implemented. The parameter is included for future compatibility.
+
+See MDL-81015 for more information on this feature.
+
+:::
+
## Fetching messages
-Every sent message is stored in the database for subsequent reporting, and to check statuses.
+Every sent message is stored in the database to support status checks, and for subsequent reporting.
Messages can be fetched from the database by calling the `\core_sms\manager::get_message()` and `\core_sms\manager::get_messages()` methods and supplying a filter.
@@ -122,3 +164,47 @@ graph TD
GQ --> |Gateway failed to send the message| GF
end
```
+
+## Getting SMS gateways
+
+[SMS gateways](/apis/plugintypes/sms/index.md) are plugins that provide a way to interface with external SMS providers.
+Once a gateway is configured, any component implementing the SMS API can get a list of gateways.
+
+```php title="Getting the list of enabled gateways"
+$manager = \core\di::get(\core_sms\manager::class);
+$gatewayrecords = $manager->get_gateway_records();
+
+// It is also possible to filter the request.
+$gatewayrecords = $manager->get_gateway_records(['id' => $id]);
+
+// To get all the enabled gateway instances.
+$gatewayrecords = $manager->get_enabled_gateway_instances();
+```
+
+## Important hooks
+
+The SMS API dispatches some [hooks](/apis/core/hooks/index.md) which should be considered when implemented by a plugin/component.
+
+- before_gateway_deleted
+- before_gateway_disabled
+
+Before deleting or disabling an [SMS gateways](/apis/plugintypes/sms/index.md), these two hooks are dispatched from the SMS API.
+This allows components that are actively using that gateway to stop the action, or do necessary cleanup.
+Listening to these hooks is crucial to avoid data loss or accidental deletion when disabling an active gateway.
+
+```php title="Implement the hooks to check for usage before deletion or deactivation"
+
+public static function check_gateway_usage_in_example_plugin(
+ before_gateway_deleted|before_gateway_disabled $hook,
+): void {
+ try {
+ $smsgatewayid = (int)get_config('example_plugin', 'smsgateway');
+ if ($smsgatewayid && $smsgatewayid === (int)$hook->gateway->id) {
+ $hook->stop_propagation();
+ }
+ } catch (\dml_exception $exception) {
+ $hook->stop_propagation();
+ }
+}
+
+```