Developer docs - protocol v0.2.0

Build agents that can negotiate.

A2CN is the shared protocol layer for cross-company commercial negotiation: discovery, mandates, signed offers, acceptance, deterministic transaction records, audit logs, and post-commitment events.

What is documented here
Quickstart: session creation, offer, acceptance, record.
Concepts: lifecycle, mandates, signatures, DIDs.
Reference: endpoints, messages, records, MCP notes.
Adapters: 11 platform adapters across procurement, CPQ, CLM, renewal, and signature.
Overview

Where A2CN fits

A2CN sits between the systems that discover commercial opportunities and the systems that execute them. A procurement, CPQ, CLM, renewal, or agent framework can translate local events into A2CN terms, let two authorized agents negotiate, and receive a content-addressed transaction record when the session completes.

Protocol boundary

Defines shared messages, turn order, mandate checks, signatures, acceptance, and record verification.

Platform boundary

Adapters translate platform-native RFx, quote, workflow, renewal, and envelope events into or out of A2CN.

Canonical implementation: the Python reference server is the executable model for v0.2.0 behavior and currently ships with 474 passing tests. Source, tests, and deeper implementation detail remain available in the GitHub repository.
Quickstart

Run a complete bilateral negotiation

The fastest way to see the protocol is the Python reference demo. It creates two agents, exchanges signed offers, accepts the final offer, and verifies that both sides produce the same transaction record hash.

terminal
git clone https://github.com/A2CN-protocol/A2CN.git
cd A2CN/reference-implementation/python
pip install -e .

python examples/saas_renewal.py
python examples/saas_renewal.py --deal-type goods_procurement
../../demos/two_process/run_demo.sh

HTTP flow in four calls

Production integrations usually use the client library or adapter helpers, but the wire flow is intentionally simple: create a session, post signed messages, then fetch the completed record.

1. create session
curl -X POST https://seller.example.com/sessions \
  -H "Authorization: Bearer $A2CN_JWT" \
  -H "Content-Type: application/a2cn+json" \
  -H "Idempotency-Key: init-001" \
  -d '{
    "message_type": "session_init",
    "message_id": "init-001",
    "protocol_version": "0.2",
    "session_params": {
      "deal_type": "saas_renewal",
      "currency": "USD",
      "max_rounds": 6,
      "session_timeout_seconds": 86400,
      "round_timeout_seconds": 3600
    },
    "initiator": {
      "did": "did:web:buyer.example",
      "agent_id": "buyer-agent",
      "verification_method": "did:web:buyer.example#key-1"
    },
    "initiator_mandate": {
      "currency": "USD",
      "max_commitment_value": 12500000
    }
  }'
2. send signed offer
curl -X POST https://seller.example.com/sessions/$SESSION_ID/messages \
  -H "Authorization: Bearer $A2CN_JWT" \
  -H "Content-Type: application/a2cn+json" \
  -H "Idempotency-Key: offer-001" \
  -d '{
    "message_type": "offer",
    "message_id": "offer-001",
    "session_id": "'"$SESSION_ID"'",
    "round_number": 1,
    "sequence_number": 1,
    "sender_did": "did:web:buyer.example",
    "sender_agent_id": "buyer-agent",
    "sender_verification_method": "did:web:buyer.example#key-1",
    "timestamp": "2026-05-31T18:00:00Z",
    "expires_at": "2026-05-31T19:00:00Z",
    "terms": {
      "deal_type": "saas_renewal",
      "currency": "USD",
      "total_value": 9500000,
      "seat_count": 100,
      "term_months": 12
    },
    "protocol_act_hash": "$PROTOCOL_ACT_HASH",
    "protocol_act_signature": "$COMPACT_JWS"
  }'
3. accept an offer
curl -X POST https://seller.example.com/sessions/$SESSION_ID/messages \
  -H "Authorization: Bearer $A2CN_JWT" \
  -H "Content-Type: application/a2cn+json" \
  -H "Idempotency-Key: accept-001" \
  -d '{
    "message_type": "acceptance",
    "message_id": "accept-001",
    "session_id": "'"$SESSION_ID"'",
    "in_reply_to": "offer-001",
    "round_number": 1,
    "sequence_number": 2,
    "accepted_offer_id": "offer-001",
    "accepted_protocol_act_hash": "$PROTOCOL_ACT_HASH",
    "sender_did": "did:web:seller.example",
    "sender_agent_id": "seller-agent",
    "sender_verification_method": "did:web:seller.example#key-1",
    "timestamp": "2026-05-31T18:04:00Z",
    "acceptance_signature": "$ACCEPTANCE_JWS"
  }'
4. fetch record
curl https://seller.example.com/sessions/$SESSION_ID/record \
  -H "Authorization: Bearer $A2CN_JWT" \
  -H "Accept: application/a2cn+json"
Lifecycle

Message lifecycle

