> ## Documentation Index
> Fetch the complete documentation index at: https://nango-khaliq-nan-660-add-support-for-personio-apis-to-nango.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration scripts

# Examples

<Tabs>
  <Tab title="Sync script">
    ```ts
    import type { GithubIssueDemo, NangoSync } from './models';

    export default async function fetchData(nango: NangoSync) {
        // Fetch issues from GitHub.
        const res = await nango.get({
            endpoint: '/repos/NangoHQ/interactive-demo/issues?labels=demo&sort=created&direction=asc'
        });

        // Map issues to your preferred schema.
        const issues: GithubIssueDemo[] = res.data.map(({ id, title, html_url }: any) => {
            return { id, title, url: html_url };
        });

        // Persist issues to the Nango cache.
        await nango.batchSave(issues, 'GithubIssueDemo');
    }
    ```
  </Tab>

  <Tab title="Action script">
    ```ts
    import type { NangoAction, GithubCreateIssueInput, GithubCreateIssueResult } from './models';

    export default async function runAction(nango: NangoAction, input: GithubCreateIssueInput): Promise<GithubCreateIssueResult> {
        // Create a GitHub issue.
        const res = await nango.post({
            endpoint: '/repos/NangoHQ/interactive-demo/issues',
            data: {
                title: `[demo] ${input.title}`,
                body: `The body of the issue.`,
                labels: ['automatic']
            }
        });

        // Send response.
        return { url: res.data.html_url, status: res.status };
    }
    ```
  </Tab>
</Tabs>

Read more about [integration scripts](/understand/concepts/scripts) to understand what role they play in Nango.

Integration scripts expose a helper object (`NangoSync` for sync scripts, `NangoAction` for action scripts), which allows to interact with external APIs & Nango more easily.

# HTTP requests

Makes an HTTP request inside an integration script:

```js
const config = { endpoint: '/some-endpoint' };

await nango.get(config); // GET request
await nango.post(config); // POST request
await nango.put(config); // PUT request
await nango.patch(config); // PATCH request
await nango.delete(config); // DELETE request
```

<Tip>
  Note that all HTTP requests benefit from automatic credential injection. Because scripts are executed in the context of a specific integration & connection, Nango can automatically retrieve & refresh the relevant API credentials.
</Tip>

**Parameters**

