POST
/
api
/
v1
/
current-home
/
me
/
publish
Publish listing
curl --request POST \
  --url https://api.example.com/api/v1/current-home/me/publish
import requests

url = "https://api.example.com/api/v1/current-home/me/publish"

response = requests.post(url)

print(response.text)
const options = {method: 'POST'};

fetch('https://api.example.com/api/v1/current-home/me/publish', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/current-home/me/publish",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"net/http"
"io"
)

func main() {

url := "https://api.example.com/api/v1/current-home/me/publish"

req, _ := http.NewRequest("POST", url, nil)

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/current-home/me/publish")
.asString();
require 'uri'
require 'net/http'

url = URI("https://api.example.com/api/v1/current-home/me/publish")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body

Overview

Transitions the caller’s listing status to LIVE. From this point the listing is visible to the matching engine and may appear as a candidate in other users’ match feeds. The server enforces four eligibility gates before transitioning. All four must be true; any failure returns 409 STATE_CONFLICT with a detail field naming the unmet condition so the client can render targeted guidance.
  1. users.onboardingStatus === "COMPLETE".
  2. users.tenancyStatus === "APPROVED" (set by the admin queue once the uploaded tenancy document has been reviewed — Phase 6 work).
  3. current_homes.photos.length >= 1.
  4. current_homes.description.length >= 100 (the 100..150-char window enforced by step-3-description).
The transition is allowed from DRAFT or HIDDEN (re-list). Publishing an already-LIVE listing is also permitted as an idempotent no-op (the gates still run, but the setStatus write is harmless).

Authentication

Bearer <accessToken> required. Scope: user.

Path parameters

None.

Query parameters

None.

Request body

None.

Response — 200 OK

Returns the updated Home object with status = LIVE.
{
  "home": {
    "id": "66400a8f1c2b4d5e6f7a8c00",
    "userId": "66400a8f1c2b4d5e6f7a8b00",
    "status": "LIVE",                                  // enum: "DRAFT" | "LIVE" | "HIDDEN" | "DELETED"
    "ownerOnboardingComplete": true,
    "ownerTenancyApproved": true,
    "updatedAt": "2026-05-22T14:32:08.412Z"
    // ...rest of the home shape (see GET /current-home/me)
  }
}

Error responses

StatusCodeMeaning
401UNAUTHENTICATEDMissing, malformed, or expired access token.
404NOT_FOUNDThe user has no current_homes listing yet, or the user record itself was not found.
409STATE_CONFLICTOne of the four eligibility gates failed. detail identifies which gate (Onboarding must be complete to publish, Tenancy verification must be APPROVED to publish, Add at least one photo before publishing, or Add a description (100..150 chars) before publishing).

Example error — 409 (tenancy not approved)

{
  "type": "https://api.swappr.co.uk/errors/state-conflict",
  "title": "State conflict",
  "status": 409,
  "code": "STATE_CONFLICT",
  "detail": "Tenancy verification must be APPROVED to publish",
  "instance": "/api/v1/current-home/me/publish",
  "requestId": "01HZQ7K3M4N5P6Q7R8S9T0V1W2"
}

Example error — 409 (no photos)

{
  "type": "https://api.swappr.co.uk/errors/state-conflict",
  "title": "State conflict",
  "status": 409,
  "code": "STATE_CONFLICT",
  "detail": "Add at least one photo before publishing",
  "instance": "/api/v1/current-home/me/publish",
  "requestId": "01HZQ7K3M4N5P6Q7R8S9T0V1W2"
}

Side effects

  • Sets current_homes.status = "LIVE" on the caller’s listing.
  • updatedAt is bumped.
  • Enqueues a match.recompute job for the owner so the matcher picks up the newly-eligible listing (Phase 3 worker; stub in Phase 2).
  • Does NOT touch users.onboardingStatus or users.tenancyStatus — they are inputs, not outputs of this endpoint.

See also

curl

curl -X POST https://api.swappr.co.uk/api/v1/current-home/me/publish \
  -H "Authorization: Bearer $ACCESS_TOKEN"