# Listing posts

> Prepare a post of one of your listings for your own Instagram or LinkedIn, edit its caption and publish it.

The Listing posts API prepares a post of one of your agency's listings for your own connected Instagram (feed post or story) or LinkedIn, then publishes it when you say so. Fondaro renders the slides from the listing and writes the caption; nothing is posted without a person's action.

These endpoints take a signed-in member's session token (`Authorization: Bearer <session-token>`); API keys do not open them. See [Authentication](https://www.fondaro.com/docs/api/authentication.md).

Every post is your own: it goes out on an account you connected. Writes need an active plan, and a sandbox organization cannot publish. Scheduling a post for later and replying to comments on posts are not available yet.

## The post object

| Field | Type | Description |
|---|---|---|
| `id` | string | |
| `listing` | object | `ref` (`{ "source": "internal", "id" }`), `reference`, `location` |
| `account` | object or null | `id`, `kind` (`instagram` or `linkedin`), `address`, `status`; `null` once the account was removed |
| `channel` | string | `instagram` or `linkedin` |
| `kind` | string | `feed` or `story` (a story is Instagram only) |
| `linkedinOrganizationId` | string or null | LinkedIn only: the company page it goes out as; `null` posts as you |
| `caption` | string | At most 2,200 characters |
| `media` | array | `{ url, width, height }` per rendered slide, in posting order |
| `scheduledAt` | string or null | When it went out, or was claimed to go out |
| `status` | string | `draft`, `scheduled`, `publishing`, `published`, `failed` or `needs_reconnect` |
| `providerPostId`, `providerPostUrl` | string or null | Set once published |
| `createdBy` | string or null | User id; `null` when Fondaro drafted it |
| `createdAt`, `updatedAt` | string | ISO 8601 |

Fondaro also drafts posts on its own when one of your listings is first published or its price changes, on the listing agent's connected Instagram and LinkedIn. These stay drafts until a person publishes them.

## List your posts

`GET /listing-posts`

Your posts, newest first, at most 100.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `listingId` | Query | uuid | No | Only this listing's posts |
| `status` | Query | string | No | One of the statuses above |

```bash
curl "https://api.fondaro.com/listing-posts?listingId=2d3d0669-0dc5-4e80-b573-b543a59fcd29" \
  -H "Authorization: Bearer $SESSION_TOKEN"
```

```json
{
  "posts": [
    {
      "id": "7a1c2b3d-4e5f-4a6b-9c8d-0e1f2a3b4c5d",
      "listing": { "ref": { "source": "internal", "id": "2d3d0669-0dc5-4e80-b573-b543a59fcd29" }, "reference": "FDR-7KQ2MX9A", "location": "Estepona" },
      "channel": "instagram",
      "kind": "feed",
      "status": "draft",
      "caption": "Estepona. €1,250,000. Three terraces over the sea.",
      "media": [{ "url": "https://…/slide-1.jpg", "width": 1080, "height": 1350 }]
    }
  ]
}
```

`GET /listing-posts/:id` returns one post object.

## List your LinkedIn pages

`GET /listing-posts/linkedin-pages`

The LinkedIn company pages you can post as, read from your LinkedIn when you ask. Empty without a working LinkedIn connection.

```bash
curl "https://api.fondaro.com/listing-posts/linkedin-pages" \
  -H "Authorization: Bearer $SESSION_TOKEN"
```

```json
{ "pages": [{ "id": "12345678", "name": "Costa Homes" }] }
```

## Prepare a draft

`POST /listing-posts`

Renders the slides and caption for one of your organization's listings. Returns the post object with `status: "draft"`.

| Field | Type | Required | Description |
|---|---|---|---|
| `listingId` | uuid | Yes | One of your organization's listings |
| `channel` | string | Yes | `instagram` or `linkedin` |
| `kind` | string | No | `feed` (default) or `story`; a story is Instagram only |
| `language` | string | No | Caption language; defaults to your organization's first language |
| `linkedinOrganizationId` | string | No | A page `id` from `GET /listing-posts/linkedin-pages`; omit to post as you |

```bash
curl -X POST "https://api.fondaro.com/listing-posts" \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "listingId": "2d3d0669-0dc5-4e80-b573-b543a59fcd29", "channel": "instagram", "kind": "feed", "language": "es" }'
```

