---
title: "Operating your own Social Server"
manual: "fixpunkt/fp-social"
version: "main"
permalink: "https://docs.typo3.org/permalink/fixpunkt/fp-social:own-social-server@main"
source: "ForDevelopers/OwnSocialServer.rst"
modified: "2026-09-17T09:45:28+00:00"
---

# Operating your own Social Server

Access to the social networks is performed exclusively through a
*Social Server*. The extension itself never communicates directly with the
individual networks, but only sends requests to the Social Server configured in
the [extension settings](https://docs.typo3.org/permalink/fixpunkt/fp-social:social-server-settings@main).

By default, the SaaS service operated by fixpunkt is used. Costs may apply for
its use.

If you do not want to use this service, you can develop and operate your own
**Social Server**. Afterwards, enter its URL as `apiUrl` in the extension
settings. This chapter describes which interface such a server must provide.

## Authentication

All requests to the Social Server are `POST` requests to the respective
endpoint URL. This URL is composed of the configured `apiUrl` and the path of
the endpoint, e. g.:

```
https://my-server.example.com/api/ + networks/facebook/posts

```

The parameters are passed as `form_params` (`application/x-www-form-urlencoded`).
In addition to the endpoint-specific parameters, every request contains the
following fields:

| Parameter | Description |
| --- | --- |
| `version` | Version of the interface. Currently always `2`. This corresponds to the namespace `v2` of the classes mentioned further below. |
| `auth[username]` | The username stored in the access credentials. |
| `auth[accesstoken]` | The access token stored in the access credentials. |

The server is responsible for verifying `auth[username]` and
`auth[accesstoken]`. With your own server, you assign these credentials
yourself.

## Expected response format

The server's response must be a JSON that can be deserialized by the extension,
with the help of the extension `fixpunkt/fp-social-bridge`, into one of the
following response objects:

| Class | Usage |
| --- | --- |
| `Fixpunkt\FpSocialBridge\v2\Response\SocialServerPostsResponse` | Response for a list endpoint (multiple posts). |
| `Fixpunkt\FpSocialBridge\v2\Response\SocialServerPostResponse` | Response for an endpoint for a single post. |
| `Fixpunkt\FpSocialBridge\v2\Response\SocialServerErrorResponse` | Response in case of an error. |

The individual posts are expected as objects of type
`Fixpunkt\FpSocialBridge\v2\Data\Post`.

> [!IMPORTANT]
> The exact structure of these classes – and thus the exact structure of the
> JSON to be returned – is not documented here, but in the extension
> `fixpunkt/fp-social-bridge`. When implementing your server, use that
> extension as a reference.

## Endpoints

For each network, endpoints are needed for reading a list of posts as well as
for reading a single post. Each endpoint is described individually below.

The JSON examples each show the complete `POST` body including the
`version` and `auth` fields described under [Authentication](https://docs.typo3.org/permalink/fixpunkt/fp-social:authentication@main), so they can
be copied directly. Depending on the endpoint, the response is expected to be
either a list of posts (`SocialServerPostsResponse`) or a single post
(`SocialServerPostResponse`); the exact format is described in the section
[Expected response format](https://docs.typo3.org/permalink/fixpunkt/fp-social:expected-response-format@main).

> [!NOTE]
> You only need to implement those endpoints whose networks you actually want
> to use. If an account of an unsupported network is synchronized, only its
> synchronization fails.

### Facebook

#### `networks/facebook/posts`

Reads the posts of a Facebook page.

`POST` request to `networks/facebook/posts`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "pageId": "Facebook page ID"
}
```

-   `pageId` – ID of the Facebook page from which the posts are read.
    Corresponds to the channel stored in the account.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/facebook/post`

Reads a single Facebook post.

`POST` request to `networks/facebook/post`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "postId": "Post ID"
}
```

-   `postId` – ID of the post. Corresponds to the ID under which the post was
    stored when it was read.

**Response:** Single post (`SocialServerPostResponse`).

### Instagram

Depending on whether the account is operated in *Profile* or *Hashtag* mode,
either `networks/instagram/posts` or `networks/instagram/hashtag` is
requested to read the list.

#### `networks/instagram/posts`

Reads the posts of an Instagram profile (*Profile* mode).

`POST` request to `networks/instagram/posts`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "pageId": "Instagram profile ID"
}
```

-   `pageId` – ID of the Instagram profile from which the posts are read.
    Corresponds to the channel stored in the account.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/instagram/hashtag`

Reads posts for a hashtag (*Hashtag* mode).

`POST` request to `networks/instagram/hashtag`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "pageId": "Instagram profile ID",
    "hashtag": "fixpunkt",
    "mode": "recent_media"
}
```

-   `pageId` – ID of the Instagram profile through which the search is
    performed. Corresponds to the channel stored in the account.
-   `hashtag` – The hashtag to search for (without `#`).
-   `mode` – Search mode for the hashtag. Possible values:

    -   `recent_media` – the most recent posts for the hashtag.
    -   `top_media` – the top posts for the hashtag.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/instagram/post`

Reads a single Instagram post.

`POST` request to `networks/instagram/post`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "postId": "Post ID"
}
```

-   `postId` – ID of the post. Corresponds to the ID under which the post was
    stored when it was read.

**Response:** Single post (`SocialServerPostResponse`).

### Instagram (direct login)

Used for Instagram accounts that are connected through the direct Instagram
login instead of a Facebook page. Apart from the missing hashtag search, the
endpoints match those of [Instagram](https://docs.typo3.org/permalink/fixpunkt/fp-social:instagram@main).

#### `networks/instagramlogin/posts`

Reads the posts of the connected profile.

`POST` request to `networks/instagramlogin/posts`. The body is transmitted
as `form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "pageId": "Instagram account ID"
}
```

-   `pageId` -- ID of the Instagram account from which the posts are read.
    Corresponds to the channel stored in the account.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/instagramlogin/post`

Reads a single post.

`POST` request to `networks/instagramlogin/post`. The body is transmitted
as `form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "postId": "Post ID"
}
```

-   `postId` -- ID of the post. Corresponds to the ID under which the post was
    stored when it was read.

**Response:** Single post (`SocialServerPostResponse`).

### LinkedIn

Depending on whether the account is operated in *Shares* or *UGC Posts* mode,
either `networks/linkedin/posts` or `networks/linkedin/ugcPosts` is
requested to read the list.

#### `networks/linkedin/posts`

Reads the posts of a LinkedIn page (*Shares* mode).

`POST` request to `networks/linkedin/posts`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "pageId": "LinkedIn page ID"
}
```

-   `pageId` – ID of the LinkedIn page from which the posts are read.
    Corresponds to the channel stored in the account.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/linkedin/ugcPosts`

Reads the user-generated-content posts of a LinkedIn page
(*UGC Posts* mode).

`POST` request to `networks/linkedin/ugcPosts`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "pageId": "LinkedIn page ID"
}
```

-   `pageId` – ID of the LinkedIn page from which the posts are read.
    Corresponds to the channel stored in the account.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/linkedin/post`

Reads a single LinkedIn post.

`POST` request to `networks/linkedin/post`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "postId": "Post ID"
}
```

-   `postId` – ID of the post. Corresponds to the ID under which the post was
    stored when it was read.

**Response:** Single post (`SocialServerPostResponse`).

### Youtube

#### `networks/youtube/videos`

Reads the videos of a YouTube channel.

`POST` request to `networks/youtube/videos`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "channel": "YouTube channel ID"
}
```

-   `channel` – ID of the YouTube channel from which the videos are read.
    Corresponds to the channel stored in the account.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/youtube/video`

