Skip to content

Listing Created

Sent when a new listing owned by one of your users is fully set up — and, with status: "failed", when an attempt to set one up fails. Use it to learn about new listings the moment they are ready, and about listings that need attention before they can be created, instead of polling the Listings endpoint.

Event type listing.created
Resource type listing-created-events
Triggered by A new listing finishing setup — its initial base price is computed — a previously removed listing coming back, or a sync attempt failing to create one

When It Fires

A listing is not ready to price against the moment its row is created: Beyond first clusters it, resolves its market, imports its calendar, and computes an initial base price for it. With status: "succeeded", this event fires at that last step — the first time the listing's base price is computed — so when you receive it the listing is fully set up and its base-price is populated.

It fires once on that first pricing, and again if the listing is ever removed and later comes back — see Restored listings below. Treat the event as an upsert rather than an insert. Later base-price changes are delivered as listing.base_price_changed instead, and the listing later leaving or re-entering the fully-priceable state is announced via listing.in_active_market_changed.

Restored Listings

Deleting a managed account removes its listings from your inventory, but the listings are kept: re-creating the account with the same channel credentials brings the same listings back, at the same listing ids. The same is true of a listing that disappears from the channel long enough to be removed and later reappears.

Because the listing already has its base price, the first-pricing milestone above cannot fire a second time — so the return is announced with a status: "succeeded" event carrying restored: true. Everything else about the payload matches a first-time creation, including created-at, which is still the listing's original creation timestamp; meta.sent-at is when it came back.

The restored attribute is omitted entirely for a first-time creation, so a payload that never had it is unchanged.

With status: "failed", the event fires when a sync attempt fails to create a listing that has not been set up yet — for example a property whose channel setup is incomplete (missing rates, misconfigured rate plans) or an unexpected error while importing it. The error attribute carries a human-readable description. Unlike the succeeded case, a failed event fires on every failing sync attempt: a listing whose setup stays broken repeats the event on each re-sync (accounts re-sync daily), until it is either fixed — at which point a status: "succeeded" event follows — or removed.

The webhook is delivered to the OAuth2 application that owns the listing's user (User.owner_application). Listings owned by ordinary, non-API users have no owning application and produce no event.

First base price, then changes

listing.created carries the listing's initial base price. To keep tracking that value over time, subscribe to listing.base_price_changed, which fires on every subsequent change.

Payload

{
  "meta": {
    "type": "listing.created",
    "sent-at": "2026-07-06T12:05:00Z"
  },
  "data": {
    "type": "listing-created-events",
    "id": "msg_01J9Z7Q1H4RM8ZW9P3D5C6B7E8",
    "attributes": {
      "status": "succeeded",
      "created-at": "2026-07-06T12:00:00Z",
      "title": "Ocean View Retreat",
      "currency": "USD",
      "base-price": 210,
      "channel-listings": [
        { "channel": "airbnb", "channel-id": "external-listing-987" }
      ]
    },
    "relationships": {
      "listing": {
        "data": { "type": "listings", "id": "12345" },
        "links": { "related": "https://developers.beyondpricing.com/api/v1/listings/12345/" }
      },
      "user": {
        "data": { "type": "users", "id": "456" },
        "links": { "related": "https://developers.beyondpricing.com/api/v1/users/456/" }
      },
      "account": {
        "data": { "type": "accounts", "id": "789" },
        "links": { "related": "https://developers.beyondpricing.com/api/v1/users/456/accounts/789/" }
      }
    }
  }
}

The meta envelope is documented in the Payload Envelope section.

Restored Listing

A listing that came back. Identical to the payload above apart from restored, and the ids are the ones you already know.

{
  "meta": {
    "type": "listing.created",
    "sent-at": "2026-08-01T09:14:00Z"
  },
  "data": {
    "type": "listing-created-events",
    "id": "msg_01J9Z7Q1H4RM8ZW9P3D5C6B7EA",
    "attributes": {
      "status": "succeeded",
      "restored": true,
      "created-at": "2026-07-06T12:00:00Z",
      "title": "Ocean View Retreat",
      "currency": "USD",
      "base-price": 210,
      "channel-listings": [
        { "channel": "airbnb", "channel-id": "external-listing-987" }
      ]
    },
    "relationships": {
      "listing": {
        "data": { "type": "listings", "id": "12345" },
        "links": { "related": "https://developers.beyondpricing.com/api/v1/listings/12345/" }
      },
      "user": {
        "data": { "type": "users", "id": "456" },
        "links": { "related": "https://developers.beyondpricing.com/api/v1/users/456/" }
      },
      "account": {
        "data": { "type": "accounts", "id": "789" },
        "links": { "related": "https://developers.beyondpricing.com/api/v1/users/456/accounts/789/" }
      }
    }
  }
}

