Download OpenAPI specification:
Deployed version: 1.1.2
Partner integration API for DealNow initiation, lead ingestion, partner-scoped read access, and real-time webhook notifications.
All POST endpoints require a Bearer token in the Authorization header. The /data read endpoints (deals, offers, listings, webhook-deliveries, documents) use the same Bearer token. The GET /sell/{partnerId} endpoint additionally supports inline JWT auth via query params — see its own description.
The token must be a HS256, HS384, or HS512 JWT signed with your partner shared secret, which PrivateAuto provides during onboarding.
Your shared secret is delivered as a base64-encoded string — decode it to a UTF-8 string before signing. The JWT payload must include p (your partner identifier) and a short expiry (we recommend ≤ 5 minutes). Pick one of the following:
Node.js (npm install jsonwebtoken):
JWT=$(node -e '
const jwt = require("jsonwebtoken");
const secret = Buffer.from("YOUR_BASE64_SECRET", "base64").toString("utf-8");
console.log(jwt.sign(
{ p: "YOUR_PARTNER_ID", iat: Math.floor(Date.now() / 1000) },
secret,
{ algorithm: "HS256", expiresIn: "5m" }
));
')
Python (pip install pyjwt):
JWT=$(python3 -c '
import base64, jwt, time
secret = base64.b64decode("YOUR_BASE64_SECRET").decode("utf-8")
now = int(time.time())
print(jwt.encode(
{"p": "YOUR_PARTNER_ID", "iat": now, "exp": now + 300},
secret,
algorithm="HS256",
))
')
CLI (jwt-cli, brew install mike-engel/jwt-cli/jwt-cli):
SECRET=$(printf '%s' 'YOUR_BASE64_SECRET' | base64 -d)
JWT=$(jwt encode \
--alg HS256 \
--secret "$SECRET" \
--exp '+5m' \
-P p=YOUR_PARTNER_ID)
curl -X POST "https://partner-api.privateauto.com/sell/YOUR_PARTNER_ID" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{ "vin": "1HGBH41JXMN109186", "amount": 18500 }'
Production host: https://partner-api.privateauto.com. Padev host: https://partner-api.padev.xyz.
PrivateAuto pushes real-time event notifications to your server whenever key actions happen on a deal, listing, offer, or user that originated through your partner integration.
Webhooks are configured per-partner during onboarding. You provide an HTTPS endpoint URL, a list of event types to subscribe to, and a webhook secret for signature verification.
Looking for the per-transaction event sequence? See the Event sequences by transaction type section below for the canonical event chain per deal shape (C2D / D2C / D2D / C2C, plus the partner-initiated
/sellflow) and minimum-viable subscription sets.
| Setting | Description |
|---|---|
| Endpoint URL | Your public HTTPS URL. Private/internal IP addresses are rejected. |
| Webhook secret | A shared secret used to sign every delivery. PrivateAuto provides this during onboarding. |
| Events | The event types you want to receive. Supports wildcards (e.g. deal.*, *). |
Webhooks are delivered as POST requests with the following headers:
| Header | Description |
|---|---|
Content-Type |
application/json |
X-PA-Event |
Event type, e.g. deal.completed |
X-PA-Timestamp |
ISO 8601 timestamp of when the event was emitted |
X-PA-Signature |
HMAC-SHA256 signature (see Verifying Signatures) |
X-PA-Partner |
Your partner ID |
X-PA-Event-Id |
Stable per-event idempotency identifier (see Idempotency) |
User-Agent |
PrivateAuto-Webhooks/1.0 |
Every payload also carries eventId and eventKey at the top level — see Idempotency.
Every delivery includes an X-PA-Signature header of the form sha256={hex}. To verify:
X-PA-Timestamp from the request headers.{timestamp}.{raw_body}.sha256= in X-PA-Signature.const crypto = require('crypto');
function verifySignature(req, secret) {
const timestamp = req.headers['x-pa-timestamp'];
const received = req.headers['x-pa-signature']; // "sha256=abc123..."
const body = req.rawBody; // raw bytes, not parsed JSON
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${body}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
}
Always use the raw request body (before JSON parsing) for signature verification.
Every webhook payload carries two fields that let you safely dedupe duplicate deliveries:
| Field | Type | Description |
|---|---|---|
eventId |
string | sha256 hex (64 chars). The canonical idempotency key. Stable across delivery retries and across our own internal replay (e.g. resume after a worker restart). |
eventKey |
string | Composite key the eventId was derived from. Informational only — see warning below. |
The same eventId value is also delivered as the X-PA-Event-Id HTTP header.
Recommended: keep a cache of received eventIds for at least 24 hours and skip processing on a hit. 24 hours covers our 3-attempt retry window with margin.
Do not parse
eventKey. Its internal structure (resume token, partner id, event name, emission index, separator) is an implementation detail and may change without an API version bump. It is provided for log correlation and support tickets only — onlyeventIdis a stable contract.
eventId is included in the signed body, so it is automatically covered by the existing X-PA-Signature HMAC. No extra verification step is needed beyond the standard signature check.
If your endpoint returns a non-2xx status or times out (10-second limit), PrivateAuto retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | 1 minute |
| 2 | 5 minutes |
| 3 | 15 minutes |
After 3 failed attempts the event is moved to a dead-letter queue. Return 2xx as quickly as possible — process events asynchronously if needed.
Subscribe to individual events or use wildcard namespaces:
| Wildcard | Matches |
|---|---|
deal.* |
All deal events |
listing.* |
All listing events |
offer.* |
All offer events |
user.* |
All user events |
* |
All events |
| Event | When it fires |
|---|---|
deal.created |
A deal is initiated via the Partner API |
deal.completed |
Deal fully completed (both parties confirmed, funds transferred) |
deal.cancelled |
Deal cancelled by either party |
deal.expired |
Deal expired without completion |
deal.offer_accepted |
Both buyer and seller have confirmed deal terms |
deal.buyer_joined |
Buyer has joined the deal |
deal.seller_joined |
Seller has joined the deal |
deal.buyer_ready |
Buyer has confirmed all steps and is ready to close |
deal.seller_ready |
Seller has confirmed all steps and is ready to close |
deal.co_seller_invited |
A co-seller invitation email is sent |
deal.title_submitted |
Seller confirms the title-information step (ownership, registration, lien holder) |
deal.title_approved |
Seller marks title attachment complete after uploading photos (seller-driven, not admin review) |
deal.docs_submitted |
Buyer/seller submit closing documents |
deal.docs_approved |
Closing documents are approved |
deal.payment_initiated |
Payment transfer is initiated |
deal.payment_acknowledged |
Seller acknowledges receipt of payment |
deal.amount_changed |
Deal amount updated after creation |
deal.negative_equity_identified |
Payoff amount exceeds deal amount |
deal.negative_equity_funded |
Negative equity balance has been funded |
deal.loan_payoff_docs |
Seller's loan payoff documents are uploaded |
deal.loan_payoff_confirmed |
Loan payoff is manually confirmed |
deal.poa_approved |
Power of Attorney document is fully signed |
deal.bill_of_sale_approved |
Bill of Sale is fully signed by all required parties |
Deal event payload:
| Field | Type | Description |
|---|---|---|
id |
string | Deal document ID |
guid |
string | UUID for the deal (e.g. d30d5242-c880-4534-8c51-0032dde02093) |
status |
string | Current deal status |
amount |
number | Deal amount in dollars |
buyerId |
string | Buyer's user ID |
sellerId |
string | Seller's user ID |
documents |
array | Present on document-upload events only — see below |
Deal payloads do not carry a
vin. FetchGET /data/deals/:partnerId/:dealIdto obtain the deal'slistingId, thenGET /data/listings/:partnerId/:listingIdforvehicle.vinand the full vehicle spec.
Document events (deal.title_submitted, deal.title_approved, deal.loan_payoff_docs, deal.poa_approved, deal.bill_of_sale_approved) also carry a documents array with short-lived signed S3 URLs:
| Field | Type | Description |
|---|---|---|
documents[].filename |
string | Original filename |
documents[].signedUrl |
string | Pre-signed HTTPS URL — fetch within the expiry window |
documents[].expiresAt |
string | ISO 8601 timestamp when the signed URL stops working (4 hours after the event) |
Signed URLs expire 4 hours after the event is emitted. Download and persist the file promptly — if you need the document later, request a fresh event or contact PrivateAuto support.
Example deal.title_submitted payload:
{
"id": "64a1f2e3b5c8d90012345678",
"eventId": "a2f1e9c4b7d8...",
"eventKey": "82f1...:partner-acme:deal.title_submitted:0",
"entityType": "deals",
"status": "active",
"guid": "d30d5242-c880-4534-8c51-0032dde02093",
"amount": 18500,
"buyerId": "64a1f2e3b5c8d90012340001",
"sellerId": "64a1f2e3b5c8d90012340002",
"documents": [
{
"filename": "title-front.jpg",
"signedUrl": "https://pa-uploads.s3.us-east-2.amazonaws.com/...",
"expiresAt": "2026-04-21T18:00:00.000Z"
},
{
"filename": "title-back.jpg",
"signedUrl": "https://pa-uploads.s3.us-east-2.amazonaws.com/...",
"expiresAt": "2026-04-21T18:00:00.000Z"
}
]
}
deal.poa_approved and deal.bill_of_sale_approved are deal-level events carried on the underlying document record. The payload looks different from other deal events:
| Field | Type | Description |
|---|---|---|
id |
string | Document ID (not the deal ID) |
entityType |
string | documents for POA; platoforms_generated_documents for Bill of Sale |
dealId |
string | Deal this document belongs to — use this to join with your deal records |
status |
string | Document status (signed / completed) |
docClassification |
string | poa or bill-of-sale |
documents |
array | Signed S3 URLs for the completed document (same shape as above) |
Example deal.poa_approved payload:
{
"id": "64a1f2e3b5c8d90012349999",
"entityType": "documents",
"dealId": "64a1f2e3b5c8d90012345678",
"status": "signed",
"docClassification": "poa",
"documents": [
{
"filename": "signed_poa.pdf",
"signedUrl": "https://pa-uploads.s3.us-east-2.amazonaws.com/...",
"expiresAt": "2026-04-21T18:00:00.000Z"
}
]
}
| Event | When it fires |
|---|---|
offer.created |
Buyer submits an offer |
offer.accepted |
Seller accepts the offer |
offer.rejected |
Seller rejects the offer |
offer.cancelled |
Offer withdrawn by buyer |
Offer event payload:
| Field | Type | Description |
|---|---|---|
id |
string | Offer document ID |
guid |
string | UUID for the offer (matches the deal guid once a deal is created) |
status |
string | Current offer status |
listingId |
string | Associated listing ID |
amount |
number | Offer amount in dollars |
buyerId |
string | Buyer's user ID |
sellerId |
string | Seller's user ID |
| Event | When it fires |
|---|---|
listing.created |
A new listing is created |
listing.updated |
Listing details edited |
listing.published |
Listing goes live |
listing.sold |
Vehicle marked sold |
listing.deleted |
Listing deactivated or expired |
listing.ownership_set |
Seller declared vehicle ownership type (owned / financed / leased) |
Listing event payload:
| Field | Type | Description |
|---|---|---|
id |
string | Listing document ID |
status |
string | Current listing status |
vin |
string | Vehicle Identification Number |
year |
number | Vehicle model year |
make |
string | Vehicle make |
model |
string | Vehicle model |
trim |
string | Vehicle trim level |
price |
number | Listing price in dollars |
sellerId |
string | Seller's user ID |
ownershipType |
string | owned, financed, or leased (present when ownership is declared) |
vehicleHaveLien |
boolean | Whether the vehicle has an active lien |
| Event | When it fires |
|---|---|
user.registered |
A user registers on your branded PrivateAuto site |
User event payload:
| Field | Type | Description |
|---|---|---|
id |
string | User document ID |
email |
string | User email address |
firstName |
string | User first name |
lastName |
string | User last name |
2xx status to acknowledge receipt.2xx immediately and process the event asynchronously if your handler is slow.401 for signature failures so PrivateAuto can flag delivery issues.Each partner event is emitted when a specific document change is observed on a Mongo change stream. The columns below name the underlying state change (authoritative — taken from lambda/trigger-distiller/src/reducers/) and the user-facing action that produces it. If your testing shows an event is not firing for an action listed here, file a ticket with the specific deal/listing ID — the field-change column is the contract.
| Event | Mongo trigger | User action |
|---|---|---|
deal.created |
deals insert |
Buyer accepts an offer (DealNow flow); partner-api POST /sell/:partnerId creating a DealNow-pending offer that finalizes into a deal |
deal.completed |
deals.status → sold |
Final closing step (payment acknowledged + title released) |
deal.cancelled |
deals.status → dealCancelled |
Either party cancels the deal from Deal Settings |
deal.expired |
deals.status → dealExpired |
Background expiration job marks a stale deal expired |
deal.offer_accepted |
deals.allPartiesConfirmed set truthy |
Both buyer and seller hit "Confirm Deal Terms" on the Offer step |
deal.buyer_joined |
dealState.buyer.status → joined |
Buyer signs in, accepts the deal invitation, and lands on the deal |
deal.seller_joined |
dealState.seller.status → joined |
Seller signs in and joins the deal |
deal.buyer_ready |
dealState.buyer.status → readyToClose |
Buyer marks "Ready to Close" after completing all required steps |
deal.seller_ready |
dealState.seller.status → readyToClose |
Seller marks "Ready to Close" after completing all required steps |
deal.co_seller_invited |
seller.coSellerInviteSentAt set |
Seller sends a co-seller invitation email |
deal.title_submitted |
seller.titleConfirmedDate set |
Seller confirms the title-information step (ownership, registration, lien holder); file uploads may or may not have happened yet |
deal.title_approved |
titleAttachment.completedDate set |
Seller marks their uploaded title attachment "complete" (clicks Done in the title-attachment modal). Seller-driven, not admin review |
deal.docs_submitted |
dealState.documentsStatus → pending |
Buyer/seller sign all required closing documents, kicking off review |
deal.docs_approved |
dealState.documentsStatus → complete |
Internal/admin reviewer approves the closing document set |
deal.payment_initiated |
dealState.closingStatus → initiated |
Buyer initiates the payment transfer (PrivateAuto Pay) |
deal.payment_acknowledged |
dealState.closingStatus → acknowledged |
Seller acknowledges receipt of payment |
deal.amount_changed |
payment.privateAutoPay.amount updated on existing deal |
Either party (or admin) adjusts the deal amount after creation; not fired on insert |
deal.negative_equity_identified |
negativeEquity set true |
Loan payoff acceptance where payoff > PA pay amount (flag stamped by spinwheel.service when manualPayoffInfo.status → ACCEPTED) |
deal.negative_equity_funded |
negativeEquityFunded set true |
Negative-equity loan payoff dispatch succeeds |
deal.loan_payoff_docs |
creditreports.manualPayoffInfo.loanPayoffDocuments populated |
Seller uploads loan payoff documents on the Title step |
deal.loan_payoff_confirmed |
creditreports.manualPayoffInfo.status → confirmed |
Internal reviewer confirms the loan payoff |
deal.poa_approved |
documents (POA) becomes fully signed |
All required signers complete Power of Attorney signing |
deal.bill_of_sale_approved |
platoforms_generated_documents (BoS) marked complete |
Bill of Sale fully signed by all required parties |
| Event | Mongo trigger | User action |
|---|---|---|
offer.created |
offers insert |
Buyer submits an offer on a listing; partner-api POST /sell/:partnerId creates a DealNow offer |
offer.accepted |
offers.status → accepted |
Seller accepts an offer from the Listing/Offers screen |
offer.rejected |
offers.status → declined |
Seller declines an offer (internal status declined → external rejected) |
offer.cancelled |
offers.status → deleted |
Buyer withdraws an offer (internal status deleted → external cancelled) |
| Event | Mongo trigger | User action |
|---|---|---|
listing.created |
seller_listings insert |
Seller saves a new listing (initial document insert) |
listing.updated |
seller_listings update where no more specific tag matches |
Seller edits a listing field that doesn't already trigger a more specific event (i.e. not a status transition, ownership-set, or cash-offer). One Mongo update produces at most one listing event — listing.updated is the catch-all for everything else. |
listing.published |
status → live |
Seller hits "Publish" on a draft listing |
listing.sold |
status → sold |
Listing marked sold (manual or via accepted DealNow flow) |
listing.deleted |
status → deactivated or expired, OR soft-delete via deleted: true, OR physical delete (no fullDocument — not delivered) |
Seller deactivates a listing, expiration job marks it expired, or admin tools soft-delete the document |
listing.ownership_set |
ownershipInfo.ownershipType set/changed |
Seller answers the "Do you own this vehicle outright, finance it, or lease it?" question on listing setup. Also fires on insert when ownership is included in the initial document. |
| Event | Mongo trigger | User action |
|---|---|---|
user.registered |
users insert with appRegisteredFrom = <partnerId> |
A user completes registration on your branded PrivateAuto experience |
appSource (the partner who originated the entity) or organization linkage (per the partner's webhookScope — see admin-api). If neither match holds for a deal/listing/offer, no event will be queued.["*"]). Events absent from that list are silently dropped before delivery.fullDocument (i.e. a physical delete) does not produce partner webhooks. Soft-deletes (deleted: true) do.Any deal/listing/document URL that PrivateAuto generates for a partner — whether returned by the sell endpoint or embedded in a future webhook payload — uses the app. subdomain (https://app.<host>/...), never the apex. The host is selected per-partner via the linkPlatform config on the partner record:
linkPlatform |
Host |
|---|---|
dealnow (default) |
https://app.${dealNowDomain} |
pa-app |
https://app.${appDomain} |
Apex domains (https://${dealNowDomain}, https://${appDomain}) are reserved for marketing pages and are not partner deep-link targets.
/data endpoint cross-referenceWebhook payloads are intentionally compact — they carry the IDs, status fields, and a small set of stable identifiers, but not the full document. To pull the rich shape of a deal, offer, listing, or document, follow the IDs in the payload to a GET /data/... endpoint. The response shapes are stable, authoritative, and described in data-endpoints.md.
Use the webhook as the signal, the /data endpoint as the source of truth.
| Event family | Payload ID field | Fetch full record from |
|---|---|---|
deal.* |
id (deal _id) |
GET /data/deals/:partnerId/:dealId → PartnerDealResponse |
offer.* |
id (offer _id); also listingId |
GET /data/offers/:partnerId/:offerId; GET /data/listings/:partnerId/:listingId |
listing.* |
id (listing _id) |
GET /data/listings/:partnerId/:listingId → PartnerListingResponse |
user.registered |
id (user _id) |
Not exposed via /data. The webhook payload is the only delivery — capture email/firstName/lastName from the body. |
deal.*_docs, deal.title_*, deal.poa_approved, deal.bill_of_sale_approved, document.* |
dealId (plus optional documentId) |
GET /data/deals/:partnerId/:dealId/documents (re-issues fresh 4-hour signed URLs); single-doc fetches via GET /data/documents/:partnerId/:documentId or GET /data/generated-documents/:partnerId/:documentId |
| Any delivery — replay/inspect | eventId (header X-PA-Event-Id) |
GET /data/webhook-deliveries/:partnerId/:logId returns the dispatched body + attempt metadata. Use GET /data/webhook-deliveries/:partnerId (filterable) to find the logId. |
Per-event field mapping (which payload field unlocks which /data field on the corresponding response DTO):
deal.* payload → PartnerDealResponse| Payload field | PartnerDealResponse field |
|---|---|
id |
id (use as :dealId) |
guid |
guid |
status |
status |
amount |
payment.privateAutoPay.amount |
buyerId |
buyer.id |
sellerId |
seller.id |
| (none — not on the payload) | listingId, dealState.*, seller.organizationId, buyer.organizationId, payment.*, titleAttachment.*, timestamps. Fetch via getDeal to get all. |
offer.* payload → PartnerOfferResponse| Payload field | PartnerOfferResponse field |
|---|---|
id |
id (use as :offerId) |
guid |
guid |
status |
status |
amount |
price |
listingId |
listing (use as :listingId on getListing) |
buyerId |
offeredBy |
sellerId |
offeredTo |
listing.* payload → PartnerListingResponse| Payload field | PartnerListingResponse field |
|---|---|
id |
id (use as :listingId) |
status |
status |
vin |
vehicle.vin |
year |
vehicle.year |
make |
vehicle.make |
model |
vehicle.model |
trim |
vehicle.trim |
price |
price |
sellerId |
sellerId |
ownershipType |
ownershipInfo.ownershipType |
vehicleHaveLien |
ownershipInfo.vehicleHaveLien |
PartnerDealDocumentsResponse / detail DTOs| Payload field | Where to follow it |
|---|---|
dealId |
GET /data/deals/:partnerId/:dealId/documents → full doc set (title + documents[] + generatedDocuments[]) with fresh signed URLs |
documentId (when present) |
GET /data/documents/:partnerId/:documentId (documents collection) or GET /data/generated-documents/:partnerId/:documentId (platoforms_generated_documents) — choose by entityType on the payload |
docClassification |
Filter on the /data response — same vocabulary (bill-of-sale, poa, etc.) |
documents[].signedUrl |
Short-lived (4h). When expired, re-fetch via the /data endpoint above to receive freshly-signed URLs. |
How the events above sequence depends on which side the partner sits on and how the deal originated. The rest of this section walks each shape end-to-end.
Every deal record carries an internal workflow_type field derived from the org membership of each party:
seller.organizationId |
buyer.organizationId |
workflow_type |
Plain-English shape |
|---|---|---|---|
| ∅ | ∅ | C2C | Consumer sells to consumer (no dealer involved) |
| ∅ | ✓ | C2D | Dealer acquires from a consumer (dealer-acquisition) |
| ✓ | ∅ | D2C | Dealer sells to a consumer (retail) |
| ✓ | ✓ | D2D | Wholesale between two dealers |
Partners always show up on the side that has organizationId === partner.organizationId. Deals where the partner org is on neither side don't fire any partner webhooks for that partner (org-routed scope) or rely on appSource (appSource-routed scope) — see the routing notes at the end of this page.
The most common partner shape: a dealer integration acquiring a vehicle from a consumer. Two sub-flows depending on entry point:
POST /sell/:partnerIdThe partner kicks off the flow from their own UI. The seller receives a deep-link to confirm ownership and the rest of the steps happen via the consumer-facing app (or via further partner-api calls).
HTTP Event delivered Notes
───────────────────────────── ──────────────────────────── ──────────────────────────────────
POST /sell/:partnerId listing.created Stub listing created for the VIN
offer.created dealNowPending offer with the
partner-org user pre-bound on
the buyer side (per PA-4489)
───────────────────────────── ──────────────────────────── ──────────────────────────────────
seller follows seller-link offer.accepted dealer + consumer both bound
(consumer confirms ownership) deal.created deal record materializes
───────────────────────────── ──────────────────────────── ──────────────────────────────────
docs round (per signer) document.signature_added one per manualSignatures slot
last signer signs document.completed terminal per-doc event
deal.bill_of_sale_approved (legacy, deprecating; same event
filtered to bill-of-sale only)
───────────────────────────── ──────────────────────────── ──────────────────────────────────
admin reviews & approves docs deal.docs_approved dealState.documentsStatus →
complete
───────────────────────────── ──────────────────────────── ──────────────────────────────────
POST /api/deals/start-transfer deal.payment_initiated buyer (dealer) clicks "send
funds"
───────────────────────────── ──────────────────────────── ──────────────────────────────────
POST /api/deals/confirm- deal.payment_acknowledged seller (consumer) confirms
payment deal.completed receipt; updateTransferDates
auto-flips deal.status to 'sold'
Minimum event subscription to track this flow: deal.created, document.completed, deal.payment_initiated, deal.payment_acknowledged, deal.completed. Adding deal.docs_approved lets you mirror PA's "all docs reviewed" state for buyer-side UI.
Consumer lists the vehicle on PrivateAuto, the dealer (your partner-org user) offers via the consumer-facing app, and both parties accept. Webhooks for partners on the buyer side:
listing.created consumer creates the listing (only if appSource match)
listing.published consumer publishes
offer.created dealer submits an offer (offer.appSource matches partner)
offer.accepted consumer accepts
deal.created materializes from accepted offer
{ same docs / payment / completion chain as 1a }
Identical from offer.accepted onward.
Mirror of C2D with the partner on the seller side. Webhooks the partner cares about:
listing.created partner (or partner-API) creates the listing
listing.published listing goes live
listing.ownership_set OR ownershipInfo.ownershipType set by admin/internal
listing.ownership_submitted ownershipInfo.ownershipType set by partner user
─────────────────────────────────────────────────────────────────────────────
offer.created consumer (buyer) offers
offer.accepted partner-side acceptance (or counter-offer chain)
deal.created deal record materializes
{ docs round — partner signs Bill of Sale, POA, etc. as the seller }
deal.docs_approved
deal.payment_initiated consumer initiates payment
deal.payment_acknowledged partner confirms receipt
deal.completed
listing.sold listing's status flips to 'sold' after deal completes
Both sides are org users. Each subscribed partner receives webhooks where their org appears on either side. The event set is the same as D2C / C2D but the partner sees BOTH a listing.published (seller side) and an offer.created (buyer side) for the same deal if they're routing both partners. Dedupe via the deal's guid.
Partner webhooks only fire if the offer or deal carries appSource = <partnerId> (i.e. the partner branded the originating user experience even though neither party joined the partner's org). Subscribe with webhookScope: "appSource" in your partner config; org-routed partners receive nothing for C2C.
The Bill of Sale and POA (and any other generated document with manualSignatures) drive two new events per document (and the legacy classifier-specific event during the deprecation window):
manualSignatures[0].signedAt set document.signature_added (slot=0, role=seller)
manualSignatures[1].signedAt set document.signature_added (slot=1, role=buyer)
document.completed (all signers complete)
deal.bill_of_sale_approved (legacy, BoS only)
deal.poa_approved (legacy, POA only)
Each document.signature_added payload carries:
{
"id": "<documentId>",
"dealId": "<dealId>",
"docClassification": "bill-of-sale" | "poa" | "addendum" | …,
"signers": [{ "signerRole": "seller" | "buyer", "signedAt": "<ISO date>" }]
}
Integrators discriminate document types by docClassification rather than by event name — document.completed arrives once per document regardless of which classification it carries. The legacy deal.bill_of_sale_approved and deal.poa_approved events keep firing during the deprecation window for backward compatibility.
When the consumer side's loan payoff exceeds the offered price:
| User vs admin path | Event | Triggered by |
|---|---|---|
| User-side | deal.negative_equity_reported |
Consumer-facing flow updates deal.payment.privateAutoPay.amount and crosses the payoff threshold |
| Admin/service-side | deal.negative_equity_identified |
Admin SpinwheelService stamps negativeEquity: true |
Both events carry negativeEquity: true on the payload. The event name is the discriminator — no source field. Once the negative-equity payoff is dispatched, deal.negative_equity_funded fires.
Specific to deals where the consumer-side seller has an outstanding loan on the vehicle:
seller uploads loan payoff doc → deal.loan_payoff_docs (only the first upload)
internal reviewer confirms → deal.loan_payoff_confirmed
The deal.loan_payoff_docs event references the underlying credit_reports document by id (not the deal id) — fetch the full deal via getDealDocuments to see the attached doc.
What appears on a deal — and therefore what signatures and document events you should expect — varies by who's on each side. PrivateAuto generates a different document set depending on whether the parties are consumers, dealers, or a mix. The table below lists the docs you should plan to see; each row is a separate row in deal.documents[] (collection: documents or platoforms_generated_documents) with its own signers and its own document.signature_added / document.completed / deal.docs_approved chain.
| Document | C2C | C2D | D2C | D2D | Notes |
|---|---|---|---|---|---|
| Title attachment (front / back photos) | ✅ | ✅ | ✅ | ✅ | Seller confirms title info → deal.title_submitted; seller uploads photos + marks attachment complete → deal.title_approved. Both are seller-driven |
Bill of Sale (docClassification: 'bill-of-sale') |
✅ | ✅ | ✅ | ✅ | Always generated; both parties sign — fires document.signature_added (×2) + document.completed (+ legacy deal.bill_of_sale_approved) |
Power of Attorney (docClassification: 'poa') |
— | ✅ | ✅ | ✅ | Generated when a dealer is on either side (the dealer signs as buyer-rep / seller-rep). Fires document.signature_added per signer + document.completed (+ legacy deal.poa_approved) |
| Loan payoff documents | seller-lien only | seller-lien only | — | — | Only when the consumer-side seller's vehicle has an outstanding loan. Stored in credit_reports.manualPayoffInfo.loanPayoffDocuments; surfaces via deal.loan_payoff_docs + deal.loan_payoff_confirmed |
| Self-inspection photos | optional | optional | — | — | Buyer-requested third-party inspection; not signed via PrivateAuto, stored as attached photos. No webhook today |
| State-specific paperwork (odometer, lien-release, title application) | varies | varies | varies | varies | Generated as needed based on deal.state (US state code). Not surfaced as distinct events; tracked as part of dealState.documentsStatus |
deal.documents[] is an array of references to the documents collection (POA + state paperwork + addendum docs).platoforms_generated_documents.*.sharedDeals[] references back to the deal(s) the BoS lives on (the BoS can be re-used across co-seller scenarios).deal.titleAttachment (not in documents collection).credit_reports.manualPayoffInfo.loanPayoffDocuments (not in documents collection).When you call GET /data/deals/:partnerId/:dealId/documents, the response merges all of the above into a single documents[] array with fresh 4-hour signed S3 URLs. That's the canonical "what's on this deal" endpoint — partners don't need to know the storage split.
When deal.coSeller is populated, the Bill of Sale and POA each pick up an extra signer slot for the co-seller. The signature events still fire once per slot — document.signature_added fires three times for a 3-signer document (seller + co-seller + buyer), and document.completed fires once when all three have signed. Watch the signers[] array on the payload to track who has signed.
credit_reports, not in a separate signed doc.webhookScope summaryHow partner.webhookScope affects which of the above events you receive:
webhookScope |
Listings | Deals & offers | Documents | Users |
|---|---|---|---|---|
appSource |
Only if listing.appSource === partnerId |
Only if offer.appSource === partnerId or deal.appSource === partnerId |
Inherits from linked deal's appSource | user.registered only when user.appRegisteredFrom === partnerId |
organization |
Listing owner is in partner.organizationId |
Either side of the deal is in partner.organizationId |
Linked deal's seller or buyer is in partner.organizationId |
User's userDetails.organizationId === partner.organizationId |
both (default) |
Either of the above matches | Either of the above matches | Either of the above matches | Either of the above matches |
If listings / documents /
user.registeredevents aren't firing onwebhookScope=organization, the cause is almost always that the source user / document has no org link populated. See the gotcha box inwebhooks.mdfor the conditional-routing matrix.
offer.accepted + deal.created). Process by name; treat sequence as informational.eventId. The same partner webhook will retry on transient delivery failures; eventId is stable per (resume token, partner, event, emission index) so you can safely treat it as an idempotency key./data/... endpoints if you need anything beyond what the webhook payload exposes — payloads are intentionally compact and stable; full DTOs are the place to read.deal.bill_of_sale_approved / deal.poa_approved in favor of document.completed + docClassification, you'll receive both. Subscribing only to document.* is forward-compatible; subscribing only to the legacy names will go silent at some point.offer.accepted in some lifecycle shapes; the user-driven path skips MARK_SOLD because the seller's confirm-payment call writes status='sold' directly. The event catalog tells you what can fire, not what must.DealNow deal initiation — redirect a prospect into a PrivateAuto deal or create one programmatically
Initiate a DealNow transaction via browser redirect. The user is redirected to their
buyer link (or a redirectUrl you specify).
Auth: Inline — JWT (Formats 1/2) or HMAC-signed short-key query (Format 3). No Authorization header needed; all three formats authenticate against the partner shared secret.
Format 1 — Explicit JWT
GET /sell/mypartner?jwt=<token>
Format 2 — VIN param is a JWT
GET /sell/mypartner?v=<token>
If the v param contains dots, it is treated as a JWT. The JWT payload may use either full field names or the short keys.
Format 3 — Signed short key query params
GET /sell/mypartner?v=1HGBH41JXMN109186&y=2021&m=Honda&o=Civic&a=18500&be=buyer@example.com&r=https://yoursite.com/thanks&ts=<epochSec>&sig=<hex>
Format 3 requires ts (current epoch seconds, ±5 min skew allowed) and sig — a hex-encoded HMAC-SHA256 of the canonical query string, signed with the partner's shared secret (the same secret used for JWT signing).
Canonical string: every query param except sig, sorted alphabetically by key, URL-encoded k=v joined by &.
# Node example
node -e '
const crypto = require("crypto");
const secret = Buffer.from("YOUR_BASE64_SECRET", "base64").toString("utf-8");
const params = { v: "1HGBH41JXMN109186", y: 2021, m: "Honda", o: "Civic",
a: 18500, be: "buyer@example.com", ts: Math.floor(Date.now()/1000) };
const canonical = Object.keys(params).sort()
.map(k => encodeURIComponent(k) + "=" + encodeURIComponent(params[k]))
.join("&");
const sig = crypto.createHmac("sha256", secret).update(canonical).digest("hex");
console.log(canonical + "&sig=" + sig);
'
| Short | Full Field | Type |
|---|---|---|
v |
vin | string |
y |
year | number |
m |
make | string |
o |
model | string |
t |
trim | string |
a |
amount | number |
bn |
buyerName | string |
be |
buyerEmail | string |
bl |
buyerSendLink | boolean |
sn |
sellerName | string |
se |
sellerEmail | string |
sl |
sellerSendLink | boolean |
r |
redirectUrl | string |
ro |
role | buyer or seller (default: buyer) |
redirectUrl is provided, the user is redirected there after the deal is created.redirectUrl is provided, the user is redirected to the link for the party specified by role (default: buyer).role=seller when the initiating user is the vehicle seller rather than the buyer.| partnerId required | string Your partner identifier, provided during onboarding (e.g. mypartner) |
| v | any VIN or JWT token (Format 2/3) |
| jwt | any Explicit JWT token (Format 1) |
Initiate a DealNow transaction. Returns buyer and seller deep links.
Requires a HS256, HS384, or HS512 JWT Bearer token signed with your partner shared secret.
If the vehicle is not already listed on PrivateAuto, year, make, and model are required in addition to vin.
Note:
redirectUrlandroleare GET-only parameters and are not applicable to this endpoint.
Your shared secret is delivered as a base64-encoded string — decode it to a UTF-8 string before signing. Pick one of the following:
Node.js (npm install jsonwebtoken):
JWT=$(node -e '
const jwt = require("jsonwebtoken");
const secret = Buffer.from("YOUR_BASE64_SECRET", "base64").toString("utf-8");
console.log(jwt.sign(
{ p: "YOUR_PARTNER_ID", iat: Math.floor(Date.now() / 1000) },
secret,
{ algorithm: "HS256", expiresIn: "5m" }
));
')
Python (pip install pyjwt):
JWT=$(python3 -c '
import base64, jwt, time
secret = base64.b64decode("YOUR_BASE64_SECRET").decode("utf-8")
now = int(time.time())
print(jwt.encode(
{"p": "YOUR_PARTNER_ID", "iat": now, "exp": now + 300},
secret,
algorithm="HS256",
))
')
CLI (jwt-cli, brew install mike-engel/jwt-cli/jwt-cli):
SECRET=$(printf '%s' 'YOUR_BASE64_SECRET' | base64 -d)
JWT=$(jwt encode \
--alg HS256 \
--secret "$SECRET" \
--exp '+5m' \
-P p=YOUR_PARTNER_ID)
curl -X POST "https://partner-api.padev.xyz/sell/YOUR_PARTNER_ID" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"vin": "1HGBH41JXMN109186",
"year": 2021,
"make": "Honda",
"model": "Accord",
"trim": "EX-L",
"amount": 18500,
"buyerName": "Jane Buyer",
"buyerEmail": "jane@example.com",
"buyerSendLink": true,
"sellerName": "John Seller",
"sellerEmail": "john@example.com",
"sellerSendLink": true
}'
Production host: https://partner-api.privateauto.com.
| partnerId required | string Your partner identifier, provided during onboarding (e.g. mypartner) |
| vin required | string Vehicle Identification Number (17 characters) |
| buyerName | string Buyer full name |
| buyerEmail | string Buyer email address. Convention: this field describes the OTHER party — the side being invited via the deal link. If your integration is on the buyer side, do NOT pass your own email here; pass the seller's email in |
| buyerSendLink | boolean If true, emails the buyer their deal link (requires buyerEmail) |
| sellerName | string Seller full name |
| sellerEmail | string Seller email address. Same convention as |
| sellerSendLink | boolean If true, emails the seller their deal link (requires sellerEmail) |
| year | number Vehicle model year. Required if vehicle is not already listed. |
| make | string Vehicle make. Required if vehicle is not already listed. |
| model | string Vehicle model. Required if vehicle is not already listed. |
| trim | string Vehicle trim level |
| amount | number Deal amount in dollars |
{- "vin": "1HGBH41JXMN109186",
- "buyerName": "Jane Smith",
- "buyerEmail": "buyer@example.com",
- "buyerSendLink": true,
- "sellerName": "John Doe",
- "sellerEmail": "seller@example.com",
- "sellerSendLink": true,
- "year": 2021,
- "make": "Honda",
- "model": "Civic",
- "trim": "EX",
- "amount": 18500
}{- "dealId": "64a1f2e3b5c8d90012345678",
- "guid": "b3c4d5e6-7f8a-49b0-a1b2-c3d4e5f6a7b8",
}Lead ingestion — submit and look up leads for dealer organizations on your partner allowlist. POST is idempotent via callerReferenceId and subject to per-partner rate limits.
Submit a lead for a dealer organization.
Requires a HS256, HS384, or HS512 JWT Bearer token signed with your partner shared secret.
The callerReferenceId is your own identifier for this lead (e.g. your CRM record ID).
Submitting the same callerReferenceId twice returns 409 Conflict with the existing lead ID,
so you can safely retry without creating duplicates.
Your partner account has an allowlist of organization IDs you can submit leads to.
Submitting to an org not on your allowlist returns 403 Forbidden.
{
"callerReferenceId": "LDR-98234",
"organizationId": "663a1f...",
"leadCode": "CONQUEST",
"contact": {
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "555-867-5309",
"message": "Interested in trading in my truck"
},
"vehicle": {
"vin": "1HGBH41JXMN109186",
"year": 2019,
"make": "Honda",
"model": "Accord",
"trim": "Sport",
"mileage": 42000
}
}
| partnerId required | string Your partner identifier |
| callerReferenceId required | string Your own reference ID for this lead — used for idempotent dedup. Resubmitting the same value returns 409 with the existing lead ID. |
| organizationId required | string Target dealer organization ID. Must be on your partner allowlist. |
| leadCode | string Lead code tag for categorization (e.g. CONQUEST, SERVICE, TRADE_IN) |
object Prospect contact information | |
object Vehicle of interest | |
| listingId | string Link to an existing PrivateAuto listing ID |
{- "callerReferenceId": "LDR-98234",
- "organizationId": "663a1f2b4e8c9a001234abcd",
- "leadCode": "CONQUEST",
- "contact": {
- "name": "Jane Smith",
- "email": "jane@example.com",
- "phone": "555-867-5309",
- "message": "Interested in trading in my truck"
}, - "vehicle": {
- "vin": "1HGBH41JXMN109186",
- "year": 2019,
- "make": "Honda",
- "model": "Accord",
- "trim": "Sport",
- "mileage": 42000
}, - "listingId": "663b2f3c5e9d0b002345bcde"
}{- "leadId": "663c3f4d6fae0c003456cdef",
- "callerReferenceId": "LDR-98234",
- "status": "new",
- "createdAt": "2026-04-16T14:22:00.000Z"
}Look up a previously submitted lead using your own reference ID.
Requires a HS256, HS384, or HS512 JWT Bearer token signed with your partner shared secret.
Returns the current lead status and metadata. Use this to check whether a lead was already submitted (e.g. before retrying) or to poll for status updates.
| partnerId required | string Your partner identifier |
| callerReferenceId required | string non-empty Your reference ID for the lead — the same value you passed on submission |
{- "leadId": "663c3f4d6fae0c003456cdef",
- "callerReferenceId": "LDR-98234",
- "status": "new",
- "createdAt": "2026-04-16T14:22:00.000Z"
}| partnerId required | string Your partner identifier (e.g. mypartner) |
| _page | number Default: 0 Zero-based page index |
| _limit | number Default: 50 Page size (max 100) |
| status | string Filter by status |
{- "data": [
- {
- "id": "6a0243d9a30d4d0026d00e7c",
- "guid": "653a905c-73b2-4e4b-bdf6-0e25b1e71363",
- "status": "active",
- "closingStatus": "none",
- "closingFeePayer": "buyer",
- "state": "string",
- "odometer": "string",
- "appSource": "string",
- "listingId": "string",
- "offerId": "string",
- "currentOfferStatus": "pending",
- "documentsStatus": "empty",
- "negativeEquity": true,
- "negativeEquityFunded": true,
- "amount": 0,
- "currency": "USD",
- "buyer": {
- "id": "6a0243d9a30d4d0026d00e7c",
- "organizationId": "67e446a09d2eb254a3b130e7",
- "status": "invited",
- "titleConfirmedDate": "2019-08-24T14:15:22Z",
- "confirmedDate": "2019-08-24T14:15:22Z",
- "infoCompletedAt": "2019-08-24T14:15:22Z",
- "termsConfirmedAt": "2019-08-24T14:15:22Z",
- "paymentConfirmedAt": "2019-08-24T14:15:22Z",
- "titleConfirmedAt": "2019-08-24T14:15:22Z",
- "servicesConfirmedAt": "2019-08-24T14:15:22Z",
- "titleSubmittedAt": "2019-08-24T14:15:22Z"
}, - "seller": {
- "id": "6a0243d9a30d4d0026d00e7c",
- "organizationId": "67e446a09d2eb254a3b130e7",
- "status": "invited",
- "titleConfirmedDate": "2019-08-24T14:15:22Z",
- "confirmedDate": "2019-08-24T14:15:22Z",
- "infoCompletedAt": "2019-08-24T14:15:22Z",
- "termsConfirmedAt": "2019-08-24T14:15:22Z",
- "paymentConfirmedAt": "2019-08-24T14:15:22Z",
- "titleConfirmedAt": "2019-08-24T14:15:22Z",
- "servicesConfirmedAt": "2019-08-24T14:15:22Z",
- "titleSubmittedAt": "2019-08-24T14:15:22Z"
}, - "payment": {
- "privateAutoPay": {
- "amount": 0,
- "transferDate": "2019-08-24T14:15:22Z",
- "checkDelivery": "pickup",
- "payoutSourceType": "wallet"
}, - "cash": {
- "amount": 0,
- "transferDate": "2019-08-24T14:15:22Z"
}, - "loan": {
- "amount": 0,
- "transferDate": "2019-08-24T14:15:22Z"
}, - "crypto": {
- "btc": {
- "amount": 0,
- "transferDate": "2019-08-24T14:15:22Z"
}
}
}, - "documents": [
- {
- "id": "string",
- "status": "string",
- "docClassification": "string"
}
], - "dealState": {
- "documentsStatus": "empty"
}, - "titleApprovedAt": "2019-08-24T14:15:22Z",
- "ownershipType": "owned",
- "payoffType": "LOAN",
- "loanPayoffDocs": [
- {
- "fileUrl": "string"
}
], - "loanPayoffConfirmed": true,
- "statusHistory": [
- {
- "value": "string",
- "previous": "string",
- "date": "2019-08-24T14:15:22Z"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "_meta": {
- "page": 0,
- "limit": 0,
- "total": 0,
- "hasMore": true
}
}| partnerId required | string Your partner identifier (e.g. mypartner) |
| dealId required | string Deal Mongo _id |
{- "id": "6a0243d9a30d4d0026d00e7c",
- "guid": "653a905c-73b2-4e4b-bdf6-0e25b1e71363",
- "status": "active",
- "closingStatus": "none",
- "closingFeePayer": "buyer",
- "state": "string",
- "odometer": "string",
- "appSource": "string",
- "listingId": "string",
- "offerId": "string",
- "currentOfferStatus": "pending",
- "documentsStatus": "empty",
- "negativeEquity": true,
- "negativeEquityFunded": true,
- "amount": 0,
- "currency": "USD",
- "buyer": {
- "id": "6a0243d9a30d4d0026d00e7c",
- "organizationId": "67e446a09d2eb254a3b130e7",
- "status": "invited",
- "titleConfirmedDate": "2019-08-24T14:15:22Z",
- "confirmedDate": "2019-08-24T14:15:22Z",
- "infoCompletedAt": "2019-08-24T14:15:22Z",
- "termsConfirmedAt": "2019-08-24T14:15:22Z",
- "paymentConfirmedAt": "2019-08-24T14:15:22Z",
- "titleConfirmedAt": "2019-08-24T14:15:22Z",
- "servicesConfirmedAt": "2019-08-24T14:15:22Z",
- "titleSubmittedAt": "2019-08-24T14:15:22Z"
}, - "seller": {
- "id": "6a0243d9a30d4d0026d00e7c",
- "organizationId": "67e446a09d2eb254a3b130e7",
- "status": "invited",
- "titleConfirmedDate": "2019-08-24T14:15:22Z",
- "confirmedDate": "2019-08-24T14:15:22Z",
- "infoCompletedAt": "2019-08-24T14:15:22Z",
- "termsConfirmedAt": "2019-08-24T14:15:22Z",
- "paymentConfirmedAt": "2019-08-24T14:15:22Z",
- "titleConfirmedAt": "2019-08-24T14:15:22Z",
- "servicesConfirmedAt": "2019-08-24T14:15:22Z",
- "titleSubmittedAt": "2019-08-24T14:15:22Z"
}, - "payment": {
- "privateAutoPay": {
- "amount": 0,
- "transferDate": "2019-08-24T14:15:22Z",
- "checkDelivery": "pickup",
- "payoutSourceType": "wallet"
}, - "cash": {
- "amount": 0,
- "transferDate": "2019-08-24T14:15:22Z"
}, - "loan": {
- "amount": 0,
- "transferDate": "2019-08-24T14:15:22Z"
}, - "crypto": {
- "btc": {
- "amount": 0,
- "transferDate": "2019-08-24T14:15:22Z"
}
}
}, - "documents": [
- {
- "id": "string",
- "status": "string",
- "docClassification": "string"
}
], - "dealState": {
- "documentsStatus": "empty"
}, - "titleApprovedAt": "2019-08-24T14:15:22Z",
- "ownershipType": "owned",
- "payoffType": "LOAN",
- "loanPayoffDocs": [
- {
- "fileUrl": "string"
}
], - "loanPayoffConfirmed": true,
- "statusHistory": [
- {
- "value": "string",
- "previous": "string",
- "date": "2019-08-24T14:15:22Z"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}| partnerId required | string Your partner identifier (e.g. mypartner) |
| _page | number Default: 0 Zero-based page index |
| _limit | number Default: 50 Page size (max 100) |
| status | string Filter by status |
{- "data": [
- {
- "id": "6a0243d8a30d4d0026d00e7a",
- "guid": "653a905c-73b2-4e4b-bdf6-0e25b1e71363",
- "status": "pending",
- "price": 0,
- "currency": "USD",
- "listingId": "string",
- "offeredByUserId": "string",
- "offeredByOrganizationId": "string",
- "offeredToUserId": "string",
- "offeredToOrganizationId": "string",
- "externalId": "string",
- "buyerExternalId": "string",
- "sellerExternalId": "string",
- "appSource": "string",
- "dealNowExpiration": "2019-08-24T14:15:22Z",
- "titleDeliveryMethod": "InPerson",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "_meta": {
- "page": 0,
- "limit": 0,
- "total": 0,
- "hasMore": true
}
}| partnerId required | string Your partner identifier (e.g. mypartner) |
| offerId required | string Offer Mongo _id |
{- "id": "6a0243d8a30d4d0026d00e7a",
- "guid": "653a905c-73b2-4e4b-bdf6-0e25b1e71363",
- "status": "pending",
- "price": 0,
- "currency": "USD",
- "listingId": "string",
- "offeredByUserId": "string",
- "offeredByOrganizationId": "string",
- "offeredToUserId": "string",
- "offeredToOrganizationId": "string",
- "externalId": "string",
- "buyerExternalId": "string",
- "sellerExternalId": "string",
- "appSource": "string",
- "dealNowExpiration": "2019-08-24T14:15:22Z",
- "titleDeliveryMethod": "InPerson",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}| partnerId required | string Your partner identifier (e.g. mypartner) |
| _page | number Default: 0 Zero-based page index |
| _limit | number Default: 50 Page size (max 100) |
| status | string Filter by status |
{- "data": [
- {
- "id": "6a024361a30d4d0026d00db2",
- "listingNo": "string",
- "slug": "string",
- "title": "string",
- "status": "pending",
- "sellerId": "string",
- "organizationId": "string",
- "price": 0,
- "vehicle": {
- "year": 0,
- "make": "string",
- "model": "string",
- "trim": "string",
- "vin": "WBA3B9C59FJ466190",
- "bodyStyle": "string",
- "mileage": 0,
- "exteriorColor": "string",
- "interiorColor": "string",
- "transmission": "string",
- "driveType": "string",
- "fuel": "string",
- "cylinders": "string"
}, - "ownershipInfo": {
- "ownershipType": "have-title",
- "vehicleHaveLien": true
}, - "condition": "new",
- "appSource": "string",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "_meta": {
- "page": 0,
- "limit": 0,
- "total": 0,
- "hasMore": true
}
}| partnerId required | string Your partner identifier (e.g. mypartner) |
| listingId required | string Listing Mongo _id |
{- "id": "6a024361a30d4d0026d00db2",
- "listingNo": "string",
- "slug": "string",
- "title": "string",
- "status": "pending",
- "sellerId": "string",
- "organizationId": "string",
- "price": 0,
- "vehicle": {
- "year": 0,
- "make": "string",
- "model": "string",
- "trim": "string",
- "vin": "WBA3B9C59FJ466190",
- "bodyStyle": "string",
- "mileage": 0,
- "exteriorColor": "string",
- "interiorColor": "string",
- "transmission": "string",
- "driveType": "string",
- "fuel": "string",
- "cylinders": "string"
}, - "ownershipInfo": {
- "ownershipType": "have-title",
- "vehicleHaveLien": true
}, - "condition": "new",
- "appSource": "string",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}| partnerId required | string Your partner identifier (e.g. mypartner) |
| _page | number Default: 0 Zero-based page index |
| _limit | number Default: 50 Page size (max 100) |
| status | string Enum: "delivered" "failed" "skipped" Filter by delivery status |
| event | string Filter by event name (e.g. deal.created) |
| dateFrom | string ISO 8601 — only deliveries attempted at or after this time |
| dateTo | string ISO 8601 — only deliveries attempted at or before this time |
{- "data": [
- {
- "id": "string",
- "partnerId": "string",
- "event": "deal.created",
- "status": "delivered",
- "url": "string",
- "statusCode": 0,
- "attemptedAt": "2019-08-24T14:15:22Z",
- "responseBodyExcerpt": "string",
- "error": "string",
- "payload": { }
}
], - "_meta": {
- "page": 0,
- "limit": 0,
- "total": 0,
- "hasMore": true
}
}| partnerId required | string Your partner identifier (e.g. mypartner) |
| logId required | string Outbound delivery log Mongo _id |
{- "id": "string",
- "partnerId": "string",
- "event": "deal.created",
- "status": "delivered",
- "url": "string",
- "statusCode": 0,
- "attemptedAt": "2019-08-24T14:15:22Z",
- "responseBodyExcerpt": "string",
- "error": "string",
- "payload": { }
}Returns title attachment + every documents-collection row + every platoforms_generated_documents row (Bill of Sale, etc.) linked to this deal. Use this to re-fetch documents after the original webhook signed-URL window has expired.
| partnerId required | string Your partner identifier (e.g. mypartner) |
| dealId required | string Deal Mongo _id |
{- "deal": {
- "id": "string",
- "guid": "string"
}, - "title": [
- {
- "key": "string",
- "url": "string",
- "expiresAt": "2019-08-24T14:15:22Z"
}
], - "documents": [
- {
- "id": "string",
- "docClassification": "string",
- "status": "string",
- "name": "string",
- "signers": [
- {
- "signerRole": "seller",
- "signedAt": "2019-08-24T14:15:22Z"
}
], - "signed": [
- {
- "key": "string",
- "url": "string",
- "expiresAt": "2019-08-24T14:15:22Z"
}
]
}
]
}Returns 404 if the document does not belong to a deal your org is on.
| partnerId required | string Your partner identifier (e.g. mypartner) |
| documentId required | string Document Mongo _id (from |
{- "id": "string",
- "dealId": "string",
- "docClassification": "string",
- "status": "string",
- "signers": [
- {
- "signerRole": "seller",
- "signedAt": "2019-08-24T14:15:22Z"
}
], - "signed": [
- {
- "key": "string",
- "url": "string",
- "expiresAt": "2019-08-24T14:15:22Z"
}
]
}Returns 404 if the document does not belong to a deal your org is on.
| partnerId required | string Your partner identifier (e.g. mypartner) |
| documentId required | string Generated-document Mongo _id (from |
{- "id": "string",
- "docClassification": "string",
- "name": "string",
- "signers": [
- {
- "signerRole": "seller",
- "signedAt": "2019-08-24T14:15:22Z"
}
], - "signed": [
- {
- "key": "string",
- "url": "string",
- "expiresAt": "2019-08-24T14:15:22Z"
}
]
}