Transform Learning with a Powerful Enterprise LMS

Learn more
Moodle

Moodle db/services.php Reference for Plugin Developers

Every key in a Moodle plugin's db/services.php, its default and where it is stored, what install and upgrade do with it, the changes that delete tokens, and the errors that trace back to the file.

Learn more about this topic with AI

Gemini opens with the prompt copied - paste it into the chat to start.

Illustration of a Moodle plugin's db/services.php file mapping external functions and services to the database

The Moodle services.php file, db/services.php in a plugin, is where Moodle learns which external functions the plugin provides and, optionally, which pre-built services bundle them. It holds two arrays: $functions, which maps each function name to its implementing class and options, and $services, which defines services an administrator can enable for an integration. Moodle copies part of it into the database when the plugin is installed or upgraded and reads the rest straight from the file on each call, and that split explains most "my change did nothing" problems.

This is a key-by-key reference with the default each key gets, where it is stored and what an upgrade does when you change or remove it. If you are writing your first function, start with our walkthrough on creating a Moodle web service function with core_external and come back here for the details. Checked against the Moodle 5.3.0 source (public/lib/upgradelib.php, public/lib/external/classes/external_api.php, public/lib/ajax/service.php, UPGRADING.md) and the Moodle developer documentation for the External API, October 2026.

File layout

<?php
// local/acmesync/db/services.php
defined('MOODLE_INTERNAL') || die();

$functions = [
    'local_acmesync_get_enrolments' => [
        'classname'    => 'local_acmesync\external\get_enrolments',
        'description'  => 'Returns enrolments changed since a timestamp.',
        'type'         => 'read',
        'ajax'         => false,
        'capabilities' => 'moodle/course:enrolreview',
    ],
];

$services = [
    'ACME sync' => [
        'functions'          => ['local_acmesync_get_enrolments'],
        'requiredcapability' => 'local/acmesync:use',
        'restrictedusers'    => 1,
        'enabled'            => 0,
        'shortname'          => 'local_acmesync',
    ],
];

Function names follow [frankenstyle_component]_[methodname], with the method usually a verb and a plural noun, such as get_enrolments. The implementing class lives in the plugin's external namespace, here local/acmesync/classes/external/get_enrolments.php, and extends \core_external\external_api (the namespaced API since Moodle 4.2, MDL-76583). The old global \external_api and related classes are deprecated in 5.3 (MDL-81225). Not run on a live site; test on staging first.

$functions keys

KeyDefaultStored inWhat it does
classnamerequiredexternal_functionsThe class that implements the function.
methodnameexecuteexternal_functionsThe method to call. Moodle also looks for {methodname}_parameters, {methodname}_returns and, optionally, {methodname}_is_deprecated. Leave it out for namespaced classes.
classpathnullexternal_functionsLegacy: a file to require_once when the class is not autoloadable. Without it Moodle falls back to the component's externallib.php. Not needed for classes under classes/external/.
descriptionnoneread from the fileHuman-readable text shown in the site's API documentation.
typenoneread from the fileread or write. It declares intent; it does not restrict access.
capabilitiesempty stringexternal_functionsComma-separated list shown to administrators. Advisory only: enforce access with require_capability() in execute().
ajaxfalseread from the fileMust be true for the function to be called through core/ajax in the browser. Otherwise the AJAX handler throws servicenotavailable.
loginrequiredtrueread from the fileSet false only for functions that must work before login, such as sign-up or password reset in core. Those can be called through lib/ajax/service-nologin.php.
readonlysessionfalseread from the fileLets an AJAX call run without the session write lock, but only when the site also sets $CFG->enable_read_only_sessions. Use it for functions that never write to the session.
allowcorsrequestsfalseread from the fileNew in 5.3 (MDL-87150). Allows CORS for AJAX calls made without Moodle cookies. It is ignored for any function with loginrequired left true.
servicesnullexternal_functionsShortnames of built-in services to add the function to, for example MOODLE_OFFICIAL_MOBILE_SERVICE (moodle_mobile_app) for the Moodle App.
testclientpathnoneread from the fileOptional file used by the admin web service test client.

$services keys

A service is a named bundle of functions that tokens are issued against. Defining one is optional; without it, an administrator builds a custom service in the web UI. The array key is the service name, and Moodle matches existing services on that name plus your component.

KeyDefaultNotes
functionsrequiredFunction names in the service. Resynced on every upgrade: removed names are dropped, new ones added. Administrators cannot change the list of a pre-built service.
requiredcapabilitynullA capability the service user must hold to use any function in the service.
restrictedusers1When 1, only users an administrator authorises for the service can use it. Note the default is 1 if you omit the key.
enabled0Applied only when the service is first created. Later upgrades leave the administrator's choice alone.
shortnamenullNeeded so administrators can configure a restricted service in the UI. Must pass PARAM_ALPHANUMEXT and be unique across the site.
downloadfiles0Allows file downloads with the service's tokens.
uploadfiles0Allows file uploads with the service's tokens.