Reads a single YouTube video.

`POST` request to `networks/youtube/video`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "videoId": "Video ID"
}
```

-   `videoId` – ID of the video. Corresponds to the ID under which the video
    was stored when it was read.

**Response:** Single post (`SocialServerPostResponse`).

### Wordpress

Depending on the selected mode of the account, one of the following three
endpoints is requested to read the list.

#### `networks/wordpress/posts`

Reads all posts of a Wordpress blog.

`POST` request to `networks/wordpress/posts`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "baseUrl": "https://my-blog.example.com"
}
```

-   `baseUrl` – Base URL of the Wordpress blog from which the posts are read.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/wordpress/postsWithTag`

Reads the posts of a Wordpress blog that are tagged with a specific tag.

`POST` request to `networks/wordpress/postsWithTag`. The body is transmitted
as `form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "baseUrl": "https://my-blog.example.com",
    "tag": "Tag"
}
```

-   `baseUrl` – Base URL of the Wordpress blog.
-   `tag` – Tag by which the posts are filtered.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/wordpress/postsFromAuthor`

Reads the posts of a specific author of a Wordpress blog.

`POST` request to `networks/wordpress/postsFromAuthor`. The body is
transmitted as `form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "baseUrl": "https://my-blog.example.com",
    "author": "Author"
}
```

