Interest in an offer — profile offer (draft 0.4)
On this page
- Status: draft 0.4, 2026-10-27. It may change incompatibly before it is declared stable (Versioning). It adds a profile and three tools beside the stable 1.0 parts and changes nothing in them: a consent-link holder, the registry and a forwarder that ignore this chapter stay conformant to 1.0.
- Editors: AutoIsto s. r. o.
- Licence: CC BY 4.0 (this text, the schemas and the examples)
The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in capitals.
1. Purpose#
An assistant has found a car or a flat for a person — through a search (search profile) or as a match of a standing intent (consent-link profile). The next thing the person says is "I'm interested in this one." Today the agent can only show a link; the person then copies a phone number from a page.
This profile lets the agent pass the interest to the holder that shows the offer, and lets the holder put buyer and seller in touch only when both of them have said yes — without either contact ever passing through the agent, the forwarder or the conversation:
person ──► agent ──(intent_express_interest: offerUrl, message)──► holder
◄── interestCode + confirmUrl on the holder's host ─┘
person ───────── confirms on the holder's page (own contact, double opt-in) ──► holder
holder ───────── the interest, WITHOUT the buyer's contact ──► seller (holder's own channel)
seller ───────── accepts or declines on the holder's page ──► holder
holder ───────── each party's contact to the other, by e-mail ──► buyer, seller
agent ──(intent_get_interest)──► status only: contact_shared / seller_declined / …
What the profile is not: it is not a bid, an offer to conclude a contract, a negotiation, a booking of a viewing or a payment. It carries no price. After both contacts are exchanged the holder steps out of the conversation (§5).
2. Declaring the profile#
A server that implements this profile declares "offer" in profiles of the holder descriptor
(registry chapter §2), next to consent-link (and search, if it has it). The 1.0 descriptor schema
accepts it without change. The registry does not check the profile yet (open question 4).
3. Tools#
All three are without sign-in and take no contact data: no e-mail, phone, name, address,
messenger handle or contact property in their input schemas. Rule 9 of the consent-link profile
applies: an undeclared argument is refused, and a contact field sent that way is never stored.
Every successful result carries structuredContent of type interest
(schema) and SHOULD repeat the essentials as text.
3.1 intent_express_interest#
| input | type | required | meaning |
|---|---|---|---|
offerUrl |
string, HTTPS | yes | the offer, exactly as the holder gave it: the url of a search result or of a match. It MUST be on the holder's host or below it |
message |
string, 1–1000 characters | no | what the person wants the seller to read, in the person's words and language. No contact (rule 3), no price (rule 2) |
intentCode |
string | no | the code of the person's intent with the same holder, when the offer came as its match; the holder MAY tell the seller that the buyer was watching for exactly this kind of car or flat — never the statement itself |
writtenBy |
person | agent |
no, SHOULD | whether the person dictated message or the agent composed it; when absent the holder assumes agent |
output (structuredContent) |
type | required | meaning |
|---|---|---|---|
specVersion, type |
string | yes | 0.4, interest |
status |
string | yes | awaiting_buyer_confirmation, or not_available (then no code is issued) |
interestCode |
string | when created | bearer code for the other two tools; at least 128 random bits, A–Z a–z 0–9 _ - |
confirmUrl |
string | when created | HTTPS URL on the holder's host or below it, where the person confirms; MUST NOT contain the interestCode |
confirmExpiresAt |
date-time | when created | at most 24 hours later |
offer |
object | yes | { url, title? } — the offer the interest is about |
reason |
string | with not_available |
seller-not-reachable (the holder has no channel to this seller that the seller agreed to, typically an aggregated listing), offer-gone, already-expressed, rate-limited |
With not_available the agent shows the person the offer's own page, where the holder says how to
reach that seller. A refusal of the input itself (contact in the message, a URL on another host) is a
tool error (isError: true) with a short text saying why, so that the agent can ask the person to
rephrase.
3.2 intent_get_interest and intent_withdraw_interest#
| input | type | required |
|---|---|---|
interestCode |
string | yes |
output (structuredContent) |
type | required | meaning |
|---|---|---|---|
specVersion, type |
string | yes | 0.4, interest |
found |
boolean | yes | false when the code is unknown or the record was deleted; the other fields except these are then absent |
status |
string | when found | §4 |
offer |
object | when found | { url, title? } |
updatedAt |
date-time | when found | when the status last changed |
respondBy |
date-time | with sent_to_seller |
when the holder stops waiting for the seller (§5 rule 6) |
intent_withdraw_interest answers with the new status withdrawn; after contact_shared it changes
nothing and says so (the contacts are already with the other party, §5 rule 9).
The code gives the same power as intentCode in the consent-link profile: read the status, withdraw.
It never gives access to a contact, the message, the seller's answer text or anything about the
seller beyond the status — not even after the contacts are exchanged.
4. Statuses#
awaiting_buyer_confirmation ──► sent_to_seller ──► contact_shared
│ ├──► seller_declined
│ ├──► no_response
│ └──► offer_gone
├──► expired (not confirmed within 24 h)
└──► withdrawn (also from sent_to_seller)
| status | meaning | final |
|---|---|---|
awaiting_buyer_confirmation |
the agent asked; nothing has reached the seller | no |
sent_to_seller |
the person confirmed; the seller has the interest without the buyer's contact | no |
contact_shared |
the seller accepted; the holder sent each party the other's contact | yes |
seller_declined |
the seller said no; nobody's contact moved | yes |
no_response |
respondBy passed without an answer; nobody's contact moved |
yes |
offer_gone |
the offer ended before the seller answered | yes |
withdrawn |
the person withdrew before the contacts were exchanged | yes |
expired |
the person did not confirm in time | yes |
not_available |
only in the answer of intent_express_interest; no record exists |
— |
A holder MUST NOT tell the agent why a seller declined, and MUST NOT distinguish seller_declined
from no_response by anything but these two statuses.
5. Rules#
Both sides say yes before any contact moves.
- The person confirms on the holder's page. The agent cannot confirm an interest and MUST NOT try (open the link for the person, fill in the form) — the same rule as consent-link profile rule 2. On the page the person sees exactly what the seller will receive (the message, the offer, a pseudonym, that it was sent through an AI assistant), chooses which of their verified contacts to share, and agrees that these will go to this seller only, and only if the seller accepts. A contact not verified before is verified first (double opt-in).
- No price. An interest carries no price, bid, counter-offer, deposit or hidden limit, and a holder MUST NOT accept such a field. Within this flow the holder MUST NOT propose a price, show a valuation, a price verdict or a score, or tell either side anything about the other side's price expectations. A price is for the two people to discuss once they are in touch.
- No contact in the message. The holder MUST refuse (tool error) a
messagethat contains a telephone number, an e-mail address, a URL or a messenger handle: it would hand over a contact before the seller agreed and before the person confirmed. It MUST NOT silently strip it, because the person would then believe the seller has it. - The holder delivers only to a seller who agreed to receive interests through it — the
advertiser of its own listing, or a seller who joined the holder's service — on the seller's
verified channel. It MUST NOT take a contact from a page it aggregated and write to that seller;
such offers are
not_availablewithseller-not-reachable. - What the seller sees: the offer, the message, the date, a pseudonym of the buyer that is
stable for this seller only, and that the interest was sent through an AI assistant (spec §8.3,
EU AI Act Art. 50) — with
writtenBy: agent, that the text was written by the assistant. Never the buyer's contact, statement, budget, hidden limit or other interests. - The seller answers
acceptordeclineon the holder's page. A holder setsrespondByat most 14 days aftersent_to_seller; after it the interest isno_response. Interests reach a seller in the order they were confirmed; the holder MUST NOT reorder, hold back or promote them. - The exchange. On
acceptthe holder sends, in the same step, the buyer's chosen contacts to the seller and the seller's contact to the buyer, each over that party's verified channel, and recordscontact_shared. Contacts MUST NOT appear in any tool result, notification (push profile), forwarded answer, log readable by support tools, or analytics. - Then the holder steps out. After
contact_sharedit MUST NOT negotiate for either party, arrange viewings or test drives, draft or sign contracts, collect, hold or forward money, or ask either party whether a deal was made in order to charge for it. - Withdrawal is possible in one action until
contact_shared— from the agent (intent_withdraw_interest) and from every message the holder sends the person. The confirmation page MUST say plainly that a contact already sent cannot be taken back. - Limits. At most one open interest per person and offer (
already-expressed). A holder SHOULD limit interests per person per day and per seller per day, and MAY limit the rate of calls. - Deletion. The interest record, the message and the buyer's pseudonym for that seller MUST be deleted no later than 30 days after a final status; the holder keeps only what a law obliges it to keep. Contacts delivered to the other party are that party's from then on (§7).
- Test calls (
x-isto-test: 1, consent-link profile rule 8): an interest created in a test MUST NOT reach a seller and SHOULD be withdrawn in the same session.
6. No money in the flow#
These rules keep a holder a publisher that lets two people find each other, not a broker. They are normative because an assistant and a person must be able to rely on them in every country, and a holder whose law draws the line elsewhere is free to be stricter, never looser:
- No fee, commission or other consideration from the buyer or the seller for an interest, for a contact, for a reply or for a deal — neither fixed nor depending on the outcome.
- A fee for publishing or promoting a listing, if any, MUST be the same whether or not the listing can receive interests and whether or not a deal follows.
- No order, visibility or delivery of offers or interests in this flow for payment.
- The holder MUST NOT present itself as finding a buyer for the seller or a seller for the buyer, and its terms SHOULD state that it is not an intermediary or agent of either party, has no claim to a reward from a deal, and does not act for either party.
- The holder does not touch the parties' money (rule 8).
7. Personal data (GDPR)#
| who | processes | role |
|---|---|---|
| Holder | the interest record, the message, the buyer's pseudonym and verified contacts, the seller's contact, the answer | controller. It gives the information required by Art. 13 GDPR on the confirmation page (buyer) and on the answer page (seller). The disclosure of a contact to the other party is done at that party's own request, after both have agreed (Art. 6(1)(b) — steps at the data subject's request before a contract; a holder MAY rely on consent instead). The text the person confirmed is recorded as in a Consent (text.uri, version, sha256). |
Seller, after contact_shared |
the buyer's contact | an independent controller for the contact it received |
Buyer, after contact_shared |
the seller's contact | a private person, or an independent controller when acting as a business |
| Forwarder (§8) | the message in transit, the sealed interestCode |
it keeps neither the message nor a contact (it never receives one); its privacy notice covers the transmission |
| Agent provider | the conversation | under its own terms; it never receives a contact through this profile |
- The message MAY contain personal data the person chose to write; the holder treats it as such (spec §11) and shows it only to the seller and to the person.
- A holder that hosts messages for sellers is a hosting service for them and offers a way to report an abusive message.
- A seller's refusal to receive interests through the holder (rule 4) is respected immediately and
applies to interests not yet answered as well — they become
seller_declined.
8. Through a forwarder (draft)#
A forwarder MAY offer the three tools under forwarding §3–§7, with these additions:
- It relays
intent_express_interestonly to a holder that declaresofferand has asked for forwarding under the forwarder's terms (forwarding §2). One without the other is not consent. - The holder is the one whose host the
offerUrlis on; the forwarder MUST NOT send the interest to any other holder. It checks the returnedconfirmUrlas forwarding §4 rule 1 checks aconsentUrl. - It returns its own code and keeps the holder's
interestCodesealed, as forwarding §4 rule 2 and §7 rule 2 require for anintentCode; it deletes it at the latest 60 days after the interest was expressed. - It passes
messageandwrittenByunchanged and keeps no copy of the message.
9. Example#
The structuredContent of intent_express_interest
(example):
{
"specVersion": "0.4",
"type": "interest",
"status": "awaiting_buyer_confirmation",
"interestCode": "Hq2ZbN7cW0xLk4tYp9VeR1sDf8AmJu3G",
"confirmUrl": "https://www.example-portal.pt/interest/confirm/Pw6nTq1Xs8DkVb3Lz0RaYc5Hf2MjGe7U",
"confirmExpiresAt": "2026-10-28T14:00:00Z",
"offer": {
"url": "https://www.example-portal.pt/listing/8f3k2m",
"title": "Škoda Octavia Combi 2.0 TDI Style, 2018"
}
}
and of a later intent_get_interest (example):
{
"specVersion": "0.4",
"type": "interest",
"found": true,
"status": "contact_shared",
"offer": { "url": "https://www.example-portal.pt/listing/8f3k2m" },
"updatedAt": "2026-10-29T09:12:00Z"
}
The agent then tells the person to look in their inbox: the seller's contact is there, and the seller has theirs.
10. Open questions#
- A seller's own agent. Should a seller be able to answer through an agent (a seller-side tool
intent_answer_interest, OAuth only), and how is the seller's yes then proven to be the seller's? Draft 0.4 keeps the answer on the holder's page. - Aggregated offers. Most offers a holder shows today come from other sites, so most answers will
be
not_available. Should a holder be able to hand the interest to the source site's own holder, if that site is listed in the registry and declaresoffer— a forward between holders? - Which contacts. Is the buyer's e-mail always shared, or may the person share only a phone number (verified by SMS) or only a reply through the holder's own relay address?
- Registry check. What can an automated check verify without reaching a real seller — a test
offer URL in the descriptor, answered only to
x-isto-testcalls? - Batch confirmation. A person interested in five cars confirms five times. Should a person who is signed in on the holder's site be able to confirm several interests at once, and how does that keep rule 1 (the person, not the agent, confirms each)?