The open protocol for direct orders between a pharmacy and its suppliers, labs, wholesalers and buying platforms, on top of A2A.
Version 0.1, published on 12 November 2026. Site: pharma2a.org. Contact: [email protected]. Version française.
In France, a community pharmacy orders directly from hundreds of suppliers: dermocosmetics, supplements, medical devices. Every order is a form, a mail, a phone call, then a check at delivery. PharmA2A fixes what the pharmacy's buying agent and the supplier's agent say to each other, so that an order is right the first time and the supplier learns, when the pharmacist allows it, what its products do on the shelf.
A2A (Agent2Agent, Linux Foundation) says how two agents talk.
PharmA2A says what they say: five messages, each a JSON Schema, declared as an A2A profile
extension, https://pharma2a.org/ext/v1. To our knowledge,
it is the first sector-specific dictionary built on A2A.
| Message | From | To | What it carries |
|---|---|---|---|
fiche_fournisseur |
supplier | anyone, no key | who the supplier is, its terms, its range by CIP 13 with pack size, status and VAT rate, and its list price if it chooses |
commande |
pharmacy | supplier | the purchase order: products, quantities, a reference; first as a proposal when the terms are unknown; never a price |
accuse_reception |
supplier | pharmacy | line by line: confirmed, back order, out of stock, substitution; order number, delivery date; its own prices as it states them |
etat_de_rayon |
pharmacy | supplier | only the supplier's products, only if the pharmacist allows it: stock, sales, cover |
relance |
pharmacy | supplier | a follow-up on an order already sent; never a new order |
The field names are French: PharmA2A starts with French community pharmacy, its CIP 13 codes and its words. The specification and the English guide explain every message in English.
- No economic data of the pharmacy in any message. The supplier's own terms travel as it states them, never recomputed.
- Nothing invented. A field nobody stated stays
null. - Only the supplier speaks for the supplier, and a transcribed answer never confirms an order on its own.
- A message that says nothing is not a confirmation.
- The pharmacy calls, the supplier answers. No push, no stream.
- No patient data.
An order is transmitted once: the reference is its identity, per customer account.
| Part | What it is | Where |
|---|---|---|
| The protocol | The specification and the five JSON Schemas. This is PharmA2A. | SPECIFICATION.md, schema/ |
| Sample supplier | The smallest supplier agent that speaks PharmA2A, about a hundred lines: an order in, an acknowledgement out. A template for a lab or a software vendor. | examples/sample-supplier/ |
| Supplier email bridge | A complete supplier-side agent for suppliers who only have a mailbox today: it sends the order by mail, reads the answer, and returns it as an acknowledgement. It can also exchange files with an ERP. Replies are transcribed by a language model, optional: the model's provider receives the text of the reply and, to match it, the order's reference and lines (product codes, labels, quantities); the agent never adds the pharmacy's identity or a price. | the pharma2a package, python -m pharma2a |
| Demo pharmacy | A command line that sends an order to any supplier agent and shows the acknowledgement. | python -m pharma2a.officine |
The pharma2a package also carries what every part uses: the dictionary and its validation (pharma2a.dictionnaire).
Python 3.11 or newer.
git clone https://github.com/pharma2a/pharma2a && cd pharma2a
python3 -m venv .venv && . .venv/bin/activate && pip install -e ".[modele,test]"The sample supplier, in one minute. Start it, then let the demo pharmacy order from it:
python examples/sample-supplier/agent.py
python -m pharma2a.officine --agent http://127.0.0.1:8766 --attendre 2 # in a second terminalThe supplier email bridge. It starts in draft mode: nothing is sent, mails are written to sorties/.
PHARMA2A_JETON=a-test-token python -m pharma2a
PHARMA2A_JETON=a-test-token python -m pharma2a.officine # in a second terminalIts agent card is at http://127.0.0.1:8765/.well-known/agent-card.json. Every setting is an
environment variable, listed in .env.example. python -m pytest runs the tests.
The pharmacy buying agent that SyderaAI (Paris) runs for its pharmacies speaks PharmA2A with their suppliers. No supplier runs an agent yet, so that buying agent hosts the supplier email bridge for each supplier: the supplier gets a clear mail with the order in its body, answers as usual, and the bridge transcribes the answer into the dictionary. The day a supplier serves its own agent, the pharmacy changes one URL.
Pharmacy buying agents that speak PharmA2A:
| Agent | Publisher |
|---|---|
| Mercury | SyderaAI, Paris |
To add yours, open a pull request that adds one line to this table: the agent's name, its publisher, and a contact. Pour ajouter le vôtre, ouvrez une pull request qui ajoute une ligne à ce tableau.
Issues and pull requests are welcome: see CONTRIBUTING.md,
GOVERNANCE.md and CODE_OF_CONDUCT.md. Security
reports go through SECURITY.md, never through a public issue. Versions are in
CHANGELOG.md.
The dictionary (schema/) is public domain, CC0 1.0. The agent and its tests are Apache 2.0.
PharmA2A is a trademark of SyderaAI, Paris, filed with the French INPI: the content is free,
the name is not, see TRADEMARK.md. Anyone may implement, copy, fork and extend
the protocol without asking; the name is protected only so that nobody can call "PharmA2A" what
does not follow it, which is what keeps the common language common.