-   `baseUrl` – Base URL of the Wordpress blog.
-   `author` – Author by which the posts are filtered.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/wordpress/post`

Reads a single Wordpress post.

`POST` request to `networks/wordpress/post`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "postId": "Post ID",
    "baseUrl": "https://my-blog.example.com"
}
```

-   `postId` – ID of the post. Corresponds to the ID under which the post was
    stored when it was read.
-   `baseUrl` – Base URL of the Wordpress blog to which the post belongs.

**Response:** Single post (`SocialServerPostResponse`).

### Bluesky

#### `networks/bluesky/posts`

Reads the posts of a Bluesky profile.

`POST` request to `networks/bluesky/posts`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "clientHandle": "profil.bsky.social"
}
```

-   `clientHandle` – Handle of the Bluesky profile from which the posts are
    read. Corresponds to the channel stored in the account.

**Response:** List of posts (`SocialServerPostsResponse`).

#### `networks/bluesky/post`

Reads a single Bluesky post.

`POST` request to `networks/bluesky/post`. The body is transmitted as
`form_params` (`application/x-www-form-urlencoded`):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    },
    "uri": "at://…"
}
```

-   `uri` – AT URI of the post. Corresponds to the ID under which the post was
    stored when it was read.

**Response:** Single post (`SocialServerPostResponse`).

### Accounts

#### `accounts`

Lists all accesses that the user has connected on the server, grouped by
network. The backend uses this endpoint for the channel selection next to
**The Channel**; it is optional -- without it the channel simply has to
be entered by hand.

`POST` request to `accounts`. The body is transmitted as `form_params`
(`application/x-www-form-urlencoded`) and needs no arguments beyond the ones
described under [Authentication](https://docs.typo3.org/permalink/fixpunkt/fp-social:authentication@main):

```json
{
    "version": 2,
    "auth": {
        "username": "Your username",
        "accesstoken": "Your access token"
    }
}
```

**Response:** List of accesses (`SocialServerAccountsResponse`). The
`accounts` key is an object whose keys name the network and whose values are
lists of accesses:

```json
{
    "type": "Fixpunkt\\FpSocialBridge\\v2\\Response\\SocialServerAccountsResponse",
    "version": 2,
    "accounts": {
        "Fixpunkt\\FpSocialServer\\Networks\\Facebook\\Connector": [
            {
                "uid": 12,
                "network": "Fixpunkt\\FpSocialServer\\Networks\\Facebook\\Connector",
                "networkKey": "facebook",
                "networkName": "Facebook",
                "displayName": "Example Organization",
                "username": "100000000000001",
                "email": "office@example.com",
                "expires": null,
                "expired": false,
                "channels": [
                    {"id": "200000000000001", "name": "Example Page"}
                ]
            }
        ]
    }
}
```

-   `networkKey` -- short form of the network. The extension maps
    `facebook`, `instagram`, `instagramlogin` and `linkedin` to its own
    account types; accesses of any other network are ignored.
-   `channels[].id` -- the value that is written into the channel of an
    account, and that is expected back as `pageId` by the endpoints above.
-   `channels[].name` -- the value that is written into the label.
-   `expires` -- expiry date of the access, or `null` for networks whose
    access keys do not expire. `expired` says whether it has already passed.

> [!NOTE]
> Never return the access keys themselves here. The channels are meant for
> display and for filling in the account, not for authentication.

### Error handling

If an error occurs on the server, you have two options:

-   You respond with a JSON that can be deserialized into a
    `SocialServerErrorResponse`.
-   You respond with an HTTP error status (4xx) and a body in the following
    form:

    ```json
    {
        "error": {
            "message": "Error description",
            "code": 1652117377
        }
    }
    ```

In both cases, `message` and `code` are evaluated by the extension and
displayed in the backend as a synchronization error.

> [!TIP]
> If a single post was deleted in the network, return an error with the code
> `1585047168`. The extension then marks the corresponding post as deleted
> at the origin.