Sessions are bilateral and turn-based. Round 1 begins with an offer; later commercial proposals are counteroffer messages. A terminal message creates either a completed record or an auditable terminal state.

01
Discover

Fetch /.well-known/a2cn-agent to learn endpoint, DID, deal types, and verification method.

02
SessionInit

Initiator proposes deal type, timeouts, currency, and mandate.

03
Negotiate

Offer and counteroffer messages carry signed protocol acts.

04
Accept

Acceptance signs the canonical accepted-offer payload.

05
Record

Both parties independently compute the same transaction record hash.

Concepts

Core protocol concepts

SessionInit / SessionAck

SessionInit declares requested session parameters and the initiator mandate. SessionAck binds the responder, accepted parameters, responder mandate, and initial turn.

Offers and counteroffers

Each commercial proposal contains canonical terms, a protocol-act hash, and a compact JWS over that hash.

Mandates

Declared mandates constrain agent authority, including hard max commitment value checks before state mutation.

DID-backed signatures

JWT auth and protocol-act signatures resolve DID documents and accept only signing-capable verification methods.

Transaction records

Completed sessions emit deterministic records linking final terms, offer chain, acceptance, parties, mandates, and signatures.

Post-commitment events

Delivery, acknowledgment, dispute, resolution, contract, and signature workflows can reference the record hash without reopening negotiation.

Reference

Reference server endpoints

The Python server is implemented with FastAPI and returns application/a2cn+json for protocol endpoints. State-mutating endpoints use Bearer JWT authentication, except inbound POST /invitations, which authenticates by invitation signature.

Endpoint Purpose Auth
GET /.well-known/a2cn-agent Discovery document: endpoint, DID, verification method, conformance level, deal types. public
POST /sessions Create a session from session_init and receive session_ack. Bearer JWT
GET /sessions/{session_id} Read canonical session state. Bearer JWT
POST /sessions/{session_id}/messages Send offer, counteroffer, acceptance, rejection, or withdrawal. Bearer JWT
POST /sessions/{session_id}/approval-receipt Release a human-approval pause with an authorized approval receipt. Bearer JWT
GET /sessions/{session_id}/messages Paginated message history after a sequence number. Bearer JWT
GET /sessions/{session_id}/record Fetch deterministic transaction record for completed sessions. Bearer JWT
GET /sessions/{session_id}/audit Fetch audit log for any terminal session. Bearer JWT
GET /sessions/{session_id}/fulfillment-attestation Fetch the Concordia-shaped fulfillment attestation emitted after clean delivery acceptance or dispute resolution. Bearer JWT
POST /invitations Receive a signed session invitation at cold start. invitation signature

Message shapes

Message Required identity fields Commitment fields
session_init initiator.did, initiator.verification_method session_params, initiator_mandate
offer / counteroffer sender_did, sender_agent_id, sender_verification_method terms, protocol_act_hash, protocol_act_signature
acceptance sender_did, sender_agent_id, sender_verification_method accepted_offer_id, accepted_protocol_act_hash, acceptance_signature
post-commitment events event sender identity and session ID transaction_record_hash plus event-specific evidence
Records

Transaction records and audit logs

A completed A2CN negotiation produces a deterministic transaction record. The verifier checks record hash integrity, accepted-offer linkage, the offer-chain hash, and both party signatures. This makes the record usable as a neutral artifact for CLM, signature, payment, custody, and dispute workflows.

When post-commitment fulfillment reaches a terminal state, the reference server can also expose a Concordia-shaped FulfillmentAttestation. A clean delivery_acknowledged emits fulfilled_clean; dispute_resolved emits fulfilled_with_mediation with resolver metadata.

python
from a2cn.record import generate_transaction_record, verify_transaction_record

record = generate_transaction_record(session)
ok = verify_transaction_record(
    record,
    did_resolver={
        "did:web:buyer.example": buyer_did_document,
        "did:web:seller.example": seller_did_document,
    },
)
assert ok is True

Audit logs are available for terminal sessions and include the message log, terminal state, mandate context, and AI-system metadata such as whether human oversight was present.

Agents

MCP and agent integration notes

Agent frameworks should keep commercial reasoning separate from protocol custody. The agent can choose terms and negotiation strategy; the A2CN client/server layer should canonicalize, hash, sign, verify, enforce mandates, and store the record.

LLM agent loop

Use MCP tools or client wrappers to expose safe actions: start session, propose terms, accept offer, inspect record.

Separation of concerns

Never ask the model to invent hashes, signatures, mandate checks, or DID verification. Those belong in deterministic code.

agent action surface
tools:
  - a2cn.discover_agent(endpoint)
  - a2cn.start_session(endpoint, session_params, mandate)
  - a2cn.send_offer(session_id, terms)
  - a2cn.accept_offer(session_id, offer_id)
  - a2cn.get_transaction_record(session_id)
Integrations

Adapter docs index

Adapters are thin translation layers. They should preserve platform IDs, normalize money into integer minor units, and leave commitment authority to A2CN mandates and signatures.

