DealsOfferExpiredPayload deals.offer.expired@1

Generated at from openvibe-contracts v0.34.2 and openvibe-sdk v0.5.0.

Version
1.0.0
Owner
deals
Visibility
first-party
Status
active
Compatibility
backward
Schema
https://openvibe.network/contracts/events/payloads/deals.offer.expired.v1.json

deals.offer.expired v1 (OpenVibe.Deals server/domain/indexing.js emitOffer, called from server/domain/offers.js expireRow). An active offer became expired: its submitter or a moderator marked it expired (POST /offers/:id/expire; reason submitter, moderator or "moderator: <note>"), or the worker found that its STATED end time has passed (expireDue; reason stated_expiry). Expiry is never inferred from missing data. Written in the transaction that set the status and the moderation_log row, next to deals.index_document.upserted (the page stays in Search as a noindex document with reason expired). The rest of the payload is the offer as it now stands, as in deals.offer.created. Envelope: subject { type: offer, id: <offer_id> }, visibility internal (an expired offer is never public), priority important (default), actor user:<usr_…> who marked it, service:<calling service> when a service acts without a person, service:deals for the worker. No consumer is built yet.

Fields

FieldTypeRequiredDescriptionConstraints
offer_idstringyesThe canonical (root) offer id.
  • pattern ^dof_[0-9A-HJKMNP-TV-Z]{26}$
slugstringyesPage slug: the slugified title plus the last six characters of the id.
  • pattern ^[a-z0-9]+(-[a-z0-9]+)*$
  • maxLength 80
urlstringyesCanonical offer page URL on Deals (/d/<slug>).
  • pattern ^https?://
  • format uri
  • maxLength 2048
titlestringyes
  • minLength 1
  • maxLength 200
statusconstyes
  • = "expired"
storestring | nullyesStore domain: the offer link's host without a leading www.; null when none could be derived.
  • minLength 1
product_idstring | nullyesDeals product the offer is attached to, if any.
  • pattern ^dpr_[0-9A-HJKMNP-TV-Z]{26}$
latest_observationobject | nullyesThe newest observation across the offer's merge group; null only when the group has none.
freshnessenumyesfresh while the latest observation is younger than DEALS_FRESHNESS_HOURS, stale after, unobserved without one.
  • one of "fresh", "stale", "unobserved"
indexabilityobjectyesThe SEO gate decision in Search's shape (index-hooks searchIndexability).
  • no other fields
indexability.decisionenumyes
  • one of "index", "noindex"
indexability.reasonsarray of stringyesSearch reason names, e.g. stale_price, expired, takedown, owner_decision (imported or AI text awaiting review).
  • maxItems 20
  • unique items
  • items: pattern ^[a-z][a-z0-9_]{1,63}$
reasonstringyessubmitter, stated_expiry, moderator, or "moderator: <note>" (the note as the moderator wrote it, whitespace collapsed).
  • pattern ^(submitter|stated_expiry|moderator(: .{1,200})?)$

Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

Valid: moderator-note
{
  "offer_id": "dof_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "slug": "usb-c-charger-65w-k0mnpq",
  "url": "https://openvibe.deals/d/usb-c-charger-65w-k0mnpq",
  "title": "USB-C charger 65W",
  "status": "expired",
  "store": "shop.example",
  "product_id": null,
  "latest_observation": {
    "price": "29.99",
    "currency": "USD",
    "availability": "in_stock",
    "observed_at": "2026-09-23T10:15:00.000Z"
  },
  "freshness": "fresh",
  "indexability": {
    "decision": "noindex",
    "reasons": [
      "expired"
    ]
  },
  "reason": "moderator: the shop ended the sale early"
}
Valid: stated-expiry-stale
{
  "offer_id": "dof_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "slug": "usb-c-charger-65w-k0mnpq",
  "url": "https://openvibe.deals/d/usb-c-charger-65w-k0mnpq",
  "title": "USB-C charger 65W",
  "status": "expired",
  "store": "shop.example",
  "product_id": null,
  "latest_observation": {
    "price": "29.99",
    "currency": "USD",
    "availability": "in_stock",
    "observed_at": "2026-09-23T10:15:00.000Z"
  },
  "freshness": "stale",
  "indexability": {
    "decision": "noindex",
    "reasons": [
      "expired",
      "stale_price"
    ]
  },
  "reason": "stated_expiry"
}
Valid: submitter
{
  "offer_id": "dof_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "slug": "usb-c-charger-65w-k0mnpq",
  "url": "https://openvibe.deals/d/usb-c-charger-65w-k0mnpq",
  "title": "USB-C charger 65W",
  "status": "expired",
  "store": "shop.example",
  "product_id": null,
  "latest_observation": {
    "price": "29.99",
    "currency": "USD",
    "availability": "in_stock",
    "observed_at": "2026-09-23T10:15:00.000Z"
  },
  "freshness": "fresh",
  "indexability": {
    "decision": "noindex",
    "reasons": [
      "expired"
    ]
  },
  "reason": "submitter"
}
Rejected: guessed-reason
{
  "offer_id": "dof_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "slug": "usb-c-charger-65w-k0mnpq",
  "url": "https://openvibe.deals/d/usb-c-charger-65w-k0mnpq",
  "title": "USB-C charger 65W",
  "status": "expired",
  "store": "shop.example",
  "product_id": null,
  "latest_observation": {
    "price": "29.99",
    "currency": "USD",
    "availability": "in_stock",
    "observed_at": "2026-09-23T10:15:00.000Z"
  },
  "freshness": "fresh",
  "indexability": {
    "decision": "noindex",
    "reasons": [
      "expired"
    ]
  },
  "reason": "sold_out"
}
Rejected: missing-reason
{
  "offer_id": "dof_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "slug": "usb-c-charger-65w-k0mnpq",
  "url": "https://openvibe.deals/d/usb-c-charger-65w-k0mnpq",
  "title": "USB-C charger 65W",
  "status": "expired",
  "store": "shop.example",
  "product_id": null,
  "latest_observation": {
    "price": "29.99",
    "currency": "USD",
    "availability": "in_stock",
    "observed_at": "2026-09-23T10:15:00.000Z"
  },
  "freshness": "fresh",
  "indexability": {
    "decision": "noindex",
    "reasons": [
      "expired"
    ]
  }
}
Rejected: still-active
{
  "offer_id": "dof_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "slug": "usb-c-charger-65w-k0mnpq",
  "url": "https://openvibe.deals/d/usb-c-charger-65w-k0mnpq",
  "title": "USB-C charger 65W",
  "status": "active",
  "store": "shop.example",
  "product_id": null,
  "latest_observation": {
    "price": "29.99",
    "currency": "USD",
    "availability": "in_stock",
    "observed_at": "2026-09-23T10:15:00.000Z"
  },
  "freshness": "fresh",
  "indexability": {
    "decision": "index",
    "reasons": []
  },
  "reason": "submitter"
}

Validate

const contracts = require('openvibe-contracts');
contracts.validate('deals.offer.expired@1', value);   // { valid, errors: [{ path, message }] }