# General Concepts

{% hint style="danger" %}
**Don't serialize/use as response i128**.\
\
We're investigating a bug that crashes the program's execution when i128s are being serialized. Consider converting them to i64s in the responses. Converting to string won't work either.
{% endhint %}

Serverless functions are similar to other functions in your program, but they are not executed for each ledger close. Instead, they are triggered externally through a web request that fetches our program, specifically our function, which contains the logic for what to return and how to return it to the caller.

They are called *severless* as you will have them available without running any infrastructure: just create the function in your program that will live on our servers, and call it externally afterwords.

Therefore, they have some unique characteristics compared to regular functions.

## EnvClient::empty()

The first thing to note is that when getting a handle on the host environment client from inside a serverless function, you should never use the standard `EnvClient::new()` that we have inside the `on_close()` functions. Using that handle will result in the program's execution stopping immediately if called as a serverless function.

You should rather use the `EnvClient::empty()` function which is compatible with serverless functions.

## Reading the request body

We said that the function will be called through a web request: the request body that you provide in the web request is forwarded to the VM and can be accessed guest-side with `env.read_request_body()` . The request structure will also need to be defined in the program:

```rust
#[derive(Serialize, Deserialize)]
pub struct Request {
    account: String
}

#[no_mangle]
pub extern "C" fn test_function() {
    let env = EnvClient::empty();
    let request: Request = env.read_request_body();
}
```

## Returning the response

Returning the response is done through `env.conclude(response)` where `response` is a serializable type.

That is the general pattern, in the next chapters we will see a lot of examples of how these elements work together.

***

## Calling functions

To call functions you can run a web request against the `/zephyr/execute` endpoint:

{% code overflow="wrap" %}

```bash
curl -X POST https://testnet.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"project_name":"zephyr-hello-world", "mode":{"Function": {"fname": "test_function", "arguments": "{\"account\": \"GC5PGBLWLRPBIJ7AC2KD3MI34BXYKCJIRVXXFBR2CP2NBLVN2LLY2HUJ\"} "}}}'
```

{% endcode %}

Where you specify the request body within the `arguments` field. Remember also to specify the correct Zephyr endpoint in the request. You can find a list of our endpoints [here](/genaral-info/endpoints.md).

## Making Functions Public and A Note on Auth

Calling functions as showed above is an authorized action, as a result, code deployed by a certain user can only be called with a JWT token that authenticates the user. This is a common practice and should always be enforced, but in some situations one might prefer to open certain data retrieval functions of the API to the public.

You can make a function publicly callable (by anyone) by calling the Mercury API. For example, if the program exports API functions `retrieve` and `users` you can make these public with:

{% code overflow="wrap" %}

```
curl -X POST https://mainnet.mercurydata.app/zephyr/pubfunctions -H "Authorization: Bearer $MERCURY_JWT" -H "Content-Type: application/json" -d '{"public":["retrieve", "users"]}'
```

{% endcode %}

## Invoking Public Functions

Once your function is public, you must invoke it by specifying the identifier of the program (which on the other hand is derived when providing the JWT). That identifier corresponds to your user id. If you don't know your user id yet (it will be soon added to the webapp), you can query the API with `allUsers` along with your authorization header:

<figure><img src="/files/QQqc1TJ39CxrTtiX3E0K" alt=""><figcaption></figcaption></figure>

Once you know your id, you can invoke the program specifying the user id with `execute/{id}` :

{% code overflow="wrap" %}

```
curl -X POST https://mainnet.mercurydata.app/zephyr/execute/30 -H 'Content-Type: application/json' -d '{"project_name": "YOUR PROJECT NAME", "mode":{"Function": {"fname": "retrieve", "arguments": "{\"kind\": \"Collateral\", \"address\": \"GDJSH2NU2WF6J4P5DL4522DUCABWSTZOKFQ7BHBCFYQ3QKC6FRYWP6OL\"}"}}}'
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mercurydata.app/zephyr-full-customization/learn/custom-apis-serverless-functions/general-concepts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
