Deal lifecycle

How a deal's status changes and how to observe it.

A deal's status comes from its buyers: it is worked out from the state of each
buyer on the deal, and you observe it through the read endpoints. A deal with a
future start date is created as scheduled and becomes active on its start
date. You can also set the status yourself when the deal reads
statusSettable: true, which a read of the single deal reports (see
Changing a deal's status).

Deal types

type on a deal request selects how buyers reach the deal. It is chosen at
creation and cannot be changed afterwards.

typeWhat it is
pmp (default)A private marketplace deal. Every buyer carries at least one seatIds entry: the seats on that DSP that may transact. Omitting type is the same as sending pmp.
openA non-seat deal: any buyer on the DSP can transact. Each buyer carries the partner only. A buyer that lists any seat in seatIds is rejected; an empty seatIds array is accepted. On DV360 an open deal appears as an Auction Package.
{
  "type": "open",
  "buyers": [{ "partner": "dv360" }]
}

Two consequences of type being fixed at creation:

  • PATCH /deal-requests/{id} does not accept type. Sending it returns 400.
  • Buyers on an open deal cannot be edited. A PATCH that includes buyers
    on an open deal returns 400; to change the buyer, create a new deal request.
📘

DSP-specific requirements

Some DSPs require fields this API otherwise treats as optional. See
Demand partners for the requirements that apply to a
given buyer before you submit.

Statuses

StatusMeaning
activeLive and eligible to transact.
scheduledIts start date is in the future; becomes active on that date.
pausedTemporarily not transacting. You can pause a deal yourself (see Changing a deal's status), and Sovrn can too.
reviewA buyer reported an error, or the deal's buyers are not all in the same state. When a buyer did not accept the deal, the deal says which buyer and why in buyerIssues (see When a buyer does not accept a deal).
dsp reviewAwaiting DSP confirmation (applies to certain buyers).
archivedTerminated, for good: an archived deal cannot be changed. Excluded from list reads unless you ask for ?status=archived.
📘

Judging freshness

GET /deal-requests/{id} refreshes the status from source (cached ~30s) and
reports statusAsOf. If that refresh fails, it returns the last-known status
with a 200 (not an error), so always read statusAsOf to judge freshness.
The list endpoint does not refresh; poll the by-id endpoint for current
status.

When a buyer does not accept a deal

Some DSPs check a deal after it is created and can turn it down. The deal then
reads review, and GET /deal-requests/{id} adds buyerIssues, one entry for
each issue that buyer's DSP reported:

{
  "status": "review",
  "buyerIssues": [
    {
      "partner": "dv360",
      "message": "This value is below the minimum this buyer accepts.",
      "field": "pricing.floor"
    },
    {
      "partner": "dv360",
      "message": "This buyer does not accept this value.",
      "field": "buyers.0.seatIds"
    }
  ]
}
  • partner is the buyer, as it appears in the deal's buyers. On a deal with
    several buyers, only a buyer that did not accept the deal is named, and the
    deal reads review all the same.
  • field, when present, is the field to correct, as a path into the deal
    request: one of schedule.endDate, description, pricing.floor, or
    buyers.N.seatIds for the seats of the buyer at position N in buyers,
    counting from 0.
  • message is written by this API, not by the DSP.

An issue that maps to no field has no field, and its message is always:

This buyer did not accept the deal. Saving the deal again retries it.

Correct the fields named with PATCH /deal-requests/{id}. Saving the deal sends
it to the buyer again, which is also how an issue without a field is retried:
a PATCH with an empty body, {}, saves the deal unchanged. The PATCH does
not wait for the buyer's answer, so read the deal again to see the outcome:
buyerIssues is gone once the buyer no longer reports an issue.

buyerIssues is absent from a deal whose buyers reported nothing, from list
items and from the 200 of a PATCH. It can also be absent when the buyers'
state could not be read; status still reads review.

Changing a deal's status

PATCH /deal-requests/{id} accepts a status, so you can pause a deal and
start it again without involving Sovrn operations:

{ "status": "paused" }

Four values may be sent. The rest of the statuses in the table above are
produced by the deal's buyers and cannot be set:

statusSend it to
pausedStop the deal transacting. Reversible.
activeResume a paused deal.
scheduledThe same as active: it resumes a paused deal. The start date decides which of the two the deal reads back.
archivedEnd the deal for good. Every later PATCH that passes validation returns 502, and the deal stays archived. Archived deals leave the default list; list them with ?status=archived.

Sending review, dsp review, or any value outside the four returns 400
naming the four. status is a normal merge-patch field: send it alone, or
alongside any other edit in the same request (see
Editing a deal).

🚧

Not every DSP

status is rejected with 400 on a deal whose buyers are all on a DSP
that manages deal status through its own integration (dv360 today). Such a
DSP manages its deals' status itself, and this API does not change it. On a
deal that mixes such a buyer with others, the others are changed and the
DSP's buyer is left as it is, so the status you send does not always stick:
see Ask the deal, not the DSP and
Demand partners.

Ask the deal, not the DSP

GET /deal-requests/{id} and the 200 from PATCH /deal-requests/{id} carry a
statusSettable boolean. Read it instead of keeping your own list of which DSPs
allow a status change: the list changes, and the deal already knows.

{
  "statusSettable": false
}

true means every buyer on the deal is one whose status this API sets, so the
deal resolves to the status you send, subject to the start-date rule below.

statusSettable is worked out from the deal's buyers alone, so an archived deal
can still read true. An archived deal cannot be changed, whatever it reads.

false is deliberately broader than the 400 above. It covers two cases:

  • every buyer is on a DSP that manages its own deal status: sending
    status returns 400, as described in the callout above; and
  • some buyers are: sending status is accepted and returns 200, and the
    other buyers are changed. The DSP's buyer keeps its own state, and the deal's
    status is worked out from all of its buyers together. Only paused on a
    pmp deal always resolves as sent. Any other value resolves as sent only if
    the DSP's buyer is already in that state on its side, and otherwise the deal
    reads back review. A deal you tried to archive that way is not archived and
    still appears in list results.

So statusSettable answers "should I offer a status control for this deal?",
not "will this PATCH return 200?". The two differ only on that second case,
and treating false as "do not offer it" is correct for both.

List items and the 201 from a create do not carry statusSettable, so read
the deal itself before offering the control.

Two things to expect from the response. status on the 200 is the status the
deal actually resolved to, which is not always the one you sent: active and
scheduled are derived from the start date, so a deal set active before its
start date reads back scheduled, one set scheduled after its start date
reads back active, and a deal whose buyers end up in different states reads
back review. And the status is written to each buyer in turn, after the other
fields in the request have been applied, so a failure partway can leave the
buyers in different states. Re-send the same request until it returns 200
(see Errors).

Editing a deal

PATCH /deal-requests/{id} follows merge-patch rules:

  • Send only the fields you change. A field you leave out keeps its value.
  • buyers and targeting replace the previous arrays whole; they are not
    merged into them.
  • description: null clears the description.
  • schedule.endDate and pricing.floor can be changed but not cleared:
    null returns 400.
  • targeting cannot be cleared: null or [] returns 400. To remove a
    deal's targeting, switch it to Run of Network with runOfNetwork: true (see
    Targeting).
  • type cannot change: sending it returns 400 (see
    Deal types).
  • status can be sent too (see
    Changing a deal's status).
  • Send the body as application/json. A PATCH sent as
    application/merge-patch+json returns 415.

A deal with a dv360 buyer has further rules on an edit; see
Demand partners.


Did this page help you?