```json
{
  "id": "7a1c2b3d-4e5f-4a6b-9c8d-0e1f2a3b4c5d",
  "channel": "instagram",
  "kind": "feed",
  "status": "draft",
  "caption": "Estepona. 1.250.000 €. Tres terrazas sobre el mar.",
  "media": [{ "url": "https://…/slide-1.jpg", "width": 1080, "height": 1350 }],
  "createdBy": "user_2a"
}
```

A listing needs a price, a town, a public photo and an agency name to be posted.

## Edit a draft

`PATCH /listing-posts/:id`

Changes the caption, the format or the LinkedIn page. Allowed while the post is `draft`, `scheduled`, `failed` or `needs_reconnect`.

| Field | Type | Required | Description |
|---|---|---|---|
| `caption` | string | No | At most 2,200 characters |
| `kind` | string | No | `feed` or `story`; renders the slides again and keeps the caption |
| `linkedinOrganizationId` | string or null | No | A page id, or `null` to post as you |

```bash
curl -X PATCH "https://api.fondaro.com/listing-posts/7a1c2b3d-4e5f-4a6b-9c8d-0e1f2a3b4c5d" \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "caption": "Estepona. €1,250,000. Three terraces over the sea." }'
```

```json
{
  "id": "7a1c2b3d-4e5f-4a6b-9c8d-0e1f2a3b4c5d",
  "status": "draft",
  "caption": "Estepona. €1,250,000. Three terraces over the sea."
}
```

## Publish a post

`POST /listing-posts/:id/publish`

Publishes now from your own account. Answers once Instagram or LinkedIn has taken it (`published`), or with `failed` or `needs_reconnect`. If the network is busy the post is left `scheduled`; publish it again later. A `failed` post is never sent again unless you publish it.

```bash
curl -X POST "https://api.fondaro.com/listing-posts/7a1c2b3d-4e5f-4a6b-9c8d-0e1f2a3b4c5d/publish" \
  -H "Authorization: Bearer $SESSION_TOKEN"
```

```json
{
  "id": "7a1c2b3d-4e5f-4a6b-9c8d-0e1f2a3b4c5d",
  "status": "published",
  "providerPostUrl": "https://www.instagram.com/p/AbC123/"
}
```

An Instagram feed post goes out as the cover slide; a LinkedIn post carries up to four slides. Published posts appear on `GET /calendar` as items of kind `post`.

## Read engagement

`GET /listing-posts/:id/engagement`

Likes, comments and impressions of a published post, read from Instagram or LinkedIn when you ask and kept for five minutes. A count the network does not report is `null`; impressions are LinkedIn only. Returns `null` for a post that is not out, or whose account cannot be read now.

```bash
curl "https://api.fondaro.com/listing-posts/7a1c2b3d-4e5f-4a6b-9c8d-0e1f2a3b4c5d/engagement" \
  -H "Authorization: Bearer $SESSION_TOKEN"
```

```json
{ "likes": 42, "comments": 3, "impressions": null, "readAt": "2026-10-02T10:00:00.000Z" }
```

## Discard a post

`DELETE /listing-posts/:id`

Deletes a post that has not gone out, with its slides. Answers `204` with no body.

```bash
curl -X DELETE "https://api.fondaro.com/listing-posts/7a1c2b3d-4e5f-4a6b-9c8d-0e1f2a3b4c5d" \
  -H "Authorization: Bearer $SESSION_TOKEN"
```

## Errors

| Status | `code` | When |
|---|---|---|
| 400 | | A story on LinkedIn, a caption over 2,200 characters, a page you cannot post as, or a listing missing a price, town, public photo or agency name |
| 403 | | A publish from a sandbox organization |
| 403 | `SUBSCRIPTION_REQUIRED` | A write without an active plan |
| 404 | | Not one of your posts, or not one of your organization's listings |
| 409 | `LISTING_POST_NO_ACCOUNT` | You have no connected account on that channel |
| 409 | `LISTING_POST_NEEDS_RECONNECT` | Your account needs reconnecting; reconnect it, then publish again |
| 409 | `LISTING_POST_NOT_EDITABLE` | The post has already gone out |

Source: https://www.fondaro.com/docs/api/listing-posts
