# Procedures

To implement a procedure in a custom book, define a Python function in your book class and decorate it with [**@procedure**](https://docs.kognitos.com/legacy/legacy-experience/books/custom-books/api-reference/decorators/procedure-decorator)**.**

## Requirements

### 1. Naming

Ensure the name of your procedure adheres to the syntax guidelines specified in the `name` parameter of the [@procedure](https://docs.kognitos.com/legacy/legacy-experience/books/custom-books/api-reference/decorators/procedure-decorator) decorator.

### 2. Method Docstrings

Your method [docstring](https://docs.kognitos.com/legacy/legacy-experience/books/custom-books/api-reference/docstrings) should include the following sections:

* A brief summary of the procedure
* Input Concepts
* Output Concepts

Examples are not required but are valuable for generating usage documentation.

### 3. Concept-Parameter Matching

Concepts and parameters must **match** to ensure they are properly mapped internally. Ensure your method definition adheres to the [guidelines](#id-3.-concept-parameter-matching).

## Using Procedures in Your Automation

### Singularized Calls

A **singularized call** is a way to call a procedure by phrasing it as if it returns a single item, even though it returns a list by definition. A procedure supports singularized calls in addition to standard calls if it meets ***all*** of the following conditions:

* **Returns a list**.
* The **output** of the procedure is the object itself.
* The **output noun phrase** is plural.
* The procedure **accepts filters.**

{% hint style="success" %}
You don't need to implement additional logic for singular calls. The system will automatically generate the singularized variation of any procedure that meets the above criteria.
{% endhint %}

#### Example

Consider a procedure that retrieves users from Outlook. It can be called in two ways:

* **Standard Way**: `get some users from outlook whose whose mail is "example.com"`
* **Singularized Way**: `get a user from outlook whose whose mail is "example.com"`

```python
@procedure("to get some (users) from *office365*")
async def retrieve_users(self, filter_expression: Optional[FilterExpression] = None) -> List[OfficeUser]:
  """
  Retrieves Office 365 users accessible via the Microsoft Graph API.

  It requires the following permissions on the application:
  User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All

  Returns:
  A list of Office 365 users.

  Example 1:
  Retrieve all users

  >>> get users from office365

  Example 2:
  Retrieve a user whose email matches the specified email address

  >>> get users from office365 whose mail is "john@acme.org"
  """
```
