docs.vin

campaign

The campaign noun — identity, lifecycle, events, and every capability as an anchored section: 27 capabilities, 0 live, 27 sandbox, 0 declared.

campaign is one of the estate's 317 automotive nouns — a job a car needs done. It carries 27 capabilities: 0 live, 27 sandbox, 0 declared · doors aggregator.vin.

Identity

Nouncampaign
PillarData (facets: 12 data · 10 services · 5 commerce)
Capabilities27 — 0 live · 27 sandbox · 0 declared
EntitiesMarketingCampaign
Doorsaggregator.vin
SDKVin.campaign.* from apis.vin
Address/catalog/campaign#{action} — the anchor IS the wire name minus campaign.

Lifecycle

MarketingCampaignCampaignLifecycleFSM: 5 states, 6 transitions — Draft · Scheduled · Live · Paused · Completed. Each transition is a past-tense event on the record.

Events

The vocabulary this noun can append to the record — 26 past-tense, versioned event types, each linked to the capability that emits it:

Discover & read

lookup

campaign.lookup · GET /campaigns/lookup · gate none · sandbox · answers CampaignLookup@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.lookup
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.lookup({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/lookup
curl 'https://apis.vin/campaigns/lookup?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.680Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignLookup@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "status": "scheduled"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "status": "scheduled"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

read

campaign.read · GET /campaigns/read · gate none · sandbox · answers CampaignRead@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.read
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.read({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/read
curl 'https://apis.vin/campaigns/read?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.712Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignRead@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "status": "scheduled"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "status": "scheduled"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

status

campaign.status · GET /campaigns/status · gate none · sandbox · answers CampaignStatus@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner
asOfstringnoformat date-time; observation instant (≡ the x-world-as-of header); the answer states the campaign lifecycle AT this instant — absent, at, or before the fixed as-of answers the unmoved world (the campaign-flight-end monitor closes a Live flight Completed past its dueAt)

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.completed@1.

the SDK — campaign.status
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.status({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/status
curl 'https://apis.vin/campaigns/status?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.721Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignStatus@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "status": "scheduled"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "status": "scheduled"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

remedyLookup

campaign.remedyLookup · GET /campaigns/remedy-lookup · gate none · sandbox · answers CampaignRemedyLookup@1

FieldTypeRequiredNotes
vinstringno

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.remedyLookup
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.remedyLookup({"vin":"1FTFW1RGXSFA22229"})
GET /campaigns/remedy-lookup
curl 'https://apis.vin/campaigns/remedy-lookup?vin=1FTFW1RGXSFA22229'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.713Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignRemedyLookup@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "remedyAvailable": false
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "remedyAvailable": false
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

statusRead

campaign.statusRead · GET /campaigns/status-read · gate none · sandbox · answers CampaignStatusRead@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.statusRead
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.statusRead({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/status-read
curl 'https://apis.vin/campaigns/status-read?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.722Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignStatusRead@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "status": "scheduled"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "status": "scheduled"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

budget

campaign.budget · POST /campaigns/budget · gate offer · sandbox · answers CampaignBudget@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.budgeted@1 · Campaign.failed@1.

the SDK — campaign.budget
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.budget({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/budget
curl -X POST https://apis.vin/campaigns/budget \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.583Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignBudget@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "budgetCents": 500000,
    "currency": "USD"
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "budgetCents": 500000,
    "currency": "USD"
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

target

campaign.target · POST /campaigns/target · gate offer · sandbox · answers CampaignTarget@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.targeted@1.

the SDK — campaign.target
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.target({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/target
curl -X POST https://apis.vin/campaigns/target \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.722Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignTarget@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "target",
      "status": "scheduled"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "target",
      "status": "scheduled"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

eligibilityCheck

campaign.eligibilityCheck · GET /campaigns/eligibility-check · gate none · sandbox · answers CampaignEligibilityCheck@1

FieldTypeRequiredNotes
vinstringno

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.eligibilityCheck
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.eligibilityCheck({"vin":"1FTFW1RGXSFA22229"})
GET /campaigns/eligibility-check
curl 'https://apis.vin/campaigns/eligibility-check?vin=1FTFW1RGXSFA22229'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.679Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignEligibilityCheck@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "eligible": false
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "eligible": false
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

Apply & book

schedule

campaign.schedule · POST /campaigns/schedule · gate offer · sandbox · answers CampaignSchedule@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.scheduleRequested@1 · Campaign.scheduled@1.

the SDK — campaign.schedule
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.schedule({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/schedule
curl -X POST https://apis.vin/campaigns/schedule \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.721Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignSchedule@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "schedule",
      "status": "scheduled"
    },
    "refusal": {
      "code": "ILLEGAL_TRANSITION",
      "from": "scheduled",
      "on": "Campaign.scheduled@1",
      "legalFrom": [
        "draft"
      ]
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "schedule",
      "status": "scheduled"
    },
    "refusal": {
      "code": "ILLEGAL_TRANSITION",
      "from": "scheduled",
      "on": "Campaign.scheduled@1",
      "legalFrom": [
        "draft"
      ]
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

create

campaign.create · POST /campaigns/create · gate offer · sandbox · answers CampaignCreate@1

FieldTypeRequiredNotes
vinstringno

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.created@1.

the SDK — campaign.create
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.create({"vin":"1FTFW1RGXSFA22229"})
POST /campaigns/create
curl -X POST https://apis.vin/campaigns/create \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.679Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignCreate@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "CAMP-1ba9593d",
      "type": "marketing",
      "action": "create",
      "status": "draft"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "CAMP-1ba9593d",
      "type": "marketing",
      "action": "create",
      "status": "draft"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

Pay & settle

pay

campaign.pay · POST /campaigns/pay · gate offer · sandbox · answers CampaignPay@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.failed@1 · Campaign.paid@1.

the SDK — campaign.pay
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.pay({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/pay
curl -X POST https://apis.vin/campaigns/pay \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.680Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignPay@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "payment": {
      "id": "PAY-5a5fcdf2",
      "status": "settled",
      "amountCents": 38000,
      "currency": "USD"
    },
    "payer": {
      "name": "Ava Good",
      "castRow": "super-prime",
      "creditTier": "super-prime"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "payment": {
      "id": "PAY-5a5fcdf2",
      "status": "settled",
      "amountCents": 38000,
      "currency": "USD"
    },
    "payer": {
      "name": "Ava Good",
      "castRow": "super-prime",
      "creditTier": "super-prime"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

settle

campaign.settle · POST /campaigns/settle · gate offer · sandbox · answers CampaignSettle@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.settleFailed@1 · Campaign.settleRequested@1 · Campaign.settled@1.

the SDK — campaign.settle
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.settle({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/settle
curl -X POST https://apis.vin/campaigns/settle \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.721Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignSettle@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "payment": {
      "id": "PAY-ce56d773",
      "status": "settled",
      "amountCents": 38000,
      "currency": "USD"
    },
    "payer": {
      "name": "Ava Good",
      "castRow": "super-prime",
      "creditTier": "super-prime"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "payment": {
      "id": "PAY-ce56d773",
      "status": "settled",
      "amountCents": 38000,
      "currency": "USD"
    },
    "payer": {
      "name": "Ava Good",
      "castRow": "super-prime",
      "creditTier": "super-prime"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

warrantyBill

campaign.warrantyBill · POST /campaigns/warranty-bill · gate offer · sandbox · answers CampaignWarrantyBill@1

FieldTypeRequiredNotes
vinstringno

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.warrantyBillRequested@1 · Campaign.warrantyBilled@1.

the SDK — campaign.warrantyBill
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.warrantyBill({"vin":"1FTFW1RGXSFA22229"})
POST /campaigns/warranty-bill
curl -X POST https://apis.vin/campaigns/warranty-bill \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.722Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignWarrantyBill@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "CAMP-1ba9593d",
    "bill": {
      "id": "CB-c23281ac",
      "billable": false,
      "amountCents": 0,
      "currency": "USD",
      "status": "nothing-to-bill"
    },
    "payer": {
      "name": "Ava Good",
      "castRow": "super-prime",
      "creditTier": "super-prime"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "CAMP-1ba9593d",
    "bill": {
      "id": "CB-c23281ac",
      "billable": false,
      "amountCents": 0,
      "currency": "USD",
      "status": "nothing-to-bill"
    },
    "payer": {
      "name": "Ava Good",
      "castRow": "super-prime",
      "creditTier": "super-prime"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

Fulfill & operate

perform

campaign.perform · POST /campaigns/perform · gate offer · sandbox · answers CampaignPerform@1

FieldTypeRequiredNotes
vinstringno

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.performFailed@1 · Campaign.performRequested@1 · Campaign.performed@1.

the SDK — campaign.perform
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.perform({"vin":"1FTFW1RGXSFA22229"})
POST /campaigns/perform
curl -X POST https://apis.vin/campaigns/perform \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.681Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignPerform@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "CAMP-1ba9593d",
    "work": {
      "id": "CW-bf6f978d",
      "operation": "perform",
      "status": "no-open-campaign"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "CAMP-1ba9593d",
    "work": {
      "id": "CW-bf6f978d",
      "operation": "perform",
      "status": "no-open-campaign"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

complete

campaign.complete · POST /campaigns/complete · gate offer · sandbox · answers CampaignComplete@1

FieldTypeRequiredNotes
vinstringno

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.completeRequested@1.

the SDK — campaign.complete
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.complete({"vin":"1FTFW1RGXSFA22229"})
POST /campaigns/complete
curl -X POST https://apis.vin/campaigns/complete \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.678Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignComplete@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "CAMP-1ba9593d",
    "work": {
      "id": "CW-a7646bd7",
      "operation": "complete",
      "status": "no-open-campaign"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "CAMP-1ba9593d",
    "work": {
      "id": "CW-a7646bd7",
      "operation": "complete",
      "status": "no-open-campaign"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

notify

campaign.notify · POST /campaigns/notify · gate offer · sandbox · answers CampaignNotify@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.notified@1 · Campaign.notifyRequested@1.

the SDK — campaign.notify
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.notify({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/notify
curl -X POST https://apis.vin/campaigns/notify \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.680Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignNotify@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "notify",
      "status": "scheduled"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "notify",
      "status": "scheduled"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

Authorize & resolve

claim

campaign.claim · POST /campaigns/claim · gate offer · sandbox · answers CampaignClaim@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.claimFailed@1 · Campaign.claimRequested@1 · Campaign.claimed@1.

the SDK — campaign.claim
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.claim({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/claim
curl -X POST https://apis.vin/campaigns/claim \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.586Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignClaim@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "payment": {
      "id": "PAY-472005e0",
      "status": "settled",
      "amountCents": 38000,
      "currency": "USD"
    },
    "payer": {
      "name": "Ava Good",
      "castRow": "super-prime",
      "creditTier": "super-prime"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "payment": {
      "id": "PAY-472005e0",
      "status": "settled",
      "amountCents": 38000,
      "currency": "USD"
    },
    "payer": {
      "name": "Ava Good",
      "castRow": "super-prime",
      "creditTier": "super-prime"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

More actions

attribution

campaign.attribution · GET /campaigns/attribution · gate key · sandbox · answers CampaignAttribution@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.attribution
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.attribution({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/attribution
curl 'https://apis.vin/campaigns/attribution?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.583Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignAttribution@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "impressions": 38459,
    "conversions": 19
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "impressions": 38459,
    "conversions": 19
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

audience

campaign.audience · GET /campaigns/audience · gate key · sandbox · answers CampaignAudience@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.audience
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.audience({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/audience
curl 'https://apis.vin/campaigns/audience?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.583Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignAudience@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "audienceSize": 3426
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "audienceSize": 3426
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

byVin

campaign.byVin · GET /campaigns/by-vin · gate none · sandbox · answers CampaignByVin@1

FieldTypeRequiredNotes
vinstringno

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.byVin
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.byVin({"vin":"1FTFW1RGXSFA22229"})
GET /campaigns/by-vin
curl 'https://apis.vin/campaigns/by-vin?vin=1FTFW1RGXSFA22229'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.586Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignByVin@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaigns": [],
    "openCount": 0
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaigns": [],
    "openCount": 0
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

equityMine

campaign.equityMine · POST /campaigns/equity-mine · gate key · sandbox · answers CampaignEquityMine@1

FieldTypeRequiredNotes
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.equityMined@1.

the SDK — campaign.equityMine
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.equityMine({"campaignId":"campaignid"})
POST /campaigns/equity-mine
curl -X POST https://apis.vin/campaigns/equity-mine \
  -H 'content-type: application/json' \
  -d '{"campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-16T14:50:09.662Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignEquityMine@1",
  "value": {
    "vin": "1HGCM82633A004352",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "candidates": 340,
    "criterion": "positive-equity"
  },
  "evidence": {
    "vin": "1HGCM82633A004352",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "candidates": 340,
    "criterion": "positive-equity"
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

launch

campaign.launch · POST /campaigns/launch · gate offer · sandbox · answers CampaignLaunch@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.launched@1.

the SDK — campaign.launch
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.launch({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/launch
curl -X POST https://apis.vin/campaigns/launch \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.679Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignLaunch@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "launch",
      "status": "live"
    },
    "transition": {
      "from": "scheduled",
      "to": "live",
      "on": "Campaign.launched@1"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "launch",
      "status": "live"
    },
    "transition": {
      "from": "scheduled",
      "to": "live",
      "on": "Campaign.launched@1"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [
    "Campaign.launched@1"
  ],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

optimize

campaign.optimize · POST /campaigns/optimize · gate offer · sandbox · answers CampaignOptimize@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.optimized@1.

the SDK — campaign.optimize
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.optimize({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/optimize
curl -X POST https://apis.vin/campaigns/optimize \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.680Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignOptimize@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "optimize",
      "status": "scheduled"
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "optimize",
      "status": "scheduled"
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

pause

campaign.pause · POST /campaigns/pause · gate offer · sandbox · answers CampaignPause@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

The gate is a 402 OFFER — the price and a hard ceiling on the wire, with a durable intent that executes on settlement. Never a wall, never "contact sales". Price: not posted — see /pricing.

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

EmitsCampaign.paused@1.

the SDK — campaign.pause
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.pause({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
POST /campaigns/pause
curl -X POST https://apis.vin/campaigns/pause \
  -H 'content-type: application/json' \
  -d '{"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"}'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.680Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignPause@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "pause",
      "status": "scheduled"
    },
    "refusal": {
      "code": "ILLEGAL_TRANSITION",
      "from": "scheduled",
      "on": "Campaign.paused@1",
      "legalFrom": [
        "live"
      ]
    }
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaign": {
      "id": "campaignid",
      "type": "marketing",
      "action": "pause",
      "status": "scheduled"
    },
    "refusal": {
      "code": "ILLEGAL_TRANSITION",
      "from": "scheduled",
      "on": "Campaign.paused@1",
      "legalFrom": [
        "live"
      ]
    }
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

performance

campaign.performance · GET /campaigns/performance · gate key · sandbox · answers CampaignPerformance@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.performance
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.performance({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/performance
curl 'https://apis.vin/campaigns/performance?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.681Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignPerformance@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "impressions": 38459,
    "conversions": 19
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "impressions": 38459,
    "conversions": 19
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

roi

campaign.roi · GET /campaigns/roi · gate key · sandbox · answers CampaignRoi@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.roi
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.roi({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/roi
curl 'https://apis.vin/campaigns/roi?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.713Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignRoi@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "roiPct": 122
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "roiPct": 122
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

spend

campaign.spend · GET /campaigns/spend · gate key · sandbox · answers CampaignSpend@1

FieldTypeRequiredNotes
vinstringno
campaignIdstringnothe marketing campaign addressed (CAMP-…); omit to address the default campaign derived from the VIN owner

Dooraggregator.vin serves this noun on its two routes: / (the landing) · /1FTFW1RGXSFA22229 (the VIN lens).

Try it — sandbox: every call answers a deterministic, provenance-labeled simulated payload ({ environment, simulated } in the body). Force any documented outcome with the magic triggers. Going live is a connect, never a ballot: submit the credential at integrates.vin (dealer systems) or connects.vin (consumer accounts) — submissions enter the activation queue and rank live rollout.

the SDK — campaign.spend
import { campaign } from 'apis.vin'

// the gate law is in the type system: Answer<T> = Ok | Empty | Blocked | Offer
const answer = await campaign.spend({"vin":"1FTFW1RGXSFA22229","campaignId":"campaignid"})
GET /campaigns/spend
curl 'https://apis.vin/campaigns/spend?vin=1FTFW1RGXSFA22229&campaignId=campaignid'

Receipt — the sandbox wire answered the request above with this exact body at build time. Captured by the receipts runner (timestamped, provenance in the payload), never authored; it re-executes only when this descriptor changes.

receipt · executed 2026-08-17T12:42:08.721Z · HTTP 200
{
  "type": "OK",
  "answers": "CampaignSpend@1",
  "value": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "spendCents": 190369,
    "currency": "USD"
  },
  "evidence": {
    "vin": "1FTFW1RGXSFA22229",
    "noun": "campaign",
    "asOf": "2026-08-10",
    "campaignId": "campaignid",
    "spendCents": 190369,
    "currency": "USD"
  },
  "provenance": {
    "simulated": true,
    "environment": "sandbox",
    "source": "aftersales-data-sandbox"
  },
  "events": [],
  "meter": {
    "charged": "0.00",
    "posted": false
  }
}

Data model

The record shape behind this noun — one entity, each property an evidence field. See the whole estate model on the data model page.

MarketingCampaign

Schema

PropertyType
idid
namestring
channelstring
dealerIdref→Dealer
leadIdref→Lead
budgetCentsmoney
statusCampaignLifecycleFSM

Relationships

FromToCardinalityAs
campaignlead*:1nurtures
campaigndealer*:1run-by

Modeled

The noun drawn out — its record shape, its lifecycle, and how it is exercised end to end. 3 diagrams, rendered from the estate model.

Campaign · Class model

Campaign · State machine

Campaign · Sequence


Generated from the catalog. Every capability, answer, gate, and entity on this page is a rendered descriptor — it cannot drift from the wire.