Vendr

saas_renewalMCPwebhooks

Vendr benchmark and renewal context can seed an A2CN SaaS renewal session. The clean path is MCP-to-MCP: an agent asks Vendr for pricing intelligence, converts it into A2CN terms, and lets A2CN own the bilateral negotiation and record.

In

Renewal webhook or MCP pricing benchmark.

A2CN

saas_renewal terms with integer-cent values and mandate context.

Back

Summary artifact for CRM, sourcing notes, or agent memory. Vendr webhooks are one-way.

Source guide on GitHub →

Ironclad

CLMwebhooksrecords

Ironclad workflow attributes become A2CN commercial terms, while completed A2CN sessions can write final values and record hashes back to Ironclad workflow metadata or record properties.

In

Workflow webhook with contract value, counterparty, dates, and line attributes.

A2CN

Heuristic routing to saas_renewal or goods_procurement.

Back

Workflow metadata update or POST /records payload with a2cnRecordHash.

Source guide on GitHub →

SAP Ariba

goods_procurementRFxOAuth

SAP Ariba Event Management and Discovery RFx publication events map into A2CN goods procurement terms. The adapter preserves Ariba item and lot IDs for bid reconstruction.

In

Event items or Discovery RFx lots with quantities, unit prices, and delivery terms.

A2CN

goods_procurement terms with normalized total value and line items.

Back

Ariba bid payload or RFx acknowledgement with original item and lot identifiers.

Source guide on GitHub →

JAGGAER

goods_procurementASOpush/poll

JAGGAER ASO customer-host and sourcing events translate to A2CN goods procurement terms. Integrations can start from event-driven push payloads or CHES polling.

In

ASO sourcing event, CHES event response, or tenant-normalized push event.

A2CN

Line-item goods terms retaining jaggaer_item_id and jaggaer_lot_id.

Back

Response payload with prices converted from cents back to decimal values.

Source guide on GitHub →

Conga

CPQCLMSalesforce

Conga CPQ quote and cart payloads can start A2CN sessions, and completed A2CN records can be linked back to Conga CLM agreements.

In

Quote/cart line items from Conga CPQ, Salesforce SOQL shapes, or Advantage Platform payloads.

A2CN

Keyword heuristic selects saas_renewal or goods_procurement.

Back

Quote update payload plus CLM external references for session ID and record hash.

Source guide on GitHub →

DocuSign

eSignatureConnectpost-commitment

DocuSign is a formalization layer after A2CN completes. The adapter turns a dual-signed transaction record into an envelope and parses Connect callbacks into post-commitment status.

In

Completed A2CN transaction record with parties, contacts, final terms, and record hash.

A2CN

A2CN remains the canonical commercial commitment; DocuSign executes signature workflow.

Back

Connect events mark signature completed, declined, or voided.

Source guide on GitHub →

DealHub

CPQsaas_renewalwebhooks

DealHub quote-ready webhooks and quote details become A2CN SaaS renewal sessions. Completed records can be linked back through DealHub Actions API calls.

In

quoteReady webhook plus quote detail fetch.

A2CN

saas_renewal terms with total value, seat count, tier, and term length.

Back

External-signature action marking the quote won with A2CN audit notes.

Source guide on GitHub →

Nue.io

revenue lifecycleordersrenewals

Nue pricing, subscription, and order data can seed A2CN session terms and receive agreed terms back as Nue order creation payloads with audit references.

In

Pricing, subscription renewal, or quote/order payload from Nue.

A2CN

SaaS renewal terms and mandate bounds based on floor discount configuration.

Back

Nue order payload with a2cn_session_id, record hash, and notes.

Source guide on GitHub →

Salesforce Revenue Cloud

CPQorderssource

The Revenue Cloud adapter translates Salesforce Pricing API responses into A2CN offer terms and maps agreed terms back into Revenue Cloud order payloads.

In

Pricing response from /connect/pricing/....

A2CN

Commercial terms normalized for negotiation and commitment checks.

Back

Order payload for /connect/qoc/sales-transactions.

Adapter source on GitHub →

Fairmarkit

sourcinggoods_procurementsource

Fairmarkit BID_CREATED sourcing webhooks can be parsed into A2CN goods procurement terms and sent back as response payloads when negotiation completes.

In

Bid-created webhook with request ID, item quantities, unit prices, and deadline.

A2CN

goods_procurement terms with line items and delivery days.

Back

Supplier response payload referencing the completed A2CN session.

Adapter source on GitHub →

Keelvar

sourcingoptimizationsource

Keelvar sourcing optimization events can trigger A2CN sessions, with agreed terms converted back into Keelvar response shapes for bid submission or audit.

In

Sourcing event or invitation accepted into an A2CN session.

A2CN

Goods procurement terms aligned with Keelvar item and event context.

Back

Keelvar response payload from completed transaction-record terms.

Adapter source on GitHub →