diff --git a/src/packages/com_mokoog/api/src/Controller/TagsController.php b/src/packages/com_mokoog/api/src/Controller/TagsController.php
new file mode 100644
index 0000000..e0d895f
--- /dev/null
+++ b/src/packages/com_mokoog/api/src/Controller/TagsController.php
@@ -0,0 +1,68 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+namespace Joomla\Component\MokoOG\Api\Controller;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Factory;
+use Joomla\CMS\MVC\Controller\ApiController;
+
+class TagsController extends ApiController
+{
+ /**
+ * The content type for JSON:API output.
+ *
+ * @var string
+ */
+ protected $contentType = 'mokoogtags';
+
+ /**
+ * The default view for the API.
+ *
+ * @var string
+ */
+ protected $default_view = 'tags';
+
+ /**
+ * Lookup an OG tag by content_type and content_id.
+ *
+ * GET /api/index.php/v1/mokoog/lookup/:content_type/:content_id
+ *
+ * @return static
+ */
+ public function lookup(): static
+ {
+ $contentType = $this->input->getString('content_type', '');
+ $contentId = $this->input->getInt('content_id', 0);
+
+ if (empty($contentType) || $contentId <= 0) {
+ throw new \RuntimeException('content_type and content_id are required', 400);
+ }
+
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('id'))
+ ->from($db->quoteName('#__mokoog_tags'))
+ ->where($db->quoteName('content_type') . ' = ' . $db->quote($contentType))
+ ->where($db->quoteName('content_id') . ' = ' . $contentId);
+
+ $db->setQuery($query);
+ $id = $db->loadResult();
+
+ if (!$id) {
+ throw new \RuntimeException('OG tag not found for ' . $contentType . ':' . $contentId, 404);
+ }
+
+ $this->input->set('id', $id);
+
+ return $this->displayItem();
+ }
+}
diff --git a/src/packages/com_mokoog/api/src/View/Tags/JsonapiView.php b/src/packages/com_mokoog/api/src/View/Tags/JsonapiView.php
new file mode 100644
index 0000000..c103df2
--- /dev/null
+++ b/src/packages/com_mokoog/api/src/View/Tags/JsonapiView.php
@@ -0,0 +1,66 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+namespace Joomla\Component\MokoOG\Api\View\Tags;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
+
+class JsonapiView extends BaseApiView
+{
+ /**
+ * The fields to render in the API response.
+ *
+ * Whitelist of fields from #__mokoog_tags that are safe to expose.
+ *
+ * @var array
+ */
+ protected $fieldsToRenderItem = [
+ 'id',
+ 'content_type',
+ 'content_id',
+ 'og_title',
+ 'og_description',
+ 'og_image',
+ 'og_type',
+ 'seo_title',
+ 'meta_description',
+ 'robots',
+ 'canonical_url',
+ 'language',
+ 'published',
+ 'created',
+ 'modified',
+ ];
+
+ /**
+ * The fields to render in list responses.
+ *
+ * @var array
+ */
+ protected $fieldsToRenderList = [
+ 'id',
+ 'content_type',
+ 'content_id',
+ 'og_title',
+ 'og_description',
+ 'og_image',
+ 'og_type',
+ 'seo_title',
+ 'meta_description',
+ 'robots',
+ 'canonical_url',
+ 'language',
+ 'published',
+ 'created',
+ 'modified',
+ ];
+}
diff --git a/src/packages/com_mokoog/mokoog.xml b/src/packages/com_mokoog/mokoog.xml
index aa2ad47..f5baeb3 100644
--- a/src/packages/com_mokoog/mokoog.xml
+++ b/src/packages/com_mokoog/mokoog.xml
@@ -69,4 +69,10 @@
+
+
+
+ src
+
+
diff --git a/src/packages/com_mokoog/src/Model/TagModel.php b/src/packages/com_mokoog/src/Model/TagModel.php
new file mode 100644
index 0000000..62d14b9
--- /dev/null
+++ b/src/packages/com_mokoog/src/Model/TagModel.php
@@ -0,0 +1,68 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+namespace Joomla\Component\MokoOG\Administrator\Model;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Factory;
+use Joomla\CMS\MVC\Model\AdminModel;
+
+class TagModel extends AdminModel
+{
+ /**
+ * Get the form for the item.
+ *
+ * @param array $data Form data
+ * @param bool $loadData Load data from state
+ *
+ * @return \Joomla\CMS\Form\Form|false
+ */
+ public function getForm($data = [], $loadData = true)
+ {
+ $form = $this->loadForm(
+ 'com_mokoog.tag',
+ 'tag',
+ ['control' => 'jform', 'load_data' => $loadData]
+ );
+
+ return $form ?: false;
+ }
+
+ /**
+ * Load the form data.
+ *
+ * @return object
+ */
+ protected function loadFormData(): object
+ {
+ $data = Factory::getApplication()->getUserState('com_mokoog.edit.tag.data', []);
+
+ if (empty($data)) {
+ $data = $this->getItem();
+ }
+
+ return $data;
+ }
+
+ /**
+ * Get the table class name.
+ *
+ * @param string $name Table name
+ * @param string $prefix Table prefix
+ * @param array $options Table options
+ *
+ * @return \Joomla\CMS\Table\Table
+ */
+ public function getTable($name = 'Tag', $prefix = 'Administrator', $options = [])
+ {
+ return parent::getTable($name, $prefix, $options);
+ }
+}
diff --git a/src/packages/plg_webservices_mokoog/language/en-GB/plg_webservices_mokoog.ini b/src/packages/plg_webservices_mokoog/language/en-GB/plg_webservices_mokoog.ini
new file mode 100644
index 0000000..e397923
--- /dev/null
+++ b/src/packages/plg_webservices_mokoog/language/en-GB/plg_webservices_mokoog.ini
@@ -0,0 +1,5 @@
+; MokoOpenGraph - Web Services Plugin Language File
+; Copyright (C) 2026 Moko Consulting. All rights reserved.
+; License: GPL-3.0-or-later
+
+PLG_WEBSERVICES_MOKOOG="Web Services - MokoOpenGraph"
diff --git a/src/packages/plg_webservices_mokoog/language/en-GB/plg_webservices_mokoog.sys.ini b/src/packages/plg_webservices_mokoog/language/en-GB/plg_webservices_mokoog.sys.ini
new file mode 100644
index 0000000..903c909
--- /dev/null
+++ b/src/packages/plg_webservices_mokoog/language/en-GB/plg_webservices_mokoog.sys.ini
@@ -0,0 +1,6 @@
+; MokoOpenGraph - Web Services Plugin System Language File
+; Copyright (C) 2026 Moko Consulting. All rights reserved.
+; License: GPL-3.0-or-later
+
+PLG_WEBSERVICES_MOKOOG="Web Services - MokoOpenGraph"
+PLG_WEBSERVICES_MOKOOG_DESCRIPTION="Exposes MokoOpenGraph OG tag data via Joomla's REST API at /api/index.php/v1/mokoog/tags."
diff --git a/src/packages/plg_webservices_mokoog/language/en-US/plg_webservices_mokoog.ini b/src/packages/plg_webservices_mokoog/language/en-US/plg_webservices_mokoog.ini
new file mode 100644
index 0000000..e397923
--- /dev/null
+++ b/src/packages/plg_webservices_mokoog/language/en-US/plg_webservices_mokoog.ini
@@ -0,0 +1,5 @@
+; MokoOpenGraph - Web Services Plugin Language File
+; Copyright (C) 2026 Moko Consulting. All rights reserved.
+; License: GPL-3.0-or-later
+
+PLG_WEBSERVICES_MOKOOG="Web Services - MokoOpenGraph"
diff --git a/src/packages/plg_webservices_mokoog/language/en-US/plg_webservices_mokoog.sys.ini b/src/packages/plg_webservices_mokoog/language/en-US/plg_webservices_mokoog.sys.ini
new file mode 100644
index 0000000..903c909
--- /dev/null
+++ b/src/packages/plg_webservices_mokoog/language/en-US/plg_webservices_mokoog.sys.ini
@@ -0,0 +1,6 @@
+; MokoOpenGraph - Web Services Plugin System Language File
+; Copyright (C) 2026 Moko Consulting. All rights reserved.
+; License: GPL-3.0-or-later
+
+PLG_WEBSERVICES_MOKOOG="Web Services - MokoOpenGraph"
+PLG_WEBSERVICES_MOKOOG_DESCRIPTION="Exposes MokoOpenGraph OG tag data via Joomla's REST API at /api/index.php/v1/mokoog/tags."
diff --git a/src/packages/plg_webservices_mokoog/mokoog.php b/src/packages/plg_webservices_mokoog/mokoog.php
new file mode 100644
index 0000000..899de00
--- /dev/null
+++ b/src/packages/plg_webservices_mokoog/mokoog.php
@@ -0,0 +1,19 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ *
+ * Legacy entry point — not executed under DI container.
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Plugin\CMSPlugin;
+
+class PlgWebservicesMokoog extends CMSPlugin
+{
+}
diff --git a/src/packages/plg_webservices_mokoog/mokoog.xml b/src/packages/plg_webservices_mokoog/mokoog.xml
new file mode 100644
index 0000000..5f862ab
--- /dev/null
+++ b/src/packages/plg_webservices_mokoog/mokoog.xml
@@ -0,0 +1,33 @@
+
+
+
+ Web Services - MokoOpenGraph
+ 01.00.00
+ 2026-05-23
+ Moko Consulting
+ hello@mokoconsulting.tech
+ https://mokoconsulting.tech
+ Copyright (C) 2026 Moko Consulting. All rights reserved.
+ GPL-3.0-or-later
+ PLG_WEBSERVICES_MOKOOG_DESCRIPTION
+
+ Joomla\Plugin\WebServices\MokoOG
+
+
+ mokoog.php
+ src
+ services
+ language
+
+
+
+ language/en-GB/plg_webservices_mokoog.ini
+ language/en-GB/plg_webservices_mokoog.sys.ini
+
+
diff --git a/src/packages/plg_webservices_mokoog/services/provider.php b/src/packages/plg_webservices_mokoog/services/provider.php
new file mode 100644
index 0000000..2aa760d
--- /dev/null
+++ b/src/packages/plg_webservices_mokoog/services/provider.php
@@ -0,0 +1,44 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Extension\PluginInterface;
+use Joomla\CMS\Factory;
+use Joomla\CMS\Plugin\PluginHelper;
+use Joomla\DI\Container;
+use Joomla\DI\ServiceProviderInterface;
+use Joomla\Event\DispatcherInterface;
+use Joomla\Plugin\WebServices\MokoOG\Extension\MokoOGWebServices;
+
+return new class () implements ServiceProviderInterface {
+ /**
+ * Register the service provider.
+ *
+ * @param Container $container The DI container
+ *
+ * @return void
+ */
+ public function register(Container $container): void
+ {
+ $container->set(
+ PluginInterface::class,
+ function (Container $container) {
+ $plugin = new MokoOGWebServices(
+ $container->get(DispatcherInterface::class),
+ (array) PluginHelper::getPlugin('webservices', 'mokoog')
+ );
+ $plugin->setApplication(Factory::getApplication());
+
+ return $plugin;
+ }
+ );
+ }
+};
diff --git a/src/packages/plg_webservices_mokoog/src/Extension/MokoOGWebServices.php b/src/packages/plg_webservices_mokoog/src/Extension/MokoOGWebServices.php
new file mode 100644
index 0000000..887e3b8
--- /dev/null
+++ b/src/packages/plg_webservices_mokoog/src/Extension/MokoOGWebServices.php
@@ -0,0 +1,81 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+namespace Joomla\Plugin\WebServices\MokoOG\Extension;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Plugin\CMSPlugin;
+use Joomla\CMS\Router\ApiRouter;
+use Joomla\Event\Event;
+use Joomla\Event\SubscriberInterface;
+use Joomla\Router\Route;
+
+final class MokoOGWebServices extends CMSPlugin implements SubscriberInterface
+{
+ /**
+ * @var bool
+ */
+ protected $autoloadLanguage = true;
+
+ /**
+ * Returns the events this plugin subscribes to.
+ *
+ * @return array
+ */
+ public static function getSubscribedEvents(): array
+ {
+ return [
+ 'onBeforeApiRoute' => 'onBeforeApiRoute',
+ ];
+ }
+
+ /**
+ * Register API routes for MokoOpenGraph.
+ *
+ * Endpoints:
+ * GET /api/index.php/v1/mokoog/tags - List all OG tags
+ * GET /api/index.php/v1/mokoog/tags/:id - Get single OG tag
+ * POST /api/index.php/v1/mokoog/tags - Create OG tag
+ * PATCH /api/index.php/v1/mokoog/tags/:id - Update OG tag
+ * DELETE /api/index.php/v1/mokoog/tags/:id - Delete OG tag
+ *
+ * @param Event $event The event object
+ *
+ * @return void
+ */
+ public function onBeforeApiRoute(Event $event): void
+ {
+ [$router] = array_values($event->getArguments());
+
+ $defaults = [
+ 'component' => 'com_mokoog',
+ 'public' => false,
+ ];
+
+ // CRUD routes for OG tags
+ $router->createCRUDRoutes(
+ 'v1/mokoog/tags',
+ 'tags',
+ $defaults
+ );
+
+ // GET by content type + content ID (lookup endpoint)
+ $router->addRoute(
+ new Route(
+ ['GET'],
+ 'v1/mokoog/lookup/:content_type/:content_id',
+ 'tags.lookup',
+ ['content_type' => '[a-z_.]+', 'content_id' => '(\d+)'],
+ $defaults
+ )
+ );
+ }
+}
diff --git a/src/pkg_mokoog.xml b/src/pkg_mokoog.xml
index 355f556..783c779 100644
--- a/src/pkg_mokoog.xml
+++ b/src/pkg_mokoog.xml
@@ -23,6 +23,7 @@
com_mokoog.zip
plg_system_mokoog.zip
plg_content_mokoog.zip
+ plg_webservices_mokoog.zip
diff --git a/src/script.php b/src/script.php
index c5a505f..0d173ba 100644
--- a/src/script.php
+++ b/src/script.php
@@ -73,6 +73,17 @@ class Pkg_MokoOGInstallerScript
$db->setQuery($query);
$db->execute();
+
+ // Enable the webservices plugin automatically
+ $query = $db->getQuery(true)
+ ->update($db->quoteName('#__extensions'))
+ ->set($db->quoteName('enabled') . ' = 1')
+ ->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
+ ->where($db->quoteName('folder') . ' = ' . $db->quote('webservices'))
+ ->where($db->quoteName('element') . ' = ' . $db->quote('mokoog'));
+
+ $db->setQuery($query);
+ $db->execute();
}
}
}