Failed Creation Attempt

On a failed attempt the listing usually does not exist yet, so the listing-specific attributes are null and the listing relationship is omitted; channel-listings and the account/user relationships tell you which property failed. The meta.sent-at envelope timestamp is when the failure was observed.

{
  "meta": {
    "type": "listing.created",
    "sent-at": "2026-07-07T12:05:00Z"
  },
  "data": {
    "type": "listing-created-events",
    "id": "msg_01J9Z7Q1H4RM8ZW9P3D5C6B7E9",
    "attributes": {
      "status": "failed",
      "error": "Room rates are not configured for this property. Please configure a rate in your PMS.",
      "created-at": null,
      "title": null,
      "currency": null,
      "base-price": null,
      "channel-listings": [
        { "channel": "mews", "channel-id": "external-listing-987" }
      ]
    },
    "relationships": {
      "user": {
        "data": { "type": "users", "id": "456" },
        "links": { "related": "https://developers.beyondpricing.com/api/v1/users/456/" }
      },
      "account": {
        "data": { "type": "accounts", "id": "789" },
        "links": { "related": "https://developers.beyondpricing.com/api/v1/users/456/accounts/789/" }
      }
    }
  }
}

data.attributes

Field Type Description
status string Outcome of the listing setup: succeeded or failed.
error string Human-readable description of what went wrong. Present only when status is failed.
restored boolean true when this listing was previously removed and has now come back (see Restored listings). Omitted entirely for a first-time creation and on a failed attempt.
created-at string (RFC 3339) | null UTC timestamp when the listing was created. null on a failed attempt where the listing does not exist yet.
title string | null The listing's title. null on a failed attempt.
currency string | null ISO 4217 currency code the listing is denominated in. null on a failed attempt.
base-price integer | null The listing's initial base price, computed by Beyond during setup, in the listing currency — the same whole number the listing resource exposes as base-price (fractional amounts are truncated toward zero). null on a failed attempt.
channel-listings array of objects The listing's active channel listings — one entry per channel the listing is syndicated to, the same channel-listings exposed on the listing resource. Empty ([]) on the rare listing with no active channel listing. On a failed attempt it holds the single channel listing that could not be set up (empty when the channel is unknown). Each entry has channel (the channel, e.g. airbnb, hostaway) and channel-id (the listing's identifier on the channel side, for correlating the event with your own records).

data.relationships

Every relationship carries a links.related URL you can GET for the current state of the related resource.

Relationship Description
listing The Beyond Pricing master listing that was created ({ "type": "listings", "id": … }). Omitted on a failed attempt where the listing does not exist yet.
user The user who owns the listing ({ "type": "users", "id": … }).
account The managed account the listing's primary channel listing belongs to ({ "type": "accounts", "id": … }). Omitted on the rare listing with no active channel listing.

Handling Tips

  • Check status first. Treat succeeded as "a new listing is ready" — by the time you receive it, the listing endpoint returns its full representation, including the base-price shown here.
  • Follow the listing.links.related URL to fetch the listing's current representation rather than assuming its contents from this event.
  • Dedupe on webhook-id (see idempotency) since retries re-use it. That handles retries, not repeats: a re-onboarded listing fires a genuinely new event with a different webhook-id. Upsert on the listing relationship id rather than inserting, so a listing you already know about is updated instead of duplicated; restored: true tells you when to expect it.
  • A failed event repeats on every failing sync attempt, so expect roughly one per broken property per day until it is fixed. Use the channel-listings[].channel-id + the account relationship to group repeats for the same property; surface the error to whoever can fix the channel setup.
  • A failed event does not mean the listing never gets created: once the setup issue is fixed, the next sync creates it and a succeeded event follows.

Known Limitations

  • Failure events cover errors raised while importing a property (channel setup problems and unexpected sync errors). A listing that imports cleanly but never gets an initial base price (for example, its market is not yet active, or it falls outside any pricing cluster) currently produces no event — neither succeeded nor failed. Both cases surface as in-active-market: false on the listing resource; once a listing has a base price, later changes of that attribute are announced via listing.in_active_market_changed.
  • Transient infrastructure errors (timeouts, worker restarts) are retried internally and do not fire failure events.