> ## Documentation Index
> Fetch the complete documentation index at: https://developers.fibery.com/llms.txt
> Use this file to discover all available pages before exploring further.

# REST endpoints

> HTTP endpoints a custom integration app must implement.

Below are a list of the HTTP endpoints expected in an integration application.

**Required**

* `GET /`: returns app information
* `POST /validate`: performs validation of the account
* `POST /api/v1/synchronizer/config`: returns synchronizer configuration
* `POST /api/v1/synchronizer/schema`: returns synchronizer schema
* `POST /api/v1/synchronizer/data`: returns data

**Optional**

* `GET /logo`: returns an image/svg+xml representation of the application's logo
* `POST /api/v1/synchronizer/datalist`: returns possible options for filter fields
* `POST /api/v1/synchronizer/filter/validate`: performs filter fields validation
* `POST /api/v1/synchronizer/resource`: returns files those behind security wall
* `POST /api/v1/synchronizer/webhooks`: setting up webhook
* `POST /api/v1/synchronizer/webhooks/pre-process`: verify and process incoming event
* `POST /api/v1/synchronizer/webhooks/transform`: convert event payload into data that can be handled by Fibery

## **GET /**

GET "/" endpoint is the main one which returns information about the app. You can find response structure in [App configuration](/guides/integrations/app-configuration).

Response example:

```json theme={null}
{
  "version": "1.0", // string representing the version of your app
  "name": "My Super Application", // title of the app
  "description": "All your base are belong to us!", // long description
  "authentication": [], // list of possible account authentication approaches
  "sources": [], // empty array
  "responsibleFor": { // app responsibility
    "dataSynchronization": true // indicates that app is responsible for data synchronization
  }
}
```

**Authentication Information**

The `authentication` object includes all account schema information. It informs the Fibery front-end how to build forms for the end-user to provide required account information. This property is required, even if your application does not require authentication. At least one authentication object must be provided within array.

In case when application doesn't require authentication, the `fields` array must be omitted.

<Callout icon="circle-exclamation" color="#e72065">
  Read more about fields in [Custom App: Fields](/guides/integrations/fields).
</Callout>

*Important note:* if your app provides OAuth capabilities for authentication, the authentication identifiers *must* be `oauth` and `oauth2` for OAuth v1 and OAuth v2, respectively.

<Callout icon="circle-exclamation" color="#e72065">
  Check [Custom App: OAuth](/guides/integrations/oauth).
</Callout>

Only one authentication type per OAuth version is currently supported.

```json theme={null}
{
  "authentication": [
    {
      "id": "basic", // identifier
      "name": "Basic Authentication", // user-friendly title
      "description": "Just using a username and password", // description
      "fields": [ //list of fields to be filled
        {
          "id": "username", //field identifier
          "title": "Username", //friendly name
          "description": "Your username, duh!", //description
          "type": "text", //field type (text, password, number, etc.)
          "optional": true, // is this a optional field?
        },
        /* ... */
      ]
    }
  ]
}
```

## **POST /validate**

This endpoint performs account validation when setting up an account for the app and before any actions that uses the account. The incoming payload includes information about the account type to be validated and all fields required:

If the account is valid, the app should return HTTP status 200 with a JSON object containing a friendly name for the account:

Incoming body:

```json theme={null}
{
  "id": "basic", // identifier for the account type
  "fields": { //list of field values to validate according to schema
    "username": "test_user",
    "password": "test$user!",
    /*...*/
  }
}
```

Success Response:

```json theme={null}
{
  "name": "Awesome Account"
}
```

If the account is invalid, the app should return HTTP status 401 (Not Authorized) with a simple JSON object containing an error message:

Failure Response:

```json theme={null}
{
  "message": "Your password is incorrect!"
}
```

**Refresh Access Token**

In addition this step can be used as a possibility to refresh access token. The incoming payload includes refresh and access token, also it can include expiration datetime. Response should include new access token to override expired one.

Refresh Access Token Request:

```json theme={null}
{
  "id": "oauth2",
  "fields": {
    "access_token": "xxxx",
    "refresh_token": "yyyy",
    "expire_on": "2018-01-01"
  }
}
```

Response sample after token refresh:

```json theme={null}
{
  "name": "Awesome account",
  "access_token": "new-access-token",
  "expire_on": "2020-01-01"
}
```

## **POST /api/v1/synchronizer/config**

The endpoint returns information about synchronization possibilities based on input parameters. It instructs Fibery about:

* Available types
* Available filters
* Available functionalities

**Request**

All input parameters are optional.

| Name    | Type   | Description               |
| ------- | ------ | ------------------------- |
| account | object | selected account's fields |

Request example:

```json theme={null}
{
  "account": {
    "token": "user-token"
  }
}
```

**Response**

