## 1. Project Overview & Quickstart (getfider/fider)

# Adding a New Language to Fider 💪

This guide explains how to add a new language/locale to Fider.

## Overview

All locale definitions are centralized in **`app/models/enum/locale.go`**. This is the single source of truth for backend locale metadata including locale codes, display names, pluralization rules, PostgreSQL text search configurations, and language detection mappings.

## Step 1: Create Translation Files

1. Create a new directory in `/locale` with the locale code (e.g., `ko` for Korean, `pt-BR` for Brazilian Portuguese)

2. Create two JSON files in the new directory:
   - `client.json` - Frontend translations (UI strings)
   - `server.json` - Backend translations (emails, server-side messages)

The easiest way to do this is copy the english files, and remove all the translations, replacing them with ones in your language.

## Step 2: Add Locale to Backend (Go)

Edit **`app/models/enum/locale.go`**:

1. Add a new locale constant:

   ```go
   LocaleKorean = Locale{
       Code:              "ko",                 // Locale code
       Name:              "Korean",             // Display name
       MessageFormatCode: "ko",                 // Pluralization library culture code
       PostgresConfig:    "simple",             // PostgreSQL text search config
       LinguaLanguage:    lingua.Korean,        // Lingua-go language enum
       IsRTL:             false,                // Right-to-left text direction
   }
   ```

2. Add the new locale to the `AllLocales` slice:
   ```go
   AllLocales = []Locale{
       LocaleEnglish,
       LocalePortugueseBR,
       // ... other locales
       LocaleKorean,  // Add your new locale here
   }
   ```

### Field Explanations

