Active & Inactive Listings
Every listing in your workspace is either active or inactive. You pay for active listings and work with them through the API. Inactive listings cost nothing and keep syncing, ready to activate when you need them. Switching never touches the connected Airbnb, Booking.com, or PMS account.
This is local to Repull only
What active and inactive mean
| Active | Inactive | |
|---|---|---|
| Billed, counts toward your plan's listing limit | Yes | No |
| Data keeps syncing and is kept | Yes | Yes |
| Readable and writable through the API | Yes | No, 403 listing_inactive |
| Included in collection endpoints | Yes | No, left out |
| Webhooks delivered | Yes | No |
Use this to choose what you manage. If a connection brings in 50 listings and you only work with 20, deactivate the other 30: you stop paying for them, and the day you activate one its reservations, messages and reviews are already up to date.
Inactive listings in the API
- Single-listing routes return
403 listing_inactive. That covers the listing itself (GET /v1/properties/{id},GET /v1/listings/{id}) and everything that belongs to it: its reservations, conversations and messages, reviews and review replies, availability, pricing, content, photos, quotes, publish calls, and the channel routes for its Airbnb or Booking.com counterpart. A guest returns 403 only when every one of their reservations is on an inactive listing. The error lists the ids inlisting_ids. See listing_inactive. - Collections leave inactive listings out.
GET /v1/reservations,/v1/conversations,/v1/reviewsand/v1/guestsskip their data, including inpagination.total. Filtering by an inactive listing (?listing_id=) returns 403 rather than an empty page. - Listing lists default to active.
GET /v1/listingsandGET /v1/propertiesreturn active listings unless you pass?status=inactiveor?status=all. Inactive rows carry identity fields only,id,name,status,inactiveReason,address.cityandchannels, so you can decide what to activate.inactiveReasonsays why:plan_limit(held back by your plan — activating needs a free slot or an upgrade),unlisted_on_airbnb, ordeactivated(switched off by you). The channel lists (GET /v1/channels/airbnb/listings,/v1/channels/vrbo/listings,/v1/channels/booking/properties) take the same?status=. Add?include=thumbnailfor a cover photo on every row — see Build a selection screen. - Webhooks are not delivered. Events about an inactive listing are dropped, not held. Activating resumes delivery for events from that moment on. Account-level events are always delivered. See Webhooks.
- The toggles always work.
PATCH /v1/listings/{id},DELETE /v1/listings/{id}andPOST /v1/listings/statusaccept inactive listings.
# Find the listings you can activate
curl "https://api.repull.dev/v1/listings?status=inactive" \
-H "Authorization: Bearer sk_live_YOUR_KEY"
# {
# "data": [
# {
# "id": "4119",
# "name": "Harbor Loft",
# "status": "inactive",
# "channels": [{ "platform": "airbnb", "externalId": "1234567890123456789", "active": true, "syncEnabled": true }]
# }
# ],
# "pagination": { "nextCursor": null, "hasMore": false }
# }Build a selection screen
The screen where someone chooses what to activate is the first thing most people build on top of Repull, and a list of names is hard to choose from. Add ?include=thumbnailand every row comes back with a cover photo — active and inactive alike, in a single request, with no follow-up call per property.
The one thing an inactive listing will show you
403 listing_inactive everywhere, and on a list it is reduced to its identity fields. ?include=thumbnailis the one exception, precisely because a picker is the one thing you are meant to do with an inactive listing. Everything else — address, content, details — still waits for activation.# Your whole catalog, active and inactive, with cover photos
curl "https://api.repull.dev/v1/listings?status=all&include=thumbnail&limit=100" \
-H "Authorization: Bearer sk_live_YOUR_KEY"
# {
# "data": [
# {
# "id": "4118",
# "name": "Ocean View Villa",
# "address": { "street": "1 Shoreline Dr", "city": "Malibu" },
# "thumbnailUrl": "https://a0.muscache.com/im/pictures/oceanview.jpg",
# "status": "active",
# "channels": [{ "platform": "airbnb", "externalId": "1234567890123456789", "active": true, "syncEnabled": true }],
# "createdAt": "2024-12-15T20:39:07.346Z",
# "updatedAt": "2026-09-01T09:14:22.101Z"
# },
# {
# "id": "4119",
# "name": "Harbor Loft",
# "status": "inactive",
# "channels": [{ "platform": "airbnb", "externalId": "9921884466103372", "active": true, "syncEnabled": true }],
# "thumbnailUrl": "https://a0.muscache.com/im/pictures/harbor.jpg"
# }
# ],
# "pagination": { "nextCursor": null, "hasMore": false, "total": 2 }
# }What to expect
thumbnailUrlis a plain image URL. Put it straight in an<img src>: it does not expire and needs no authentication.nullmeans the property has no cover photo yet. The property is still in the response — show a placeholder rather than hiding a property someone is looking for.- Leave the expansion off and the field is absent, not
null. That is how you tell “no photo” apart from “I did not ask for photos”. - It is free: the photo already travels with the row, so asking for it does not make the call slower and does not use extra credits.
- Only building an Airbnb picker?
GET /v1/channels/airbnb/listings?include=thumbnailtakes the same expansion and returns the Airbnb connection for each property alongside it. - Anything other than
content,detailsorthumbnailreturns422 invalid_paramsnaming the values that work — a typo never silently drops the photos.
Activate or deactivate in bulk
/v1/listings/statusSets up to 500 listings active or inactive in one call. The call is all or nothing: either every listing ends up in the requested state, or nothing changes.
# Deactivate three listings
curl -X POST "https://api.repull.dev/v1/listings/status" \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "listingIds": ["4118", "4119", "4120"], "active": false }'
# Activate them again (subject to your plan's listing limit)
curl -X POST "https://api.repull.dev/v1/listings/status" \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "listingIds": ["4118", "4119", "4120"], "active": true }'Body parameters
listingIdsstring[]RequiredListing ids to change, 1 to 500, each at most once. Send them as GET /v1/listings returns them (strings); plain integers are accepted too.
activebooleanRequiredfalse deactivates every listing in listingIds; true activates them. Active listings count toward your plan's listing limit.
Response
{
"active": false,
"updated": ["4118", "4120"],
"unchanged": ["4119"]
}activebooleanThe state every listing in the request is now in.
updatedstring[]Listing ids this call changed, in request order.
unchangedstring[]Listing ids that were already in the requested state, in request order. Re-sending a request is safe.
Errors
404 not_found: at least one id is not a listing in your workspace. Nothing changes;listing_idsnames the unknown ids.402 listings_limit_exceeded: activating would take you over your plan's listing limit. Nothing changes. Only listings that are currently inactive count toward the new total, so re-sending ids that are already active never trips it. See listings_limit_exceeded.422 invalid_params:listingIdsis empty, has more than 500 entries, repeats an id, or contains something that is not an id, oractiveis not a boolean.fieldnames the problem.
Works while you are over your limit
402 listings_limit_exceeded. POST /v1/listings/status, PATCH /v1/listings/{id} and DELETE /v1/listings/{id} keep working, so you can always deactivate your way back under it.Activate or deactivate one listing
/v1/listings/:idSet active to false to deactivate a listing, or true to activate it. Setting a listing to the state it is already in returns 200. Activating returns 402 listings_limit_exceededwhen it would take you over your plan's listing limit.
# Deactivate
curl -X PATCH "https://api.repull.dev/v1/listings/4118" \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "active": false }'
# Activate (subject to your plan's listing limit)
curl -X PATCH "https://api.repull.dev/v1/listings/4118" \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "active": true }'Body parameters
activebooleanRequiredfalse deactivates the listing; true activates it, subject to your plan's listing limit.
Response
{
"id": "4118",
"active": false
}idstringThe listing id.
activebooleanThe listing's state after the call.
Deactivate with DELETE
/v1/listings/:idThe same as PATCH with {"active": false}. Despite the verb, nothing is deleted: the listing is kept and keeps syncing. Returns the same {id, active} response.
curl -X DELETE "https://api.repull.dev/v1/listings/4118" \ -H "Authorization: Bearer sk_live_YOUR_KEY"
How listings become inactive
- You deactivate them, with the endpoints above or the toggle on your listings page.
- You disconnect the account they came from.
DELETE /v1/connect/{provider}deactivates that account's listings, unless a listing is still connected through another account or channel. See Disconnect an account. - They are unlisted on Airbnb when first imported. Connecting Airbnb imports every listing on the account, including unlisted ones. New listings that are listed on Airbnb arrive active; new unlisted ones arrive inactive. Listings added on Airbnb after you connect are picked up by a daily refresh, following the same rule. A later sync never changes the state of a listing you already have.
What does not change upstream
- The listing stays live and bookable on Airbnb, Booking.com, or wherever it originated.
- Your connected PMS or channel-manager account is untouched. No listing is unlisted or deleted.
- Reservations, guests, and messages on the upstream platform are unaffected, and keep syncing into Repull.
What you're billed for
You are billed for your active listings, nothing else. An inactive listing costs nothing, whether or not it is taking bookings.
“Inactive” means inactive in Repull. Unlisting or snoozing a property on Airbnb does not change your Repull billing on its own. Deactivate it here and it drops out of the count.
Choosing what you pay for
- In the dashboard: open Listings, find the property, and click Deactivate. Use the status filter to see everything that is currently active.
- Over the API:
POST /v1/listings/statusfor many listings, orPATCH /v1/listings/{id}for one.
Related
- listing_inactive — the 403 an inactive listing returns, and how to recover.
- List Properties — retrieve your catalog and filter by status.
- listings_limit_exceeded — how the active-listing limit works and how to recover.