Response example:

```javascript theme={null}
{
  "types": [
    {"id": "bug", "name": "Bug"},
    {"id": "us", "name": "User Story"},
  ],
  "filters": [
    {
      "id": "modifiedAfter",
      "title": "Modified After",
      "optional": true,
      "type": "datebox"
    }
  ]
}
```

Output parameters:

| Name     | Type                           | Description                                                            |
| -------- | ------------------------------ | ---------------------------------------------------------------------- |
| types    | `[{id: string, name: string}]` | supported types list with id and display name                          |
| filters  | Array of filters               | it is used to help the user to exclude non-required data.              |
| webhooks | `{enabled: true, type: 'ui'}`  | Optional fields that indicates that webhook functionality is supported |

### **Filter information**

The `filter` object is used to help the user to exclude non-required data. Just like other field-like objects, the `filter` object is not required. If nothing is provided, users will not be able to filter out data received from the app.

For more information about filters, please refer to [App configuration](/guides/integrations/app-configuration) and [Fields](/guides/integrations/fields).

## **POST /api/v1/synchronizer/schema**

Integration app must provide data schema in advance so Fibery will be able to create approriate types and relations and then be able to maintain them.

It should provide a schema for all requested types. Each type must contain `name` and `id` field. In additional there is a reserved field `__syncAction` that should be added to the schema if delta synchronization with possibility of removing items should be supported.

**Request**

Request contains:

* `types` - an array of selected type ids
* `filter` - currently configured filter
* `account` - selected account

Request example

```json theme={null}
{
  "types": [
    "pullrequest",
    "repository"
  ],
  "filter": {
    "owner": "fibery",
    "repositories": [
      "fibery/core",
      "fibery/ui"
    ]
  },
  "account": {
    "token": "token"
  }
}
```

**Response**

Includes schema for all requested types

Schema is JSON object where key is field and value if field description. Field description contains:

| field       | description                        | type                                                                                                                                                  |
| ----------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| id          | Field id                           | string                                                                                                                                                |
| ignore      | Is field visible in fields catalog | boolean                                                                                                                                               |
| name        | Field name                         | string                                                                                                                                                |
| description | Field description                  | string                                                                                                                                                |
| readonly    | Disable modify field name and type | boolean                                                                                                                                               |
| type        | Type of field                      | "id", "text" ,"number" , "date", "array\[text]" Learn more in [Integration Schema types](/guides/integrations/schema-types)                           |
| relation    | Relation between types             | see relations section                                                                                                                                 |
| subType     | Optional Fibery sub type           | "url" , "integer", "email", "boolean","html", "md", "files", "date-range" Learn more in [Integration Schema types](/guides/integrations/schema-types) |

Response example:

```json theme={null}
{
  "repository": {
    "id": {
      "type": "id",
      "name": "Id"
    },
    "name": {
      "type": "text",
      "name": "Name"
    },
    "url": {
      "type": "text",
      "name": "Original URL",
      "subType": "url"
    }
  },
  "pullrequest": {
    "id": {
      "type": "id",
      "name": "Id"
    },
    "name": {
      "type": "text",
      "name": "Name"
    },
    "repositoryId": {
      "type": "text",
      "name": "Repository Id",
      "relation": {
        "cardinality": "many-to-one",
        "name": "Repository",
        "targetName": "Pull Requests",
        "targetType": "repository",
        "targetFieldId": "id"
      }
    },
    "__syncAction": {
      "type": "text",
      "name": "Sync Action"
    }
  }
}
```

### **Relations**

`relation` field provides a possibility to create a relation between entities in Fibery. It contains following fields:

| field         | description                       | type                                        |
| ------------- | --------------------------------- | ------------------------------------------- |
| cardinality   | Type of relation                  | "many-to-one", "many-to-many", "one-to-one" |
| name          | Name of the field on source side  | string                                      |
| targetType    | Id of target type                 | string                                      |
| targetName    | Field name of target side         | string                                      |
| targetFieldId | Find relation by value from field | string                                      |

Repository will have following fields (example includes only relation fields):

* Pull Requests - Array

Pull Request will have following fields:

* Repository Id - string - this field will be hidden from end user
* Repository - Repository

Example:

```json theme={null}
{
  "repository": {
    "id": {
      "type": "id",
      "name": "Id"
    },
    "name": {
      "type": "text",
      "name": "Name"
    },
    "url": {
      "type": "text",
      "name": "Original URL",
      "subType": "url"
    }
  },
  "pullrequest": {
    "id": {
      "type": "id",
      "name": "Id"
    },
    "name": {
      "type": "text",
      "name": "Name"
    },
    "repositoryId": {
      "type": "text",
      "name": "Repository Id",
      "relation": {
        "cardinality": "many-to-one",
        "name": "Repository",
        "targetName": "Pull Requests",
        "targetType": "repository",
        "targetFieldId": "id"
      }
    }
  }
}
```