What happens on install and upgrade

When a plugin is installed or its version changes, upgrade_component_updated() calls external_update_descriptions() for that component. It reads the file and syncs the tables:

  • New functions get a row in external_functions; changed classname, methodname, classpath, capabilities or services values are updated.
  • A function you delete from $functions loses its external_functions row. Its entries in custom services are kept on purpose so administrators can see the function has gone.
  • A service you delete from $services is removed along with its function list, its authorised users and every token issued for it.
  • After all plugins are upgraded, external_update_services() adds functions to the services named in their services key. It only adds to services defined in code (those with a component), never to services an administrator created.

The keys marked "read from the file" in the first table are read by external_function_info() when the function is called, so a change to ajax or loginrequired applies as soon as the file is deployed. Everything stored in the database needs a version bump in version.php; see our version.php reference. In 5.3 run the upgrade with php admin/cli/upgrade.php from the project root, since admin/cli sits outside public/.

Changes that break integrations

  • Renaming a service key. Moodle sees the old name as removed and the new one as added, so existing tokens are deleted. Keep the key stable and change the description elsewhere.
  • Renaming a function. Clients calling the old name fail. Add the new function, mark the old one deprecated with execute_is_deprecated() returning true and the @deprecated PHPDoc tag, and remove it in a later release.
  • Changing parameters. Add new parameters with VALUE_DEFAULT rather than making them required. Top-level parameters cannot use VALUE_OPTIONAL.
  • Adding a function to a built-in service. Listing MOODLE_OFFICIAL_MOBILE_SERVICE exposes the function to the Moodle App, so any app user's token can call it and its capability checks must be complete.

Common errors traced to services.php

MessageCause
Cannot find file ... with external function implementationThe class is not autoloadable and no valid classpath or externallib.php exists; usually a typo in classname or a namespace mismatch.
Missing implementation method / Missing parameters description methodmethodname does not match the class, or execute_parameters() or execute_returns() is missing.
Web service is not available. (It doesn't exist or might be disabled.)From AJAX: the function's ajax key is not true.
Can't find data record in database table external_functions.The function was never registered: the version was not bumped, or the upgrade has not run yet.
Coding error: the service shortname ... can only contain alphanumeric charactersshortname contains spaces or other characters outside PARAM_ALPHANUMEXT.
A web service with the shortname ... already existsAnother service already uses that shortname. Prefix it with your component.

Token errors from external clients have their own checklist in our Moodle invalid token guide, and the Moodle guide puts web services in the context of the wider plugin APIs.

Review checklist before release

  1. Every function name starts with the plugin's frankenstyle component.
  2. Every execute() calls validate_parameters(), validate_context() and require_capability(); the capabilities key lists the same capabilities.
  3. ajax is true only for functions your JavaScript calls; loginrequired stays true unless the function is genuinely public.
  4. Service keys and shortnames are unchanged from the previous release, or the upgrade notes tell administrators that tokens will be reissued.
  5. The plugin version is bumped and the function appears under Site administration > Server > Web services > API Documentation.

How we can help

We build and review Moodle web service plugins, from function design and capability checks to upgrade-safe service definitions for integrations. See our Moodle development services or contact us about your integration.

Frequently asked questions

Do I need to bump the plugin version after editing db/services.php?

For new functions and for changes to classname, methodname, classpath, capabilities or services, yes: Moodle only syncs those during install or upgrade. Changes to ajax, loginrequired, readonlysession and allowcorsrequests are read from the file when the function is called.

Is the $services array required?

No. Without it your functions are still registered, and an administrator can add them to a custom service in Site administration. Define $services when you want a ready-made service for your integration.

Does the capabilities key in services.php enforce permissions?

No. It is shown to administrators as a hint. Your execute() method must call validate_context() and require_capability() to enforce access.

How do I make my function available to the Moodle App?

Add 'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE] to the function definition and bump the version. After the upgrade Moodle adds it to the built-in moodle_mobile_app service.

Free 30-minute consultation

Not sure where to start? Talk to an LMS engineer.

Tell us what platform you run and what you need. You’ll get honest, practical advice - even if the answer is that you don’t need us.

Sources & references

  1. Writing a new service - Moodle HQ
  2. External function definitions - Moodle HQ
  3. Service creation (custom services) - Moodle HQ
  4. upgradelib.php: external_update_descriptions() (Moodle 5.3.0) - Moodle HQ
  5. external_api class (Moodle 5.3.0) - Moodle HQ
Add as a preferred source on Google

Add All-in-One LMS as a preferred source to see more of our articles in Google’s Top Stories.

Learn more about this topic with AI

Gemini opens with the prompt copied - paste it into the chat to start.

Keep reading

Before you go - get a free LMS audit

Tell us which LMS you use and what is not working. An engineer replies within one business day.

Choose which optional cookies we may use. You can change this at any time from "Cookie preferences" in the footer. Cookie policy · Privacy policy