> For the complete documentation index, see [llms.txt](https://docs.ninox.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ninox.com/ninox-scripting/automate-your-workflows/work-with-functions/integration-and-http.md).

# Integration and HTTP

Learn how to call external services, validate XML against XSD schemas, transform XML, create email values, and send emails with Ninox scripts.

Integration functions connect your app to services and communication tools outside Ninox. You can call APIs, validate XML against schemas, transform XML, and send emails.

In this chapter, you will learn how to:

* Call external services with HTTP.
* Validate XML against an XSD schema.
* Transform XML.
* Create email values and send emails.

<table><thead><tr><th width="249.3359375">Function (A-Z)</th><th>Task</th></tr></thead><tbody><tr><td><code>email()</code></td><td>Convert text into an email value</td></tr><tr><td><code>formatXML()</code></td><td>Convert JSON data to XML text</td></tr><tr><td><code>http()</code></td><td>Send an HTTP request</td></tr><tr><td><code>parseXML()</code></td><td>Convert XML text to a JSON object</td></tr><tr><td><code>sendEmail()</code></td><td>Send an email from your Ninox app</td></tr><tr><td><code>validateXML()</code></td><td>Validate XML text against an attached XSD schema</td></tr></tbody></table>

## Call external services

Use these functions to call any REST API, to pull data from another service or push data between Ninox databases.

### Call an API with `http()`

Use `http()` to send a request to an external service.

Use it when you want to:

* Fetch data from, or send updates to another system.
* Connect Ninox to REST APIs and other Ninox databases.

{% hint style="warning" %}
**Don't place `http()` inside `do as transaction...end`**

Transactions use a single-threaded write queue. An HTTP call inside a transaction blocks all other writes until the request finishes. The app does not hang forever, but every pending write waits for the full duration of the call. That can make the app feel slow.
{% endhint %}

`http(method, url)`\
`http(method, url, body)`\
`http(method, url, header, body)`\
`http(method, url, header, body, files)`

* `method` the HTTP method as text, for example, `"GET"` or `"POST"`
* `url` text value of the endpoint URL
* `header` optional request headers as a JSON object, for example, `{ Authorization: token }`
* `body` optional request body as a JSON object
* `files` optional files to upload as `[file]` when the current execution context supports file uploads (server context)

{% hint style="warning" %}
**A body is required when accessing Ninox data**

If you use `http()` to access data in Ninox, a body must be passed. If no information needs to be passed in the body, pass an empty object: `{}`. For example:

`http("GET", "https://api.ninox.com/v1/[...]", {Authorization: "Bearer xxxx-xxxx-xxxx", "content-type": "application/json"}, {})`
{% endhint %}

#### Let’s take a look at some examples:

```ninox
http("GET", "https://api.example.com/status")
```

Calls the external service and returns a JSON response object or an error object.

```ninox
let url := "https://api.ninox.com/v1/teams/" + teamId() +
           "/databases/" + databaseId() + "/tables/";
let apiKey := "Bearer abcd1234-0000-xxxx-zzzz-1a1aa1aaa1a111";

let response := http("GET", url, {
    Authorization: apiKey
});
response
```

Lists tables from the current database through the Ninox API or an error object.

```ninox
do as server
   let url := "https://api.ninox.com/v1/teams/" + teamId() +
             "/databases/" + databaseId() + "/query";
   let apiKey := "Bearer abcd1234-0000-xxxx-zzzz-1a1aa1aaa1a111";
   
   let response := http("POST", url, {
             Authorization: apiKey, 
             "content-type": "application/json"
   }, {
    query: "select customers where status = 4"
   });
   response
end
```

Sends a POST request and returns matching records or an error object.

<pre class="language-ninox"><code class="lang-ninox"><strong>let response := do as server
</strong>    http("POST",
        "https://example.com/upload",
        { "content-type": "multipart/form-data" },
        null,
        [myFile])
end
</code></pre>

Uploads a file to an external service when file uploads are supported in the current execution context.

Tips:

* `http()` returns a JSON object, not plain text.
* If you access another Ninox database, you need an API key.
* Some endpoints expect a body even for `GET` requests. Use `{}` when the target endpoint requires one and you do not need to send fields.
* File uploads depend on the execution context.
* Test integration scripts against the real service response, not sample output only.

## Validate and transform XML

Use these functions when another system sends or expects XML, especially when the XML must match a defined schema.

### Check XML before you use it with `validateXML()`

Use `validateXML()` to validate an XML string against an XSD schema file. This is useful when you receive XML from an external source and need to confirm that the structure matches the expected schema before you process it further.

Use it when you want to:

* Catch invalid XML structures before parsing them.
* Protect follow-up logic from malformed or unexpected input.

`validateXML(record, string, string)`

* `record` the record that contains the attached XSD schema file
* First `string` the XML text you want to validate
* Second `string` the filename of the XSD schema attached to the record

#### Let’s take a look at some examples:

```ninox
let xsd := ---
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="ordertype">
    <xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:element name="order" type="ordertype"/>
</xs:schema>
---;
let xsdFilename := "validation.xsd";
let xsdFile := createTextFile(this, xsd, xsdFilename);
let xmlString := ---
<?xml version="1.0" encoding="UTF-8"?>
<order
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="order.xsd">
</order>
---;
formatJSON(validateXML(this, xmlString, xsdFilename))
```

Returns a JSON object with the validation result and any errors, for example:

```json
{"result":true,"errors":[]}
```

```ninox
xmlString := ---
<?xml version="1.0" encoding="UTF-8"?>
<order id="123"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="order.xsd">
</order>
---;
formatJSON(validateXML(this, xmlString, xsdFilename))
```

This example continues the previous example.

Returns a JSON object with `result: false` and the validation errors, for example:

```json
{"result":false,"errors":[{"domain":17,"code":1827,"level":2,"column":0,"file":"","line":4,"str1":"id"}]}
```

{% hint style="info" %}
If the attached file does not contain a valid XSD schema, the function returns `void`.
{% endhint %}

### Convert XML text to data with `parseXML()`

Use `parseXML()` to turn XML text into a JSON object you can inspect in Ninox. This is especially useful when you connect Ninox to external services by API and need to process XML responses. XML is a common exchange format alongside JSON.

Use it when you want to:

* Read values from an XML response.
* Extract fields from imported XML.
* Convert XML into structured data for later logic.

`parseXML(string)`

* `string` the XML text you want to convert to a JSON object

#### Let’s take a look at an example:

```ninox
let xml := "<?xml version=""1.0"" encoding=""UTF-8""?>
<note>
    <to>Jane Doe</to>
    <from>Ninox</from>
    <heading>Save the world!</heading>
    <body>Please save the world!</body>
</note>";
parseXML(xml)
```

Returns a JSON object built from the XML text, for example:

```json
{
  "note": {
    "to": {
      "@": "Jane Doe"
    },
    "from": {
      "@": "Ninox"
    },
    "heading": {
      "@": "Save the world!"
    },
    "body": {
      "@": "Please save the world!"
    }
  }
}
```

{% hint style="info" %}
If you have an XSD schema, validate external XML before you parse it.
{% endhint %}

### Create XML text with `formatXML()`

Use `formatXML()` to convert JSON data into XML text.

Use it when you want to:

* Prepare XML for another service.
* Reformat parsed data into readable XML.

`formatXML(JSON)`\
`formatXML(JSON, boolean)`

* `JSON` the structured data you want to convert to XML
* `boolean` whether the output should be visually structured for reading

#### Let’s take a look at some examples:

```ninox
let x := parseXML("<root><item>1</item></root>");
formatXML(x, true)
```

Formats the parsed object back into readable XML text.

```ninox
formatXML({
    contact: {
        @type: "Person",
        firstName: {
            @: "Max"
        },
        lastName: {
            @: "Mustermann"
        },
        phone: [{
            @type: "Mobile",
            @: "(+1) (202) 123 45 67"
        }, {
            @type: "Phone",
            @: "+1.151.11 ++66 14 66"
        }]
    }
}, true)
```

Converts the JSON object into structured XML text. Keys like `@type` become XML attributes. `@` becomes the node text value.

Tips:

* Use the pretty option when humans need to read the result.
* Use compact output when the target system only needs the payload.
* This function is especially useful for API integrations that expect XML instead of JSON.

## Send email messages

Use this function to open an email message from Ninox.

### Work with an email value using `email()`

Use `email()` to convert text into an email value.

Use it when you want to:

* Open your device's email app from an email value.
* Display a Logic field as an email field.
* Extract an email address from text and use it with one click.

`email(string)`

* `string` the text value to use as an email address. Include an `@` and a valid domain.

{% hint style="info" %}
Click <i class="fa-envelope">:envelope:</i> in a field or button. Ninox opens your device's default email app.
{% endhint %}

#### Let’s take a look at some examples:

```ninox
email(myEmail)
```

Converts the value in `myEmail` into an email value.

```ninox
email("maria.garcia@company.com")
```

Displays the address as an email value with a clickable mail action.

Tips:

* Use correctly formatted email addresses. Otherwise, the mail action can return an error.
* A correctly formatted address opens your device's default email app.

### Send a message with `sendEmail()`

Use `sendEmail()` to send an email directly from Ninox. It is best used in a button or automation when you want to trigger an outgoing message from a record or workflow.

Use it when you want to:

* Send order confirmations or any other emails from Ninox.
* Trigger a notification from a button or automation.
* Send attachments with a message.

`sendEmail(JSON)`

* `JSON` the email definition, for example:
  * `from` sender email address
  * `to` recipient email address
  * `replyTo` reply address - *optional*
  * `cc` copy recipient - *optional*
  * `bcc` blind copy recipient - *optional*
  * `subject` subject line
  * `text` plain text body
  * `html` HTML body
  * `attachments` file or files to attach - *optional*

#### Let’s take a look at some examples:

```ninox
sendEmail({
    from: "support@example.com",
    to: "customer123@example.com",
    cc: "contact456@example.com",
    bcc: "noreply@example.com",
    subject: "Thank you for your email",
    text: "We received your request to get another copy of your invoice",
    html: "<b> Some text with markup </b>",
    attachments: invoice_field
})
```

Sends an email from `support@example.com` and attaches the file that is displayed in the image field "Invoice".

Use `replyTo` when replies should go to a different address than `from`.

```ninox
sendEmail({
    from: "support@example.com",
    to: "customer123@example.com",
    replyTo: "reply@example.com",
    cc: "contact456@example.com",
    bcc: "noreply@example.com",
    subject: "Thank you for your email",
    text: "We received your request to get another copy of your invoice",
    html: "<b> Some text with markup </b>",
    attachments: invoice_field
})
```

Sends the same email, but replies go to `reply@example.com`.

Tips:

* The sender must be a member of the workspace!
* `cc`, `bcc`, `replyTo`, and `attachments` are optional.
* There is no immediate delivery confirmation and the sent email is not stored in the database.
* Build totals and dates with `format()` before you include them in the message.

{% hint style="info" %}
Integration behavior can depend on your environment, client, and connected services. Confirm HTTP and email workflows in the same setup your users run in production.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.ninox.com/ninox-scripting/automate-your-workflows/work-with-functions/integration-and-http.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