**Reserved field - `__syncAction`**

Sync action is reserved field that won't be visible for end user. The field is used for delta synchronization when entity should be deleted.

## **POST /api/v1/synchronizer/data**

Data endpoint performs actual data retrieving for the specified integration settings. Data retrieving is run by each type independently.

Data synchronization supports:

* pagination
* delta synchronization

**Request**

Inbound payload includes following information:

* `types` - array of selected type ids
* `requestedType` - currently fetching type
* `account` - account on behalf of data should be fetched
* `filter` - currently configured filters
* `lastSynchronizedAt` - OPTIONAL field that indicated when last successful synchronization was run
* `pagination` - OPTIONAL field includes pagination settings that was returned from previous data request
* `schema` - current integration schema

Request example:

```json theme={null}
{
  "requestedType": "pullrequest",
  "types": ["repository", "pullrequest"],
  "filter": {
    "owner": "fibery",
    "repositories": ["fibery/core", "fibery/ui", "fibery/apps-gallery"]
  },
  "account": {
    "token": "token"
  },
  "pagination": {
    "repositories": ["fibery/ui", "fibery/apps-gallery"]
  },
  "lastSynchronizedAt": "2020-09-30T09:08:47.074Z"
  "schema": {
    "repository": {
      "id": {
        "name": "Id",
        "type": "text"
      }
    }
  }
}
```

### **Response**

Outboud payload includes:

* `items` - REQUIRED array of fetched data rows
* `pagination` - OPTIONAL parameter that includes information about pagination
* `hasNext` - boolean attribute that indicates that there are more pages available
* `nextPageConfig` - object that will be passed in `pagination` request body parameter with next page request
* `synchronizationType` - OPTIONAL parameter with possible values `delta` or `full`. It indicates how data will be handled on Fibery side. If `delta` is set then only provided changes will be applied. Fibery will be looking for `__syncAction` field to identify whether row should be set or removed. If `__syncAction` equal `REMOVE` then corresponding entity will be removed. If `full` is set then unsynced data will be removed (if keep unsynced is unchecked).

Response example:

```json theme={null}
{
  "items": [
    {
      "id": "PR_1231",
      "name": "Improve performance"
    },
    {
      "id": "PR_1232",
      "name": "Fix bugs"
    }
  ],
  "pagination": {
    "hasNext": true,
    "nextPageConfig": {
      "repositories": [
        "fibery/apps-gallery"
      ]
    }
  },
  "synchronizationType": "full"
}
```

### **Errors**

If something goes wrong then integration app should respond with corresponding error HTTP status code and error message.

Sample of error about sync failure:

```json theme={null}
{
  "message": "Unable to fetch data."
}
```

But some errors can be fixed if try to fetch data later. In this case error body should include `tryLater` flag with value `true`. Fibery will retry this particular page later on.

Sample of error about limits

```json theme={null}
{
  "message": "Rate limits reached",
  "tryLater": true
}
```

## **GET /logo**

`OPTIONAL`

The `/logo` endpoint is used to provide a SVG representation of a connected application's logo. This endpoint is entirely optional. Valid responses are a HTTP 200 response with a `image/svg+xml` content type, a HTTP 204 (No Content) response if there is no logo, or a 302 redirect to another URI containing the logo. If no logo is provided, or an error occurs, the application will be represented with our default app logo.

## **POST /api/v1/synchronizer/datalist**

`OPTIONAL`

**Request**

The inbound payload includes:

* `types` - an array of selected type ids
* `account` - selected account
* `field` - name of requested field
* `dependsOn` - object that contains filter key-value pairs of dependant fields

Request body:

```json theme={null}
{
  "types": [
    "pullrequest",
    "branch"
  ],
  "account": {
    "token": "token"
  },
  "field": "repository",
  "dependsOn": {
    "owner": "fibery"
  }
}
```

This endpoint performs retrieving datalists from filter fields that marked with `datalist` flag.

**Response**

The response from your API should include `items` that is a JSON-serialized list of name-value objects: The `title` in each object is what is displayed to the end-user for each value in a combobox and the `value` is what is stored with the filter and what will be passed with subsequent requests that utilize the user-created filter.

Response sample:

```json theme={null}
{
  "items": [
    {
      "title": "fibery/ui",
      "value": "124"
    },
    {
      "title": "fibery/core",
      "value": "125"
    }
  ]
}
```

## **POST /api/v1/synchronizer/filter/validate**

`OPTIONAL`

This endpoint performs filter validation. It can be useful when app doesn't know about what filter value looks like. For example, if your app receives sql query as filter you may want to check is that query is valid.

**Request**

Request body contains:

* `types` - array of selected type ids
* `account` - account on behalf of data should be fetched
* `filter` - currently configured filters

Request example:

```json theme={null}
{
  "types": [
    "repository",
    "pullrequest"
  ],
  "filter": {
    "owner": "fibery",
    "repositories": [
      "fibery/core",
      "fibery/ui",
      "fibery/apps-gallery"
    ]
  },
  "account": {
    "token": "token"
  }
}
```

**Response**

If the filter is valid, the app should return HTTP status 200 or 204.

If the account is invalid, the app should return HTTP status 400 (Bad request) with a simple JSON object containing an error message:

Error response sample:

```json theme={null}
{
  "message": "Your filter is incorrect!"
}
```

## POST /api/v1/synchronizer/resource

`OPTIONAL`

This endpoint is used to access files that require authentication. For example, if the schema contains a `files` field and the files are not accessible by direct link then this route can be used to download files by specifying a url as `app://resource?url=:url&value=1`. As a result the route will be called with `url` and `value` params. The resource endpoint is called with all query parameters specified in `app://resource` url.

**Request**

Request body contains:

* `types` - array of selected type ids
* `account` - account on behalf of data should be fetched
* `filter` - currently configured filters
* `params` - list of parameters.

**Response**

File content as a stream

## POST /api/v1/synchronizer/webhooks

`OPTIONAL`

The endpoint is responsible for installing, updating or reinstalling a webhook based on provided parameters. It's the place where webhook based configuration starts.

**Request**. It accepts following parameters:

* `types` - an array of selected types ids
* `filter` - currently configured filter
* `account` - authenticated external account
* `webhook` - OPTIONAL. If it's `null` then a new webhook is going to be installed, otherwise it will contain current webhook configuration (that is returned by THIS endpoint)

```json theme={null}
{
  "types": [
    "pullrequest",
    "repository"
  ],
  "filter": {
    "owner": "fibery",
    "repositories": [
      "fibery/ui",
      "fibery/core"
    ]
  },
  "account": {
    "token": "token"
  },
  "webhook": null
}
```

**Response:**

Response is a JSON object with following required fields

* `id` - some random id
* `workspaceId` - 3rd party workspace id linked to webhook/synchronization (e.g. slack workspace, intercom workspace, gitlab organization)
* any other data that you want to receive on reinstall event.

```json theme={null}
{
  "id": "webhook_id",
  "workspaceId": "workspaceId",
  "events": [
    "create_repo",
    "delete_repo"
  ]
}
```

## POST /api/v1/synchronizer/webhooks/pre-process

`OPTIONAL`

The route is responsible for initial pre processing of request. Data that is received by this route is the same as 3rd party service sends without any changes (almost). It's done to be able to calculate request signature properly.

Goals of the service:

* verify incoming request (usually it means that service should verify signature based on 3rd party system chosen algorithm, e.g. [hubspot webhook verification](https://developers.hubspot.com/beta-docs/guides/apps/authentication/validating-requests#validating-requests-from-hubspot))
* response with data that should be sent to 3rd party caller and list of workspace ids this event will work for. HTTP status code of the response will also be forwarded to 3rd party system

**Request**

Request payload and headers depends on 3rd party service

**Response**

Response should include following fields:

* `reply` - data will be send as a response to 3rd party caller
* `workspaceIds` - array of workspace ids this event can be applied on. Array can be empty

```json theme={null}
{
  "reply": {
    "challenge": "value"
  },
  "workspaceIds": [
    "team-a",
    "team-b"
  ]
}
```

## POST /api/v1/synchronizer/webhooks/transform

`OPTIONAL`

This route is responsible for converting event payload into data that can be handled by Fibery. Data is applied by `delta` synchronization rules.

**Request**

Request payload includes:

* `params` - event headers that comes from external system.
* `payload` - event body that comes from external system.
* `types` - an array of selected type ids
* `filter` - currently configured filter
* `account` - selected account

```json theme={null}
{
  "params": {
    "x-github-id": "1234",
    "x-github-signature256": "dsadsa"
  },
  "payload": {
    "action": "create",
    "repository": {
      "id": "repo1"
    }
  },
  "types": [
    "pullrequest",
    "repository",
    "branch"
  ],
  "filter": {
    "owner": "fibery",
    "repositories": []
  },
  "account": {
    "token": "token"
  }
}
```

**Response**

Response includes `data` object that is a map of data arrays by type id.

```json theme={null}
{
  "data": {
    "repositories": [
      {
        "id": "repo1",
        "name": "Repo1",
        "__syncAction": "SET"
      }
    ],
    "branches": [
      {
        "id": "master",
        "name": "master",
        "repositoryId": "repo1",
        "__syncAction": "SET"
      }
    ]
  }
}
```