<Expandable>
  <ResponseField name="config" type="object" required>
    <Expandable title="config" defaultOpen>
      <ResponseField name="endpoint" type="string" required>
        The endpoint of the request.
      </ResponseField>

      <ResponseField name="headers" type="Record<string, string>">
        The headers of the request.
      </ResponseField>

      <ResponseField name="params" type="Record<string, string | number>">
        The query parameters of the request.
      </ResponseField>

      <ResponseField name="data" type="unknown">
        The body of the request.
      </ResponseField>

      <ResponseField name="retries" type="number">
        The number of retries in case of failure (with exponential back-off). Optional, default 0.
      </ResponseField>

      <ResponseField name="retryOn" type="number[]">
        Array of additional status codes to retry a request in addition to the 5xx, 429, ECONNRESET, ETIMEDOUT, and ECONNABORTED
      </ResponseField>

      <ResponseField name="baseUrlOverride" type="string">
        The API base URL. Can be ommitted if the base URL is configured for this API in the [providers.yaml](https://nango.dev/providers.yaml).
      </ResponseField>

      <ResponseField name="decompress" type="boolean">
        Override the decompress option when making requests. Optional, defaults to false
      </ResponseField>

      <ResponseField name="responseType" type="'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'">
        The type of the response.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

**Response**

<Expandable>
  ```json
      {
          data: {}, // the response provided by the server
          status: 200, // the HTTP status code
          headers: {}, // the HTTP headers
          config: {}, // the config provided for the request
          request: {} // the request that generated this response
      }
  ```

  <Tip>
    The response object is an [Axios response](https://axios-http.com/docs/res_schema).
  </Tip>
</Expandable>

# Logging

You can collect logs in integration scripts. This is particularly useful when:

* developing, to debug your integration scripts
* in production, to collect information about integration script executions & understand issues

Collect logs in integration scripts as follows:

```ts
await nango.log("This is a log.");
```

Logs can be viewed & searched in the Nango UI. We plan to make them exportable in the future as well.

# Environment variables

Integration scripts sometimes need to access sensitive variables that should not be revealed directly in the code.

For this, you can define environment variables in the Nango UI, in the *Environment Settings* tab. Then you can retrieve these environment variables from integration scripts with:

```js
await nango.getEnvironmentVariables();
```

**Parameters**

No parameters.

**Response**

<Expandable>
  ```json
  [
      {
          "name": "MY_SECRET_KEY",
          "value": "SK_373892NSHFNCOWFO..."
      }
  ]
  ```
</Expandable>

# Trigger action

Integration scripts currently do not support importing files, which limits the ability to share code between integration scripts.

As a temporary workaround, you can call action scripts from other integration scripts with:

```js
await nango.triggerAction('<ACTION-NAME>', { 'custom_key1': 'custom_value1' });
```

**Parameters**

<Expandable>
  <ResponseField name="actionName" type="string" required>
    The name of the action to trigger.
  </ResponseField>

  <ResponseField name="input" type="unkown" required>
    The necessary input for your action's `runAction` function.
  </ResponseField>
</Expandable>

**Response**

<Expandable>
  ```json
  {
      "your-properties": "The data returned by the action"
  }
  ```
</Expandable>

# Paginate through API responses

Follow the pagination [step-by-step guides](/customize/guides/advanced/paginate-api-responses) to learn how to paginate through API responses easily.

# Manage connection metadata

### Get connection metadata

Returns the connection's metadata.

```js
await nango.getMetadata();
```

Better, you can specify the type of the metadata;

```ts
interface CustomMetadata {
    anyKey: Record<string, string>;
}
const myTypedMetadata = await nango.getMetadata<CustomMetadata>();
```

**Parameters**

No parameters.

**Example Response**

<Expandable>
  ```json
  {
      "custom_key1": "custom_value1"
  }
  ```
</Expandable>

### Set connection metadata

Set custom metadata for the connection (overrides existing metadata).

```js
await nango.setMetadata({ 'CUSTOM_KEY1': 'CUSTOM_VALUE1' });
```

**Parameters**

<Expandable>
  <ResponseField name="metadata" type="Record<string, any>" required>
    The custom metadata to store in the connection.
  </ResponseField>
</Expandable>

**Response**

Empty response.

### Edit connection metadata

Edit custom metadata for the connection. Only overrides & adds specified properties, not the entire metadata.

```js
await nango.updateMetadata({ 'CUSTOM_KEY1': 'CUSTOM_VALUE1' });
```

**Parameters**

<Expandable>
  <ResponseField name="metadata" type="Record<string, any>" required>
    The custom metadata to store in the connection.
  </ResponseField>
</Expandable>

**Response**

Empty response.

# Get the connection credentials

Returns a specific connection with credentials.

```js
await nango.getConnection();
```

<Info>
  The response content depends on the API authentication type (OAuth 2, OAuth 1, API key, Basic auth, etc.).
</Info>

<Tip>
  When you fetch the connection with this API endpoint, Nango will check if the access token has expired. If it has, it will refresh it.

  We recommend not caching tokens for longer than 5 minutes to ensure they are fresh.
</Tip>

**Parameters**

<Expandable>
  <ResponseField name="forceRefresh" type="boolean">
    Defaults to `false`. If `false`, the token will only be refreshed if it expires within 15 minutes. If `true`, a token refresh attempt will happen on each request. This is only useful for testing and should not be done at high traffic.
  </ResponseField>

  <ResponseField name="refreshToken" type="boolean">
    Defaults to `false`. If `false`, the refresh token is not included in the response, otherwise it is. In production, it is not advised to return the refresh token, for security reasons, since only the access token is needed to sign requests.
  </ResponseField>
</Expandable>

**Example Response**

<Expandable>
  ```json
  {
      "id": 18393,                                 
      "created_at": "2023-03-08T09:43:03.725Z",     
      "updated_at": "2023-03-08T09:43:03.725Z",     
      "provider_config_key": "github",              
      "connection_id": "1",                         
      "credentials": {
          "type": "OAUTH2",                         
          "access_token": "gho_tsXLG73f....",       
          "refresh_token": "gho_fjofu84u9....",     
          "expires_at": "2024-03-08T09:43:03.725Z", 
          "raw": { // Raw token response from the OAuth provider: Contents vary!
              "access_token": "gho_tsXLG73f....",
              "refresh_token": "gho_fjofu84u9....",
              "token_type": "bearer",
              "scope": "public_repo,user"
          }
      },
      "connection_config": {                       
          "subdomain": "myshop",
          "realmId": "XXXXX",
          "instance_id": "YYYYYYY"
      },                      
      "account_id": 0,                              
      "metadata": {                                 
          "myProperty": "yes",
          "filter": "closed=true"
      }
  }                              
  ```
</Expandable>

# Sync-specific helper methods

Sync scripts persist data updates to the Nango cache, which your app later fetches (cf. [step-by-step guide](/integrate/guides/sync-data-from-an-api)).

### Save records

Upserts records to the Nango cache (i.e. create new records, update existing ones). Each record needs to contain a unique `id` field used to dedupe records.

```js
const githubIssues: GitHubIssue[] = ...; // Fetch issues from GitHub API. 

await nango.batchSave(githubIssues, 'GitHubIssue');
```

**Parameters**

<Expandable>
  <ResponseField name="recordList" type="Model[]" required>
    The list of records to persist.
  </ResponseField>

  <ResponseField name="modelType" type="string" required>
    The model type of the records to persist.
  </ResponseField>
</Expandable>

### Delete records

Marks records as deleted in the Nango cache. Deleted records are still returned when you fetch them, but they are marked as deleted in the record's metadata (i.e. soft delete).

The only field that needs to be present in each record when calling `batchDelete` is the unique `id`; the other fields are ignored.

```js
const githubIssuesToDelete: { id: string }[] = ...; // Fetch issues to delete from GitHub API. 

await nango.batchDelete(githubIssuesToDelete, 'GitHubIssue');
```

**Parameters**

<Expandable>
  <ResponseField name="recordList" type="{ id: string }[]" required>
    The list of records to delete.
  </ResponseField>

  <ResponseField name="modelType" type="string" required>
    The model type of the records to delete.
  </ResponseField>
</Expandable>

# Action-specific helper methods

### `ActionError`

You can use `ActionError` in an action script to return a descriptive error to your app when needed:

```ts

export default async function runAction(nango: NangoAction): Promise<Response> {
    // Something went wrong...

    throw new ActionError({ any_key: 'any_value' });
}

```

In this case, the response to the trigger action call will be:

```json
{
  "error_type": "action_script_failure",
  "payload": {
    "any_key": "any_value"
  }
}
```

<Tip>
  **Questions, problems, feedback?** Please reach out in the [Slack community](https://nango.dev/slack).
</Tip>