- **Code**: The locale code (e.g., `"en"`, `"pt-BR"`, `"ko"`)
- **Name**: Human-readable name shown in language selector
- **MessageFormatCode**: Culture code for the [messageformat](https://github.com/gotnospirit/messageformat) library (used for pluralization)
- **PostgresConfig**: PostgreSQL text search configuration name (see [PostgreSQL docs](https://www.postgresql.org/docs/current/textsearch-dictionaries.html))
  - Available configs: `"english"`, `"german"`, `"french"`, `"spanish"`, `"portuguese"`, `"italian"`, `"dutch"`, `"russian"`, `"swedish"`, `"turkish"`, `"arabic"`
  - Use `"simple"` if PostgreSQL doesn't have native support for your language
- **LinguaLanguage**: The [lingua-go](https://github.com/pemistahl/lingua-go) enum for automatic language detection
  - See lingua-go documentation for available languages
- **IsRTL**: Set to `true` for right-to-left languages (Arabic, Hebrew, Persian, etc.)

## Step 3: Add Locale to Frontend

1. Update `locale/locales.ts`

Add your locale to the `locales` object:

```typescript
const locales: { [key: string]: Locale } = {
  en: {
    text: "English",
  },
  // ... other locales
  ko: {
    text: "Korean",
  },
}
```

2. Update `lingui.config.js`

Add your locale code to the `locales` array:

```javascript
locales: ["pt-BR", "es-ES", "nl", /* ... other locales, */ "ko"],
```

3. Update `public/ssr.tsx`

Add your locale to the `messages` object for server-side rendering:

```typescript
const messages: { [key: string]: any } = {
  en: require(`../locale/en/client`),
  // ... other locales
  ko: require(`../locale/ko/client`),
}
```

## Step 4: Generate and Compile Translations

After adding the locale to all configuration files:

1. Check that everything works..

   ```bash
   make build
   ```

2. Run the server:

   ```bash
   make run
   ```

3. Verify:

   - The new language appears in the language selector
   - Translations display correctly
   - Right-to-left rendering works (if applicable)
   - Search functionality works with the correct PostgreSQL configuration

4. Open a pull request

## When New Translation Strings Are Added

Fider uses [LinguiJS](https://lingui.dev) for i18n management. When new features are added:

1. New translation keys are automatically extracted and added to all locale files (`client.json` / `server.json`)
2. A [GitHub Action](/.github/workflows/locale.yml) uses Google Cloud Translate to automatically translate missing keys
3. Machine translations are submitted as a pull request for review

While the automated translations work well for most cases, you may want to refine them for accuracy and cultural context. Feel free to submit pull requests with improved translations at any time.

## 2. Official Technical Reference & Guides (getfider/fider-docs)

## File: README.md

# Welcome to the Fider docs

This public repo hosts the documentation used at the fider site --> https://fider.io

The files are pullied in to the main fider website to build the documentation. 

Pull requests welcome!

---

## File: api.mdx

import Overview from './api/overview.mdx'
import Authentication from './api/authentication.mdx'
import BestPractices from './api/best-practices.mdx'
import Posts from './api/posts.mdx'
import Votes from './api/votes.mdx'
import Comments from './api/comments.mdx'
import Users from './api/users.mdx'
import Tags from './api/tags.mdx'
import Invitations from './api/invitations.mdx'

<Overview />
<Authentication />


<Votes />
<Comments />

<Tags />

---

## File: configuring-oauth.mdx

OAuth is an open standard for authentication and authorization. Fider is an OAuth client that can connect to any OAuth2 provider to enable a fast, easy and secure sign in process.

Fider has native support to Facebook, Google and GitHub. To add any other OAuth provider please follow this guide.

### Registering a new OAuth Provider

While logged in as an Administrator, navigate to **Site Settings -> Authentication**.

This page list all registered providers, either Enabled or Disabled. To register a new provider, click **Add New** and fill the form with all the required information. If you're new to OAuth, we've prepared a [list of how to configure the most common providers](#oauth-common-providers).

<h3 id="oauth-testing">Testing</h3>

Before enabling any provider on Fider, we highly recommend that you keep it disabled and use the **Test button** to confirm it's working properly.

**Test button** becomes available after registering a new provider. Whenever clicked, Fider opens a popup and redirects you to the provider of your
choice to start the authentication process. Once authenticated, you'll be redirected back to Fider and a report will be presented. Once you're happy with the configuration,
you can enable it and make it available for everyone to use during the sign in process.


  <figure className="flex-1">
    
    <figcaption>A correctly configured OAuth</figcaption>
  </figure>
  <figure className="flex-1">
    
    <figcaption>How an incorrect configuration may look like</figcaption>
  </figure>


<h3 id="oauth-common-providers">Common Providers</h3>

#### Facebook

This is only required for self-hosted Fider. Our Cloud service already has Facebook enabled.

1. Create a new Facebook app at [https://developers.facebook.com/apps](https://developers.facebook.com/apps) and enable Facebook Login product
2. Take note of the **App ID** and an **App Secret** that you'll be given
3. Input **&lt;your-fider-site&gt;/oauth/facebook/callback** into **Valid OAuth Redirect URIs** field and change your Facebook app status to Live
4. Update your environment variable as follows
   - **OAUTH_FACEBOOK_APPID:** `use the App ID given by Facebook`
   - **OAUTH_FACEBOOK_SECRET:** `use the App Secret given by Facebook`

#### Google

This is only required for self-hosted Fider. Our Cloud service already has Google enabled.

1. Create a Google app at [https://console.developers.google.com](https://console.developers.google.com) by navigating to Credentials -> OAuth Client ID. Take note of the **Client ID** and **Client Secret** that you'll be given
2. Input **&lt;your-fider-site&gt;/oauth/google/callback** into **Authorized redirect URIs** field
3. Update your environment variable as follows
   - **OAUTH_GOOGLE_CLIENTID:** `use the Client ID given by Google`
   - **OAUTH_GOOGLE_SECRET:** `use the Client Secret given by Google`

<h4>GitHub</h4>

This is only required for self-hosted Fider. Our Cloud service already has GitHub enabled.

1. Create a GitHub app at [https://github.com/settings/applications/new](https://github.com/settings/applications/new). Use **&lt;your-fider-site&gt;/oauth/github/callback** as the callback URL during registration.
2. Take note of the **Client ID** and **Client Secret** that you'll be given
3. Update your environment variable as follows
   - **OAUTH_GITHUB_CLIENTID:** `use the Client ID given by GitHub`
   - **OAUTH_GITHUB_SECRET:** `use the Client Secret given by GitHub`

<h4>Microsoft Azure AD</h4>

1. Login to [https://portal.azure.com](https://portal.azure.com) and navigate to **Azure Active Directory -&gt; App Registrations**
2. Click on New Application Registration and create a new application. Give it a name, select Web app / API type and use your Fider site URL as the sign-on URL
3. Take note of the **Application ID** that you'll be given
4. Navigate to **Settings -> Keys** and generate a new key. We recommend that you set this key to never expire. Take note of the **Value** of this key
5. Fill Fider OAuth form as follows and then press Save
   - **Display Name:** Azure AD
   - **Client ID:** `use the Application ID given by Azure`
   - **Client Secret:** `use the Key Value you generated in Azure`
   - **Authorize URL:** https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/authorize
   - **Token URL:** https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
   - **Profile API URL:** https://graph.microsoft.com/v1.0/me
   - **Scope:** User.Read
   - **JSON Path ID:** id
   - **JSON Path Name:** displayName
   - **JSON Path Email:** mail
   - **Status:** Disabled
6. Find Azure AD on the list of OAuth providers and copy the callback URL
7. On Azure, navigate to your newly created **App > Authentication > Web > Redirect URIs** and replace existing URL with the copied callback URL from Fider
8. You can now [Test](#oauth-testing) this configuration

#### Twitch

1. Navigate to [https://dev.twitch.tv/console/apps](https://dev.twitch.tv/console/apps) and register your new Twitch App
2. Twitch requires you to input the OAuth Redirect URL upon registration. For now, just type any valid URL like http://example.org, we'll change this later
3. Find your app on the list and click Manage
4. Take note of the **Client ID** that is shown
5. Click on **New Secret** and take note of **Client Secret** as well
6. Fill Fider OAuth form as follows and then press Save
   - **Display Name:** Twitch
   - **Client ID:** `use the Client ID given by Twitch`
   - **Client Secret:** `use the Client Secret given by Twitch`
   - **Authorize URL:** https://id.twitch.tv/oauth2/authorize
   - **Token URL:** https://id.twitch.tv/oauth2/token
   - **Profile API URL:** https://id.twitch.tv/oauth2/userinfo
   - **Scope:** user:read:email openid
   - **JSON Path ID:** sub
   - **JSON Path Name:** preferred_username
   - **JSON Path Email:** email
   - **Status:** Disabled
7. Find Twitch on the list of OAuth providers and copy the callback URL
8. On Twitch, navigate to your newly created App, click manage and replace existing **OAuth Redirect URL** with the copied callback URL from Fider
9. You can now [Test](#oauth-testing) this configuration

#### Discord

1. Navigate to [https://discord.com/developers/applications](https://discord.com/developers/applications) and click on Create on aplication
2. Change your App Name and take note of the **Client ID** that is shown
3. Under Client Secret, click on **click to reveal** and take note of **Client Secret** as well
4. Fill Fider OAuth form as follows and then press Save
   - **Display Name:** Discord
   - **Client ID:** `use the Client ID given by Discord`
   - **Client Secret:** `use the Client Secret given by Discord`
   - **Authorize URL:** https://discord.com/api/oauth2/authorize
   - **Token URL:** https://discord.com/api/oauth2/token
   - **Profile API URL:** https://discord.com/api/users/@me
   - **Scope:** identify email
   - **JSON Path ID:** id
   - **JSON Path Name:** username
   - **JSON Path Email:** email
   - **Status:** Disabled
5. Find Discord on the list of OAuth providers and copy the callback URL
6. On Discord, navigate to your newly created **App -> OAuth2 -> Redirects**, click Add Redirect, paste the callback URL from Fider and hit Save Changes
7. You can now [Test](#oauth-testing) this configuration

#### GitLab

1. Navigate to [https://gitlab.com/oauth/applications](https://gitlab.com/oauth/applications)
2. Input an application name, for example, Fider
3. GitLab requires you to input the OAuth Redirect URL upon registration. For now, just type any valid URL like http://example.org, we'll change this later
4. Select **read_user** on the list of scopes
5. After saving, take note of the **Application Id** and **Secret** that is shown
6. Fill Fider OAuth form as follows and then press Save
   - **Display Name:** GitLab
   - **Client ID:** `use the Application Id given by GitLab`
   - **Client Secret:** `use the Secret given by GitLab`
   - **Authorize URL:** https://gitlab.com/oauth/authorize
   - **Token URL:** https://gitlab.com/oauth/token
   - **Profile API URL:** https://gitlab.com/api/v4/user
   - **Scope:** read_user
   - **JSON Path ID:** id
   - **JSON Path Name:** name
   - **JSON Path Email:** email
   - **Status:** Disabled
7. Find GitLab on the list of OAuth providers and copy the callback URL
8. On GitLab, navigate to your newly created application, click Edit and replace the Redirect URL with the copied callback URL from Fider
9. You can now [Test](#oauth-testing) this configuration

#### Twitter

Unfortunately Twitter doesn't fully implement the OAuth2 protocol and the authorization flow. This means we cannot use this process to add Twitter authentication to Fider.

If you'd like to use Twitter as a sign in method for your site, please cast your vote on [Add Twitter as authentication method](https://feedback.fider.io/ideas/1/add-twitter-as-authentication-method) as this requires internal changes to Fider.

---

## File: hosting-instance.mdx

### Prerequisites

##### Docker [https://docs.docker.com/engine/install](https://docs.docker.com/engine/install)

As we don't distribute Linux or Windows specific binaries, Docker is a must to host Fider. It provides a consistent runtime environment and is widely supported by many cloud providers. You can run it standalone or in a container orchestration.

##### Docker Compose [https://docs.docker.com/compose/install](https://docs.docker.com/compose/install)

This installation guide uses Docker Compose to simplify the setup of containers.

##### PostgreSQL 12+ Database

Although Fider works on PostgreSQL 9.6, we recommend using PostgreSQL 12+. This guide uses Postgres inside a container for simplicity, but it's possible to install it on the host virtual machine or a different machine.

##### E-mail Sender

You can choose between a **SMTP Server** or a **[Mailgun](https://www.mailgun.com)** account.

### Installing and Running

##### Step 1: Create a docker compose file

Create a `/var/fider` folder and copy content below into a file `/var/fider/docker-compose.yml`. Read the inline comments to know what each setting is used for and modify them appropriately.

```
services:
  db:
    restart: always
    image: postgres:12
    volumes:
      - /var/fider/pg_data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: fider
      POSTGRES_PASSWORD: s0m3g00dp4ssw0rd
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U fider"]
      interval: 10s
      timeout: 5s
      retries: 5
  app:
    restart: always
    image: getfider/fider:stable
    ports:
      - "80:3000"
    environment:
      # Public Host Name
      BASE_URL: http://localhost

      # Connection string to the PostgreSQL database
      DATABASE_URL: postgres://fider:s0m3g00dp4ssw0rd@db:5432/fider?sslmode=disable

      # Generate a secure secret, for example using https://jwtsecret.com
      JWT_SECRET: VERY_STRONG_SECRET_SHOULD_BE_USED_HERE

      # From which account e-mails will be sent
      EMAIL_NOREPLY: noreply@yourdomain.com

      ###
      # EMAIL
      # Either EMAIL_MAILGUN_* or EMAIL_SMTP_* or EMAIL_AWSSES_* is required
      ###

      # EMAIL_MAILGUN_API: key-yourkeygoeshere
      # EMAIL_MAILGUN_DOMAIN: yourdomain.com
      # EMAIL_MAILGUN_REGION: US

      # EMAIL_SMTP_HOST: smtp.yourdomain.com
      # EMAIL_SMTP_PORT: 587
      # EMAIL_SMTP_USERNAME: user@yourdomain.com
      # EMAIL_SMTP_PASSWORD: s0m3p4ssw0rd
      # EMAIL_SMTP_ENABLE_STARTTLS: 'true'

      # EMAIL_AWSSES_REGION: us-east-1
      # EMAIL_AWSSES_ACCESS_KEY_ID: youraccesskeygoeshere
      # EMAIL_AWSSES_SECRET_ACCESS_KEY: yoursecretkeygoeshere
    depends_on:
      db:
        condition: service_healthy
      smtp:
        condition: service_started
```

Pay close attention to the BASE_URL field; ensure it is set to the correct public URL and that the HOST is correct (https/http).

The Docker Compose file above defines two services: `db` and `app`. In case you're using an external Postgres database, remove the db service and replace `DATABASE_URL` environment variable with your connection string.

##### Step 2: Pull the images and run it

Open your favorite terminal, navigate to `/var/fider` and run

```
docker compose pull
docker compose up -d
```

> **Important!** If you see messages like `Error: dial tcp :5432: connect: connection refused`. Don't panic, that's expected when using PostgreSQL in Docker. That happens when the application starts before the database is still ready.

You can find the logs by using `docker compose logs app`. The message `http server started on :3000` means everything is ok and you're ready to go.

Just open your favorite browser and navigate to [http://localhost](http://localhost). You should see a page like the following.

<figure>
  
  <figcaption>Installation page of a clean Fider instance</figcaption>
</figure>

### Use a testing SMTP server

You need a valid SMTP server to start the application, or you will see `panic: could not find environment variable named 'EMAIL_SMTP_HOST'` errors.

If you don't have one and just want to test, you can use [MailHog](https://github.com/mailhog/MailHog). Add a new service to your docker-composer.yml, and configure it:

```patch
  app:
    environment:
      # use this EMAIL config:
      EMAIL_SMTP_HOST: mailhog
      EMAIL_SMTP_PORT: 1025

  # add this service:
  mailhog:
    image: mailhog/mailhog
    restart: always
    ports:
      - "8025:8025"
```

Then restart docker compose. You can now browse to [http://localhost:8025](http://localhost:8025) and read mails sent by fider, especially the sign-in link.

### Secure Fider with HTTPS

When exposing Fider to the internet, it's strongly recommended to setup HTTPS. Take a look at [How to enable TLS/SSL](/docs/how-to-enable-ssl) to learn multiple ways on how to do that.

### F.A.Q.

##### I have submitted the installation form, but I haven't got any confirmation email

Start with your Spam folder, it shouldn't be there, but just be sure about that first. If not, it's highly likely that you either input the wrong email or your email configurations are invalid. When this happens, you'll notice that you can't fill in that form again as you'll be presented with a 404 page. This page will only go away when you click the confirmation link that Fider sends.

To solve this you'll need to log into your Postgres Database and run `TRUNCATE TABLE tenants RESTART IDENTITY CASCADE;`. This command will purge all the data from Fider, thus making the installation page available again. You may now change your email configurations and try again. You can repeat this as much as you need.

---

## File: hosting-on-azure.mdx

### Prerequisites

##### An [Azure](https://azure.microsoft.com/en-us/) subscription

It's free to start, but will require a variable monthly payment afterwards.

##### E-mail Sender

You can choose between a **SMTP Server** or a **[Mailgun](https://www.mailgun.com)** account.

### Deploying your instance

##### Step 1: Create a new PostgreSQL Database

Using Azure portal, crease a new instance of `Azure Database for PostgreSQL servers` using the [Official Guide](https://docs.microsoft.com/en-us/azure/postgresql/quickstart-create-server-database-portal).

<figure>
  
  <figcaption>Creating a new PostgreSQL Server</figcaption>
</figure>

The guide above also explains how to configure Firewall and create a Database using psql. Follow that process and create a database named `fider`.

```
CREATE DATABASE fider;
```

Alternatively, you can also install PostgreSQL on a Virtual Machine.

##### Step 2: Create an Azure App Service

**Azure App Service** (also known as Azure Web App) is where the actual application will be hosted. Using Azure portal again, search for Azure App Service and create a new instance.

We recommend using Linux and Basic B1 at a minimum, but if you're expecting higher traffic, upgrade to a more suitable tier.

<figure>
  
  <figcaption>Creating an Azure App Service</figcaption>
</figure>

<figure>
  
  <figcaption>Docker Settings</figcaption>
</figure>

##### Step 3: Configure your App

Select **Configuration** on your App Service blade and add the following Application Settings:

- `DATABASE_URL`: {`postgresql://{POSTGRES_SERVER}.postgres.database.azure.com:5432/fider?user={DB_USERNAME}@{POSTGRES_SERVER}&password={DB_PASSWORD}&sslmode=require`}
- `BASE_URL`: https://yourapplicationame.azurewebsites.net
- `JWT_SECRET`: It's a secret key used for authentication tokens, you can generate a good secret using an online tool like [this one](https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx) (take at least 512-bit for security).
- `EMAIL_NOREPLY`: Set this variable to a no-reply address associated to your instance.
- `EMAIL_MAILGUN_API`: Your Mailgun API key.
- `EMAIL_MAILGUN_DOMAIN`: Set this variable to your Mailgun domain.

<figure>
  
  <figcaption>Application Settings</figcaption>
</figure>

**If you're using plain SMTP to send emails**, you need to replace `MAILGUN_*` variables by the equivalent SMTP variables: `EMAIL_SMTP_HOST`, `EMAIL_SMTP_PORT`, `EMAIL_SMTP_USERNAME`,`EMAIL_SMTP_PASSWORD`.

Save your Application Settings.

##### Step 4: That's it!

It might take a few seconds for the application to restart and load all the new settings. Once that's done, open `https://{your_appname}.azurewebsites.net` and you should see the signup screen to create your Administrator account, and you can enjoy your Fider instance and share it with your users.

<figure>
  
  <figcaption>Installation page of a clean Fider instance</figcaption>
</figure>

---

## File: hosting-on-heroku.mdx

### Prerequisites

##### A [Heroku](https://www.heroku.com) account

It's totally free to sign up, and will allow you to deploy your application for free on a small instance.

##### E-mail Sender

You can choose between a **SMTP Server** or a **[Mailgun](https://www.mailgun.com)** account.

### Deploying your instance

##### Step 1: Create a new heroku app

Click the upper left button to create a new application. You will be prompted for an app name, you can choose anything you want. You also need to choose the hosting region, choose the one closest to you or your users.

<figure>
  
  <figcaption>Creating a new app on Heroku</figcaption>
</figure>

##### Step 2: add a database to the application

Under the **Resources** tab, in the **Add-ons** section, search and add the **Heroku Postgres** add-on to provide a database for your instance. When prompted for the Plan Name, you can leave the default **Hobby Dev - Free** selected and click **Provision**.

<figure>
  
  <figcaption>Provisioning the Postgresql database</figcaption>
</figure>

##### Step 3: add buildpacks

Buildpacks are Heroku's scripts that are run when an app is deployed, they are used to "build" your app, usually install dependencies and compile code. For Fider you need two buildpacks: go and nodejs. Under the **Settings** tab, in the **Buildpacks** section, click on **Add buildpack**, click on the **go** button and then on **Save changes** on the dialog.

<figure>
  
  <figcaption>Adding the Go buildpack</figcaption>
</figure>

Repeat the operation with the **nodejs** buildpack. You should now have two buildpacks listed in this section.

##### Step 4: configure application

In the **Config Vars** section of the **Settings** tab, click on **Reveal Config Vars** to display the current environment variables set on your application. You should already have one `DATABASE_URL` variable set. Don't touch it, it was automatically set by Heroku when you provisioned your database. You need to add some values for the Fider instance to work properly:

- `BASE_URL`: https://yourapplicationame.herokuapp.com
- `JWT_SECRET`: It's a secret key used for authentication tokens, you can generate a good secret using an online tool like [this one](https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx) (take at least 512-bit for security).
- `EMAIL_NOREPLY`: Set this variable to a no-reply address associated to your instance.
- `EMAIL_MAILGUN_API`: Your Mailgun API key.
- `EMAIL_MAILGUN_REGION`: Set to US or EU. Use capital letters only, defaults to US.
- `EMAIL_MAILGUN_DOMAIN`: Set this variable to your Mailgun domain.

<figure>
  
  <figcaption>Application environment variables.</figcaption>
</figure>

**If you're using plain SMTP to send emails**, you need to replace `MAILGUN_*` variables by the equivalent SMTP variables: `EMAIL_SMTP_HOST`, `EMAIL_SMTP_PORT`, `EMAIL_SMTP_USERNAME`,`EMAIL_SMTP_PASSWORD`.

##### Step 5: deploy your application

The easiest way to deploy your application to Heroku is to connect your application to a github repository. Fork the [Fider official repository](https://github.com/getfider/fider) and connect this fork to your Heroku application under the **Deploy** tab in the **Deployment method**.

<figure>
  
  <figcaption>Connecting your Github repository for deployment.</figcaption>
</figure>

You can now deploy your application by clicking on the **Deploy Branch** button. Once your app is deployed successfully, you can access the app online by clicking the **View** button.

<figure>
  
  <figcaption>Successfull deployment of your application.</figcaption>
</figure>

That's it! You should see the signup screen to create your Administrator account, and you can enjoy your free Fider instance and share it with your users.

**Reminder:** To keep your instance always up to date with latest features and fixes, update your fork every once in a while.

---

## File: how-to-enable-ssl.mdx

There are three options on how to configure SSL/TLS on your Fider instance.

### 1. HTTPS with a Reverse Proxy

This is often the most popular option as multiple reverse proxy supports TLS termination and various other useful features.
It's beyond the scope of this page to explain how to set it up, but these are the most popular options:

- https://traefik.io
- https://caddyserver.com
- https://nginx.com

### 2. Automatic HTTPS with Let's Encrypt

Fider integrates with [Let's Encrypt](https://letsencrypt.org/) natively, so you can have TLS without installing anything else or buying your own certificate.

To enable it:

1. Ensure your app is NOT behind a proxy.
2. Add the SSL_AUTO to your docker-compose.yml
3. Restart your application.

```
version: '2'
services:
  db:
    ...
  app:
    ports:
      - "80:80"
      - "443:3000"
    environment:
      ...
      SSL_AUTO: "true"
```

It can take a few seconds on the initial request to generate a certificate, but after visiting your site, you'll should see the green lock and the certificate generated for you.

**NOTE**: You must enable firewall access on port 80 and 443. Fider will redirect all traffic from HTTP to HTTPS.

### 3. HTTPS with your own certificate

You can also buy (or generate) a certificate and use it on Fider. Copy your `.crt` and `.key` files into `/var/fider/etc/`, add the following to your docker-compose.yml and restart your application.

```
version: '2'
services:
  db:
    ...
  app:
    ports:
      - "443:3000"
    environment:
      ...
      SSL_CERT: filename.crt
      SSL_CERT_KEY: filename.key
    volumes:
      - /var/fider/etc:/app/etc
```

---

## File: how-to-show-legal-pages.mdx

Starting from Fider 0.13, it is now possible host custom Privacy Policy and Terms of Service that will be displayed to all users during the registration and sign in process.

### Prerequisites

You will need both documents written in a markdown format, they **need** to be named `terms.md` and `privacy.md`.

### How to

Fider's Docker image expects both file to be available on `/app/etc`. You can copy these files anywhere you want on your server and share them with your Docker container by using [volumes](https://docs.docker.com/storage/volumes/).

For example, if your files are inside `/home/me/fider`, you can map it to the container with `-v /home/me/fider:/app/etc`.

---

## File: using-webhooks.mdx

Webhooks are a powerful integration feature that allow you to propagate events from Fider to other applications.

Events happens when users interact on Fider. Four types of events currently exists, but more of them could be created in the future.

Webhooks are highly customizable and you can create as many webhooks as you need for each event type.

### Create a new Webhook

While logged in as an Administrator, navigate to **Site Settings -> Webhooks**.

This page list all created Webhooks, either Enabled or Disabled. To create a new one, click **Add New** and fill the form with all the required information as explained on the section below.

<figure className="flex-1">
  
  <figcaption>The admin control panel to manage your Webhooks</figcaption>
</figure>

<h3 id="webhook-configuration">Webhook configuration</h3>

The power of this feature reside in its customization. Each Webhook has a name for you to quickly recognize it, a type defining its trigger event, a status
so you can enable or disable it, an URL and a content both formattable using Go templates, an HTTP method used to perform the request and even a set of
additional HTTP headers.

<figure className="flex-1">
  
  <figcaption>The Webhook creation form</figcaption>
</figure>

#### Name

The name is used in the admin control panel to identify the Webhook. You may give the name you want, it'll never get shown to users or sent in the request.
It do not needs to be unique: a unique ID display with a `#` symbol is always included with the name so you can distinguish two Webhooks with the same name.

#### Type

The type define which event will trigger this Webhook. It's also used to categorize them on the admin control panel. As new events could be added in future,
this attribute is subject to modification.

#### Status

The status define whether the Webhook is active or not. We highly recommend you to [test](#webhook-testing) your Webhook before
enabling it. When the execution of a Webhook fails, it'll automatically get disabled until you edit and fix it.

#### URL

The URL is one of the most important parts in the Webhook definition. Indeed, it is part of the definition of the HTTP request that this Webhook perform.
This is usually defined by your targeted application, and you must refer to its documentation to know how to get one.
See the list of [common Webhook targets](#common-webhook-targets-documentation) that you probably want to integrate with below to get some help with them.

#### Content

The content is the main element in your Webhook. You define here the data sent as HTTP request body. In most cases, the payload will include information
about the event that triggered it. Just like the URL, you can also use [Go template formatting](#writing-go-templates) here. Do not hesitate to check the integrated
help section by clicking on the information icon next to it. Take a look at the **Preview** zone to see what would your request contains with example data.

#### HTTP Method

This is the [HTTP request method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) of the request triggered by the Webhook. In most cases, when sending
data in the **Content**, the HTTP method will be `POST`. Check your targeted application's documentation to be sure.

#### HTTP Headers

You can add any [HTTP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) you want here. Each header have a name and a value, and you cannot
define the same header twice. The most common headers are:

- `Content-Type`: use it to tell your application the MIME type of the data represented in your **Content**. Common values are: `application/json`, `text/plain`,
  `application/x-www-form-urlencoded`, `application/xml`...
- `Authorization`: use it to authenticate with given credentials.

<h3 id="writing-go-templates">Writing Go templates (for your Webhook URL and content)</h3>

#### The preview field

When writing templates, a preview is available before saving you check when it'll look like. Use it as many times as you need!

<figure className="flex-1">
  
  <figcaption>An example of the preview field</figcaption>
</figure>

#### Presentation

[Go templates][go-template-doc] are a way to customize a text using external values (also called here "properties"). The engine used here is the
native `text/template` Go package. This is a powerful engine, but creating a basic templates is not complicated. You can write text as you want and insert a
property name, prefixed by a dot, enclosed in double braces with space within to place its value. For example, this is the most basic template with some values:

**Template**

```gotemplate
A new post entitled "{{ .post_title }}" has been created by {{ .author_name }}.
```

**Rendered text**

```
A new post entitled "Example dummy post title" has been created by Test.
```

In addition to properties, you can also use "functions", which are really useful to perform operations on values before they got inserted in the text. Example:
_(Read more about time formatting [here][go-time-format])_

**Template**

```gotemplate
The post was created on {{ format "Monday, 02 Jan 2006 at 15:04:05" .post_created_at }}.
```

**Rendered text**

```
The post was created on Friday, 07 May 2021 at 18:42:27.
```

To adapt the content dynamically depending on a property's value, you can even use "control structures", such as conditions and loops!
For example, you may add an element for post tags (also note the use of the minus sign `-` to trim lisibility white spaces):

**Template**

```gotemplate
The post have {{ if len .post_tags -}}
  {{ len .post_tags }} tag {{- if gt (len .post_tags) 1 -}} s {{- end }}:
  {{- range .post_tags }} {{ . }} {{- end -}}
{{- else -}}
  no tag
{{- end }}.
```

**Rendered text**

Post with tags

```
The post have 2 tags: tag1 tag2.
```

Post without tag

```
The post have no tag.
```

When using function call result as another function's argument, don't forget to parenthesis the expression: `{{ quote (format "15:04:05" .post_created_at) }}`.
You can also use a pipe character (`|`) to chain calls: `{{ .post_created_at | format "15:04:05" | quote }}` or `{{ format "15:04:05" .post_created_at | quote }}`.

Since the double braces are special characters in templates, if you need to insert them in your text, use the following trick: `{{ "{{" }}`. Do not hesitate
to consult the [official Go documentation][go-template-doc] about templates to see what are the possibilities.

#### Security disclaimer

You should always keep in mind user content may be insecure! Posts title and description, comments or users name are free text directly from the users.
You need to properly encode values like that when using them in JSON fields for example. The following example is a **bad** configuration:

```gotemplate
{
  "message": "{{ .post_description }}"
}
```

A malicious user could create a post with this description:

```gotemplate
Hacked!",
"important": true,
"from": "admin
```

When the template will be executed, the final result will look like:

```json
{
  "message": "Hacked!",
  "important": true,
  "from": "admin"
}
```

The targeted application may interpret the `"important": true` as a message requiring a notification and use the `from` field to set the sender. Thus, people
will receive a notification for a message from the admin saying "Hacked!". Pretty scary.

Please avoid these trouble and use the safety functions like `quote`, `escape`, `urlquery`, `stripHtml`...

The correct configuration would be (note the external quotes have been removed too):

```gotemplate
{
  "message": {{ quote .post_description }}
}
```

#### List of properties and functions

You can find theses information in the integrated help by clicking on the information icon next to the **URL** and **Content** fields.

##### Properties

| Property name                 | Example value                                                                                                                                                                                                                                                                                   |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `author_avatar`               | https://yourapp.fider.io/static/avatars/letter/1/Test                                                                                                                                                                                                                                           |
| `author_email`                | test@test.fr                                                                                                                                                                                                                                                                                    |
| `author_id`                   | 1                                                                                                                                                                                                                                                                                               |
| `author_name`                 | Test                                                                                                                                                                                                                                                                                            |
| `author_role`                 | administrator                                                                                                                                                                                                                                                                                   |
| `comment`                     | An example \*\*comment\*\* on a post.                                                                                                                                                                                                                                                           |
| `post_author_avatar`          | https://fider.io/images/logo-100x100.png                                                                                                                                                                                                                                                        |
| `post_author_email`           | contact@fider.io                                                                                                                                                                                                                                                                                |
| `post_author_id`              | 7                                                                                                                                                                                                                                                                                               |
| `post_author_name`            | Fider                                                                                                                                                                                                                                                                                           |
| `post_author_role`            | visitor                                                                                                                                                                                                                                                                                         |
| `post_comments`               | 3                                                                                                                                                                                                                                                                                               |
| `post_created_at`             | 2021-05-07T18:42:27Z                                                                                                                                                                                                                                                                            |
| `post_description`            | {"\*Those data are fake.\*This is an example of a post, but don't worry, nothing was created on your Fider instance:It was just a test of a webhook trigger.You can use \`{{ markdown .post_description }}\` to parse \_\_Markdown\_\_ to \*\*HTML\*\* in post!"} |
| `post_id`                     | 36                                                                                                                                                                                                                                                                                              |
| `post_number`                 | 36                                                                                                                                                                                                                                                                                              |
| `post_old_status`             | open                                                                                                                                                                                                                                                                                            |
| `post_response`               | true                                                                                                                                                                                                                                                                                            |
| `post_response_author_avatar` | https://yourapp.fider.io/static/avatars/letter/1/Test                                                                                                                                                                                                                                           |
| `post_response_author_email`  | test@test.fr                                                                                                                                                                                                                                                                                    |
| `post_response_author_id`     | 1                                                                                                                                                                                                                                                                                               |
| `post_response_author_name`   | Test                                                                                                                                                                                                                                                                                            |
| `post_response_author_role`   | administrator                                                                                                                                                                                                                                                                                   |
| `post_response_responded_at`  | 2021-07-09T15:29:57Z                                                                                                                                                                                                                                                                            |
| `post_response_text`          | This is a response, still in \*Markdown\*.                                                                                                                                                                                                                                                      |
| `post_slug`                   | example-dummy-post-title                                                                                                                                                                                                                                                                        |
| `post_status`                 | started                                                                                                                                                                                                                                                                                         |
| `post_tags`                   | tag1<hr />tag2                                                                                                                                                                                                                                                                                  |
| `post_title`                  | Example dummy post title                                                                                                                                                                                                                                                                        |
| `post_url`                    | https://yourapp.fider.io/posts/36/example-dummy-post-title                                                                                                                                                                                                                                      |
| `post_votes`                  | 7                                                                                                                                                                                                                                                                                               |
| `tenant_id`                   | 1                                                                                                                                                                                                                                                                                               |
| `tenant_locale`               | fr                                                                                                                                                                                                                                                                                              |
| `tenant_logo`                 | https://fider.io/images/logo-100x100.png                                                                                                                                                                                                                                                        |
| `tenant_name`                 | Testing                                                                                                                                                                                                                                                                                         |
| `tenant_status`               | active                                                                                                                                                                                                                                                                                          |
| `tenant_subdomain`            | yourapp                                                                                                                                                                                                                                                                                         |
| `tenant_url`                  | https://yourapp.fider.io                                                                                                                                                                                                                                                                        |

##### Functions

| Function    | Description                                                                          | Parameters<small>Type - Description</small>                                          |
| ----------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| `stripHtml` | Strip HTML tags from the input data                                                  | `string` - The input string containing HTML to strip                                       |
| `md5`       | Hash text using [MD5](https://en.wikipedia.org/wiki/MD5) algorithm                   | `string` - The input string to hash                                                        |
| `lower`     | Lowercase text                                                                       | `string` - The input string to lowercase                                                   |
| `upper`     | Uppercase text                                                                       | `string` - The input string to uppercase                                                   |
| `markdown`  | Parse [Markdown](https://en.wikipedia.org/wiki/Markdown) to HTML from the input data | `string` - The input string containing Markdown to parse                                   |
| `format`    | [Format][go-time-format] the given date and time                                     | `string` - The date format according to Go specifications<hr />`time` - The time to format |
| `quote`     | Enquote a string and escape inner special characters                                 | `string` - The input string to quote                                                       |
| `escape`    | Escape inner special characters of a string, without enquoting it                    | `string` - The input string to escape                                                      |
| `urlquery`  | Encode a string into a valid URL query element                                       | `string` - The input string to encode as URL query value                                   |

Don't forget to use the **Preview** field to help you experiment these functions!

<h3 id="webhook-trigger-failure-report">Webhook trigger failure report</h3>

This report is shown when a manual trigger of a Webhook goes wrong. It means your configuration is incorrect and you should not enable this Webhook now.
A failed Webhook is automatically disabled until you edit it. It is a good practice to always test it after each edition to ensure nothing was broken.

<figure className="flex-1">
  
  <figcaption>An extract of the failure report</figcaption>
</figure>

#### Understanding the report

There is a lot of informations included in the report and it may be disconcerting the first time you see it.

First, the **Message** indicates where the process was interrupted, and why. Then, the **Error** shows what went wrong and caused the trigger process to stop.
**URL** and **Content** are the parsed templates replaced with properties' values, helping you to understand the performed request.
The **Status code** is the [HTTP response status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) returned by the request.
**Properties** are every variables you can use in templates associated with their resolved values.

<h3 id="webhook-testing">Testing</h3>

Before enabling any your Webhook on Fider, we highly recommend that you keep it disabled and use the **Trigger button** to confirm it's working properly.

**Trigger button** becomes available after creating a new Webhook. Whenever clicked, an event of the appropriate type is simulated,
triggered only this Webhook. A notification in the upper-right corner of the screen indicate the result of the trigger. Once you're happy with the configuration,
you can enable it and it will be triggered automatically with real properties every time the selected event occurs.

The result can be either a success: everything was good and the HTTP request was executed successfully; or a failure: something went wrong during the process.
In case of a success, check your targeted application to confirm everyhing is OK, then you can enable your Webhook.
However, if it was a failure, a report will be available beside your Webhook's name, by clicking on this information icon.
Read more about [Webhook trigger failure reports](#webhook-trigger-failure-report) here.

#### Analyzing the message and error

Four error **messages** are possible:

1. _Could not parse webhook URL template_
2. _Could not parse webhook content template_
3. _Could not execute webhook HTTP request_
4. _Webhook HTTP request returned an error response code_

For each of these messages, the **error** field will bring more precise information about:

1. What was malformated in the **URL** template
2. What was malformated in the **Content** template
3. What prevented the HTTP request from being executed
4. What did the server respond to the request

#### Solving problems

In case of **1.** or **2.**, you should verify your templates and do not hesitate to take advantage of the **Preview** area in the Webhook edition form.
See [Writing Go templates](#writing-go-templates) for more information.

Regarding the **3.**, it become more subtle. If anything, from the request sending, to the response reading, fails, it will be this error.
First of all, verify manually the URL to check if you didn't made a spelling mistake in your app's domain name.
Also, try pasting this URL in your browser to see if the targeted application is alive.
On your application, be sure to reply and properly close the HTTP connection after Webhook handling.
If you're trying to reach the Internet from an internal network, ensure your server can emit request to your application.

Finally, concerning the **4.**, the request was correctly sent to your application, but it was invalid. This can be caused by an invalid **URL**,
an inappropriate **content**, or even a missing **HTTP header**. Please refer to your application's official documentation and try to start with
basic example (sending `Hello World` seems to be a good idea to begin your debugging session).

A special case of failing could be the malformation of the result produced by templates with some values.
Here are some recommendations about this:

- Properties passed as GET parameters in the URL query (i.e. after the `?`) should always be encoded using `urlquery`.
  ```gotemplate
  https://example.org/webhook/fider?author={{ urlquery .author_name }}
  ```
- When using a structured text format such as JSON, or any other format asking you to enquote an element, you should use the `quote` function.
  ```gotemplate
  {
    "title": {{ quote .post_title }}
  }
  ```

When you think your problem has been solved, don't forget to [test](#webhook-testing) your Webhook before enabling it!

<h3 id="common-webhook-targets-documentation">Common Webhook targets documentation</h3>

- Slack: [Generic Webhook documentation](https://slack.com/help/articles/115005265063-Incoming-webhooks-for-Slack), [Create the Webhook](https://api.slack.com/messaging/webhooks), [Webhook messages format](https://api.slack.com/messaging/composing)
- Discord: [Create the Webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks), [Webhook messages format](https://discord.com/developers/docs/resources/webhook)
- Microsoft Teams: [Create the Webhook](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook), [Webhook messages format](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL)

[go-template-doc]: https://pkg.go.dev/text/template
[go-time-format]: https://yourbasic.org/golang/format-parse-string-time-date-example/#standard-time-and-date-formats

---

## File: api/authentication.mdx

<h3 id="authentication">Authentication</h3>

Some API endpoint require authentication to work. This section explains how to make authenticated HTTP Requests to Fider.

The first step is to generate an API Key on your user profile. Sign in on Fider and navigate to **Settings -> API Key** and click on **Regenerate API Key**. An API Key will be shown. Take note of it as you won't be able to retrieve this key again. If your Key is lost or has been compromised, you can always repeat this process to generate a new Key.

API Key is only available for users with **Collaborator** or **Administrator** role. **Visitors** are not allowed to use any authenticated API endpoint.

With the API Key on hands, it's now possible to send authenticated requests the API using the **Authorization** HTTP Header as shown below.

```
Authorization: Bearer {api-key}
```

**Impersonation**

Every action performed via the API is executed under the User that generated the API Key. Fider also allow **Administrators** to impersonate another User and execute the operations under their behalf. To do so, add the following HTTP Header to the request.

```
Authorization: Bearer {api-key}
X-Fider-UserID: {target-user-id}
```

**Roles**

Fider has 3 user roles: `Visitor`, `Collaborator` and `Administrator`. These roles are used to restrict which actions each user can perform on the platform, be it via UI or via the API. Most operations can only be executed if the authenticated user has a specific role assigned. Every operation listed below will specify which role is required.

---

## File: api/best-practices.mdx

<h3 id="best-practices">Best Practices</h3>

**Service Account**

A common approach when using Fider API is to sign in with a generic email address (like `admin@yourcompany.com`), then switch to an Administrator user and promote the new user to an Administrator as well. This allows you to use a common user account on all API operations, without having to use a personal user account.

**How to properly use impersonation**

We usually recommend the usage of impersonation in combination with the [Create User](#create-user) API. This API will retrieve or create a new user and returns its User ID, which can then be used to impersonate that user.

As an example, imagine that you have a Mobile App that lists all your Fider posts and you want to let the user vote on it via your App. The first step is to call Create User with the name, email and an optional (altough recommended) reference ID. The API will the return a user ID. It might be a new user ID or an existing one, it doesn't matter. Call the [Add Vote](#add-vote) API with the `X-Fider-UserID` parameter to execute this action under that user account.

---

## File: api/comments.mdx

<h3 id="comments">Comments</h3>

- [List Comments](#list-comments)
- [Get a Comment](#get-comment)
- [Add a Comment](#add-comment)
- [Edit a Comment](#edit-comment)
- [Delete a Comment](#delete-comment)

<h4 id="list-comments">List Comments</h4>

- **Authentication:** Optional

```
GET /api/v1/posts/{number}/comments
```

**Parameters**

| Name     | Type     | Description                                                |
| -------- | -------- | ---------------------------------------------------------- |
| `number` | `number` | **Required.** The number of the post to get comments from. |

**Example**

```
GET <baseURL>/api/v1/posts/47/comments
```

**Response**

```
[
  {
    "id":67,
    "content":"Sounds good, right?",
    "createdAt":"2017-07-26T04:15:22.72261Z",
    "user":{
      "id":54,
      "name":"Michael Jackson",
      "role":"visitor"
    }
  },
  {
    "id":68,
    "content":"Definitely. Just do it!",
    "createdAt":"2017-07-26T06:49:03.951383Z",
    "user":{
      "id":23,
      "name":"Darth Vader",
      "role":"visitor"
    },
    "editedAt":"2018-09-29T17:37:59.516909Z",
    "editedBy":{
      "id":1,
      "name":"Jon Snow",
      "role":"administrator"
    }
  }
]
```

<h4 id="get-comment">Get a Comment</h4>

- **Authentication:** Optional

```
GET /api/v1/posts/{number}/comments/{id}
```

**Parameters**

| Name     | Type     | Description                                          |
| -------- | -------- | ---------------------------------------------------- |
| `number` | `number` | **Required.** The number of the post to retrieve.    |
| `id`     | `number` | **Required.** The id of the comment to be retrieved. |

**Example**

```
GET <baseURL>/api/v1/posts/47/comments/68
```

**Response**

```
200 OK
---
{
  "id":68,
  "content":"Definitely. Just do it!",
  "createdAt":"2017-07-26T06:49:03.951383Z",
  "user":{
    "id":23,
    "name":"Darth Vader",
    "role":"visitor"
  },
  "editedAt":"2018-09-29T17:37:59.516909Z",
  "editedBy":{
    "id":1,
    "name":"Jon Snow",
    "role":"administrator"
  }
}
```

<h4 id="add-comment">Add a Comment</h4>

- **Authentication:** Required

```
POST /api/v1/posts/{number}/comments
```

**Parameters**

| Name      | Type     | Description                                              |
| --------- | -------- | -------------------------------------------------------- |
| `number`  | `number` | **Required.** The number of the post to add the comment. |
| `content` | `string` | **Required.** The content of the comment.                |

**Example**

```
POST <baseURL>/api/v1/posts/47/comments
---
{
  "content": "Agreed, we'll soon need to act on this"
}
```

**Response**

```
200 OK
---
{
  "id":5675
}
```

<h4 id="edit-comment">Edit a Comment</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator.

```
PUT /api/v1/posts/{number}/comments/{id}
```

**Parameters**

| Name      | Type     | Description                                                  |
| --------- | -------- | ------------------------------------------------------------ |
| `number`  | `number` | **Required.** The number of the post that has given comment. |
| `id`      | `number` | **Required.** The id of the comment to be edited.            |
| `content` | `string` | **Required.** The new content of the comment.                |

**Example**

```
POST <baseURL>/api/v1/posts/47/comments/5675
---
{
  "content": "Agreed, we need to act on this as soon as possible"
}
```

**Response**

```
200 OK
---
{}
```

<h4 id="delete-comment">Delete a Comment</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator.

```
DELETE /api/v1/posts/{number}/comments/{id}
```

**Parameters**

| Name     | Type     | Description                                                  |
| -------- | -------- | ------------------------------------------------------------ |
| `number` | `number` | **Required.** The number of the post that has given comment. |
| `id`     | `number` | **Required.** The id of the comment to be edited.            |

**Example**

```
DELETE <baseURL>/api/v1/posts/47/comments/5675
```

**Response**

```
200 OK
---
{}
```

---

## File: api/invitations.mdx

<h3 id="invitations">Invitations</h3>

- [Send a Sample](#send-sample)
- [Send an Invite](#send-invite)

<h4 id="send-sample">Send a Sample</h4>

Sample invitations are example of invitations emails that are sent to current authenticated user's email. Use it to see how the email looks like before sending to other users.

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator

```
POST /api/v1/invitations/sample
```

**Parameters**

| Name      | Type     | Description                                                                                                                                            |
| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `subject` | `number` | **Required.** The subject of the email to be sent.                                                                                                     |
| `message` | `string` | **Required.** The content of the email to be sent. The message must include the %invite% placeholder, which will be replaced a secure invitation link. |

**Example**

```
POST <baseURL>/api/v1/invitations/sample
---
{
  "subject": "Share your ideas and thoughts about Fider",
  "message": "Hi,\n\nAt **Fider** we take feedback very seriously, which is why we've launched a space where you can vote, discuss and share your ideas and thoughts about our products and services.\n\nWe'd like to extend an invite for you to join this community and raise awareness on topics you care about!\n\nTo join, click on the link below.\n\n%invite%\n\nRegards,\nFider"
}
```

**Response**

```
200 OK
---
{}
```

<h4 id="send-invite">Send an Invite</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator

```
POST /api/v1/invitations/send
```

**Parameters**

| Name         | Type               | Description                                                                                                                                            |
| ------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `recipients` | `array of strings` | **Required.** The list of email addresses to send an invite.                                                                                           |
| `subject`    | `string`           | **Required.** The subject of the email to be sent.                                                                                                     |
| `message`    | `string`           | **Required.** The content of the email to be sent. The message must include the %invite% placeholder, which will be replaced a secure invitation link. |

**Example**

```
POST <baseURL>/api/v1/invitations/send
---
{
  "recipients":["jon.snow@got.com","arya.stark@got.com"],
  "subject": "Share your ideas and thoughts about Fider",
  "message": "Hi,\n\nAt **Fider** we take feedback very seriously, which is why we've launched a space where you can vote, discuss and share your ideas and thoughts about our products and services.\n\nWe'd like to extend an invite for you to join this community and raise awareness on topics you care about!\n\nTo join, click on the link below.\n\n%invite%\n\nRegards,\nFider"
}
```

**Response**

```
200 OK
---
{}
```

---

## File: api/overview.mdx

<h3 id="overview">Overview</h3>

Welcome to the Fider API documentation.

The Fider API allows you to manage Posts and other data within your Fider instance in a simple, programmatic way using conventional HTTP requests. The endpoints are intuitive and powerful, allowing you to easily make calls to retrieve information or to execute actions.

**Version**

The **API v1** was introduced on Fider `v0.16.0`. Make sure you're running the latest version of Fider to leverage the API. All Cloud users on `fider.io` are already on the latest so you can start using it right now.

**Request**

Allowed HTTP Verbs are GET, POST, PUT and DELETE. All data must be sent as JSON.

Requests are sent to your Fider URL using the HTTP/HTTPS protocol.

| Hosting                  | URL                                                                                                                 | Protocol                   |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| Cloud                    | `https://<subdomain>.fider.io` or, if configured, your custom domain name (e.g: `https://feedback.yourcompany.com`) | HTTPS only                 |
| <nobr>Self-Hosted</nobr> | The URL you have configured                                                                                         | <nobr>HTTP or HTTPS</nobr> |

**Response**

Every response will be encoded with `application/json` and one of the following status code.

| Status Code                     | Description                                                                                                                       |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| 200 OK                          | Fider has accepted and processed your request, no error was encountered.                                                          |
| 400 Bad Request                 | Something is incorrect with your request, it might be missing a parameter or have an invalid value. See **Error Messages** below. |
| 403 Forbidden                   | API Key is not present or not allowed to perform the operation                                                                    |
| 404 Not Found                   | The resource you're looking for doesn't exist.                                                                                    |
| <nobr>500 Internal Error</nobr> | This generally indicates a server-side problem on Fider and it cannot fulfill your request currently.                             |

**Error Messages**

Every `400 Bad Request` response contains a JSON payload with details of what went wrong. Each `error (object)` contains a `message (string)` describing what is incorrect and may also contain a `field (string)` property. If the error object doesn't contain the field, that's a general error message.

```
{
  "errors": [
    {
      "field": "color",
      "message": "'dark' is an invalid color."
    },
    {
      "message": "A tag named 'suggestion' already exists."
    }
  ]
}
```

---

## File: api/posts.mdx

<h3 id="posts">Posts</h3>

- [List Posts](#list-posts)
- [Get a Post](#get-post)
- [Create a Post](#create-post)
- [Edit a Post](#edit-post)
- [Delete a Post](#delete-post)
- [Respond to a Post](#respond-post)

A **Post** is new topic created by a user on the Feedback Site, while it's usually a suggestion or feature request, sometimes it might also be a bug report or a complain.

<h4 id="list-posts">List Posts</h4>

- **Authentication:** Optional

```
GET /api/v1/posts
```

**Parameters**

| Name    | Type      | Description                                                                                                                                                                                   |
| ------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `query` | `string`  | The search keywords                                                                                                                                                                           |
| `view`  | `string`  | The filter and order to apply. Possible values are `all`, `recent`, `my-votes`, `most-wanted`, `most-discussed`, `planned`, `started`, `completed`, `declined` and `trending`. Default: `all` |
| `limit` | `integer` | The number of entries to return. Default: 30                                                                                                                                                  |
| `tags`  | `string`  | The list of tags to filter by. Separate multiple tags by ,                                                                                                                                    |

**Example**

```
GET <baseURL>/api/v1/posts?view=completed&query=open+links&limit=50
```

**Response**

```
200 OK
---
[
  {
    "id": 4315,
    "number": 65,
    "title": "Open links in new tab",
    "slug": "open-links-in-new-tab",
    "description": "When somebody pastes a link in the description of an item, it has to open link in a new tab so you don't lose focus in the app",
    "createdAt": "2018-05-16T13:50:34.579281Z",
    "user": {
      "id": 45642,
      "name": "Jon Snow",
      "role": "visitor"
    },
    "hasVoted": true,
    "votesCount": 34,
    "commentsCount": 0,
    "status": "completed",
    "response": {
      "text": "This is now available on `v0.14`. Links from any markdown text will open in a new tab.",
      "respondedAt": "2018-06-13T17:48:27.073178Z",
      "user": {
        "id": 8,
        "name": "Arya Stark",
        "role": "administrator"
      },
      "original": null
    },
    "tags": ["hard","critical"]
  },
  {
    ...
  }
]
```

<h4 id="get-post">Get a Post</h4>

- **Authentication:** Optional

```
GET /api/v1/posts/{number}
```

**Parameters**

| Name     | Type     | Description                                       |
| -------- | -------- | ------------------------------------------------- |
| `number` | `number` | **Required.** The number of the post to retrieve. |

**Example**

```
GET <baseURL>/api/v1/posts/65
```

**Response**

```
200 OK
---
{
  "id": 4315,
  "number": 65,
  "title": "Open links in new tab",
  "slug": "open-links-in-new-tab",
  "description": "When somebody pastes a link in the description of an item, it has to open link in a new tab so you don't lose focus in the app",
  "createdAt": "2018-05-16T13:50:34.579281Z",
  "user": {
    "id": 45642,
    "name": "Jon Snow",
    "role": "visitor"
  },
  "hasVoted": true,
  "votesCount": 34,
  "commentsCount": 0,
  "status": "completed",
  "response": {
    "text": "This is now available on `v0.14`. Links from any markdown text will open in a new tab.",
    "respondedAt": "2018-06-13T17:48:27.073178Z",
    "user": {
      "id": 8,
      "name": "Arya Stark",
      "role": "administrator"
    },
    "original": null
  },
  "tags": ["hard","critical"]
}
```

<h4 id="create-post">Create a Post</h4>

- **Authentication:** Required

```
POST /api/v1/posts
```

**Parameters**

| Name          | Type     | Description                          |
| ------------- | -------- | ------------------------------------ |
| `title`       | `string` | **Required.** The title of the post. |
| `description` | `string` | The description of the post.         |

**Example**

```
POST <baseURL>/api/v1/posts
---
{
  "title": "Allow users to edit any comment",
  "description": "This is useful to fix some minor typos or introduce more details"
}
```

**Response**

```
200 OK
---
{
  "id": 6848,
  "number": 47,
  "title": "Allow users to edit any comment",
  "slug": "allow-users-to-edit-any-comment"
}
```

<h4 id="edit-post">Edit a Post</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator

```
PUT /api/v1/posts/{number}
```

**Parameters**

| Name          | Type     | Description                                        |
| ------------- | -------- | -------------------------------------------------- |
| `number`      | `number` | **Required.** The number of the post to be edited. |
| `title`       | `string` | **Required.** The title of the post.               |
| `description` | `string` | The description of the post.                       |

**Example**

```
POST <baseURL>/api/v1/posts/47
---
{
  "title": "Allow users to edit their own comments",
  "description": "This is useful to fix some minor typos or introduce more details"
}
```

**Response**

```
200 OK
---
{}
```

<h4 id="delete-post">Delete a Post</h4>

- **Authentication:** Required
- **Required Role:** Administrator

```
DELETE /api/v1/posts/{number}
```

**Parameters**

| Name     | Type     | Description                                         |
| -------- | -------- | --------------------------------------------------- |
| `number` | `number` | **Required.** The number of the post to be deleted. |
| `text`   | `string` | The reason why this post is being deleted.          |

**Example**

```
DELETE <baseURL>/api/v1/posts/47
---
{
  "text": "this is spam!"
}
```

**Response**

```
200 OK
---
{}
```

<h4 id="respond-post">Respond to a Post</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator

```
PUT /api/v1/posts/{number}/status
```

**Parameters**

| Name             | Type     | Description                                                                                                                        |
| ---------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `number`         | `number` | **Required.** The number of the post to add a response.                                                                            |
| `status`         | `string` | **Required.**The new status of the post. Possible values are `open`, `planned`, `started`, `completed`, `declined` and `duplicate` |
| `text`           | `string` | An optional description of what is the status on this post. This is made visible to all visitors on the website.                   |
| `originalNumber` | `number` | The number of the post to merge this into. This parameter **Required** when status is duplicate.                                   |

**Example #1**

```
PUT <baseURL>/api/v1/posts/47/status
---
{
  "status": "declined",
  "text": "this is spam!"
}
```

**Example #2**

```
PUT <baseURL>/api/v1/posts/47/status
---
{
  "status": "duplicate",
  "originalNumber": 84
}
```

**Response**

```
200 OK
---
{}
```

---

## File: api/tags.mdx

<h3 id="tags">Tags</h3>

- [List Tags](#list-tags)
- [Create a Tag](#create-tag)
- [Edit a Tag](#edit-tag)
- [Delete a Tag](#delete-tag)
- [Tag a Post](#tag-post)
- [Untag a Post](#untag-vote)

<h4 id="list-tags">List Tags</h4>

- **Authentication:** Optional

```
GET /api/v1/tags
```

The list of tags returned by this endpoint depends on the role of the authenticated user. Private Tags are only returned for users with either `administrator` or `collaborator` role.

**Example**

```
GET <baseURL>/api/v1/tags
```

**Response**

```
200 OK
---
[
  {
    "id": 8,
    "name": "Under Consideration",
    "slug": "under-consideration",
    "color": "87BE1F",
    "isPublic": true
  },
  {
    "id": 86,
    "name": "Hard",
    "slug": "hard",
    "color": "E60737",
    "isPublic": false
  }
]
```

<h4 id="create-tag">Create a Tag</h4>

- **Authentication:** Required
- **Required Role:** Administrator

```
POST /api/v1/tags
```

**Parameters**

| Name       | Type      | Description                                                   |
| ---------- | --------- | ------------------------------------------------------------- |
| `name`     | `string`  | **Required.** The display name of the tag.                    |
| `color`    | `string`  | **Required.** The Hex color of the tag (without #).           |
| `isPublic` | `boolean` | **Required.** true for public tags or false for private tags. |

**Example**

```
POST <baseURL>/api/v1/tags
---
{
  "name": "impact: big",
  "color": "FE422D",
  "isPublic": true
}
```

**Response**

```
200 OK
---
{
  "id": 1003,
  "name": "impact: big",
  "slug": "impact-big",
  "color": "FE422D",
  "isPublic": true
}
```

<h4 id="edit-tag">Edit a Tag</h4>

- **Authentication:** Required
- **Required Role:** Administrator

```
PUT /api/v1/tags/{slug}
```

**Parameters**

| Name       | Type      | Description                                                   |
| ---------- | --------- | ------------------------------------------------------------- |
| `slug`     | `string`  | **Required.** The slug of the tag to be edited.               |
| `name`     | `string`  | **Required.** The display name of the tag.                    |
| `color`    | `string`  | **Required.** The Hex color of the tag (without #).           |
| `isPublic` | `boolean` | **Required.** true for public tags or false for private tags. |

**Example**

```
PUT <baseURL>/api/v1/tags/impact-big
---
{
  "name": "impact: small",
  "color": "063589",
  "isPublic": true
}
```

**Response**

```
200 OK
---
{
  "id": 1003,
  "name": "impact: small",
  "slug": "impact-small",
  "color": "063589",
  "isPublic": false
}
```

<h4 id="delete-tag">Delete a Tag</h4>

- **Authentication:** Required
- **Required Role:** Administrator

```
DELETE /api/v1/tags/{slug}
```

**Parameters**

| Name   | Type     | Description                                      |
| ------ | -------- | ------------------------------------------------ |
| `slug` | `string` | **Required.** The slug of the tag to be deleted. |

**Example**

```
DELETE <baseURL>/api/v1/tags/impact-small
```

**Response**

```
200 OK
---
{}
```

<h4 id="tag-post">Tag a Post</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator

```
POST /api/v1/posts/{number}/tags/{slug}
```

**Parameters**

| Name     | Type     | Description                                          |
| -------- | -------- | ---------------------------------------------------- |
| `number` | `number` | **Required.** The number of the post to add the tag. |
| `slug`   | `string` | **Required.** The slug of the tag to be added.       |

**Example**

```
POST <baseURL>/api/v1/posts/47/tags/impact-big
```

**Response**

```
200 OK
---
{}
```

<h4 id="untag-vote">Untag a Post</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator

```
DELETE /api/v1/posts/{number}/tags/{slug}
```

**Parameters**

| Name     | Type     | Description                                             |
| -------- | -------- | ------------------------------------------------------- |
| `number` | `number` | **Required.** The number of the post to remove the tag. |
| `slug`   | `string` | **Required.** The slug of the tag to be removed.        |

**Example**

```
DELETE <baseURL>/api/v1/posts/47/tags/impact-big
```

**Response**

```
200 OK
---
{}
```

---

## File: api/users.mdx

<h3 id="users">Users</h3>

- [List Users](#list-users)
- [Create a User](#create-user)

<h4 id="list-users">List Users</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator

```
GET /api/v1/users
```

**Example**

```
GET <baseURL>/api/v1/users
```

**Response**

```
200 OK
---
[
  {
    "id": 3,
    "name": "Arya Stark",
    "role": "administrator",
    "status": "active",
  },
  {
    "id": 5,
    "name": "Jon Snow",
    "role": "visitor",
    "status": "active"
  },
  {
    "id": 24,
    "name": "The Queen",
    "role": "collaborator",
    "status": "blocked"
  },
  {
    ...
  }
]
```

<h4 id="create-user">Create a User</h4>

- **Authentication:** Required
- **Required Role:** Administrator

```
POST /api/v1/users
```

The Create User API will only create a new user if it cannot find an existing user with given email or reference ID. If the user already exists on Fider, the ID of the existing user is returned instead of creating a new user.

The ID returned by this API can be used to impersonate that user. Read more about [impersonation](#impersonation).

**Parameters**

| Name        | Type     | Description                                 |
| ----------- | -------- | ------------------------------------------- |
| `name`      | `string` | **Required.** The name of the user.         |
| `email`     | `string` | The email of the user.                      |
| `reference` | `string` | A unique ID for the user in another system. |

**Example**

```
POST <baseURL>/api/v1/users
---
{
  "name": "Jon Snow",
  "email": "jon.snow@got.com",
  "reference": "CRM-817453"
}
```

**Response**

```
200 OK
---
{
  "id": 6332
}
```

---

## File: api/votes.mdx

<h3 id="votes">Votes</h3>

- [Vote on a Post](#add-vote)
- [Remove Vote from a Post](#remove-vote)
- [List Votes of a Post](#list-post-votes)

<h4 id="add-vote">Vote on a Post</h4>

- **Authentication:** Required

When casting a vote upon a post, the vote is registered under the current authenticated user. Impersonate another user to vote on behalf of them.

```
POST /api/v1/posts/{number}/votes
```

**Parameters**

| Name     | Type     | Description                                      |
| -------- | -------- | ------------------------------------------------ |
| `number` | `number` | **Required.** The number of the post to vote on. |

**Example**

```
POST <baseURL>/api/v1/posts/47/votes
```

**Response**

```
200 OK
---
{}
```

<h4 id="remove-vote">Remove Vote from a Post</h4>

- **Authentication:** Required

When removing the vote from a post, the vote is removed from the current authenticated user. Impersonate another user to remove votes on behalf of them.

```
DELETE /api/v1/posts/{number}/votes
```

**Parameters**

| Name     | Type     | Description                                                    |
| -------- | -------- | -------------------------------------------------------------- |
| `number` | `number` | **Required.** The number of the post to have the vote removed. |

**Example**

```
DELETE <baseURL>/api/v1/posts/47/votes
```

**Response**

```
200 OK
---
{}
```

<h4 id="list-post-votes">List Votes of a Post</h4>

- **Authentication:** Required
- **Required Role:** Collaborator or Administrator

```
GET /api/v1/posts/{number}/votes
```

**Parameters**

| Name     | Type     | Description                                             |
| -------- | -------- | ------------------------------------------------------- |
| `number` | `number` | **Required.** The number of the post to list the votes. |

**Example**

```
GET <baseURL>/api/v1/posts/47/votes
```

**Response**

```
200 OK
---
[
  {
    "createdAt":"2018-11-28T12:18:26.95415Z",
    "user":{
      "id":1234,
      "name":"Jon Snow",
      "email":"jon.snow@got.com"
    }
  },
  {
    "createdAt":"2018-11-28T15:45:45.612288Z",
    "user":{
      "id":5678,
      "name":"Arya Stark",
      "email":"arya.stark@got.com"
    }
  }
]
```