Skip to main content
ClaudeWave
ToolsOfficial Registry0 stars0 forksPythonMITUpdated today
ClaudeWave Trust Score
77/100
Trusted
Passed
  • Open-source license (MIT)
  • Actively maintained (<30d)
  • Documented (README)
Flags
  • !No description
Last scanned: 9/17/2026
Get started
Method: Clone
Terminal
git clone https://github.com/Ensi81/Avel
1. Clone the repository.
2. Follow the README for installation and usage instructions.
Use cases

Tools overview

# agent-interchange

SDK Python per **AVEL** (Agent Verification Layer) — verifica
identità/reputazione di chi paga e chi riceve, su qualunque metodo di
pagamento, senza mai custodire denaro. Il server è closed-source; questo
pacchetto è lo strato client, pensato per essere pubblico e riusabile
(licenza MIT). Standalone — nessuna dipendenza dal codice del server,
solo `httpx`, `eth-account` e l'URL di un'istanza raggiungibile
(`https://aisrail.fly.dev`).

<!-- mcp-name: io.github.Ensi81/avel -->

## Install

```bash
pip install -e .
```

## Uso

```python
from agent_interchange import InterchangeClient

client = InterchangeClient("https://aisrail.fly.dev")
result = client.verify(
    payer_address=agent_a_address,
    payee_id="merchant-42",
    amount=25.0,
    currency="EUR",
    private_key=agent_a_private_key,
    fee_payment_method_id="pm_...",   # con cosa si paga LA VERIFICA
)
```

**Il pagamento fra i due agenti non passa da qui.** Questa chiamata dice
soltanto se è sicuro procedere; poi l'agente paga sul rail che già usa.
Noi incassiamo solo la provvigione per il controllo eseguito (1%
dell'importo verificato, minimo 0,50 su carta) — **dovuta anche su un
verdetto DENIED**, se la firma di chi chiama è comunque valida: è il
prezzo del controllo, non dell'esito.

Tre esiti possibili:

| Risposta | Significato |
|---|---|
| `verdict: "APPROVED"` | Controllo superato, provvigione incassata: si procede |
| `verdict: "DENIED"` | Non procedere. Provvigione comunque dovuta se la firma di chi chiama è valida — gratuito solo quando non lo è (nessuno da addebitare con certezza) |
| `verdict_withheld: true` | Verifica eseguita ma provvigione non ancora incassata: il verdetto (APPROVED o DENIED) resta trattenuto finché non si paga |

`private_key` è la chiave EVM dell'agente (mai la nostra). Il primo uso
autenticato lega quell'identità all'indirizzo che firma
(trust-on-first-use): ogni chiamata successiva deve firmare con la
STESSA chiave. Nessuna registrazione preventiva.

`verify()` usa `protocol="native"`. Se l'agente sta già pagando con
x402, AP2 o MPP non serve una seconda firma: si manda la prova che ha
già prodotto per il pagamento — un esempio per ciascun protocollo è in
`scripts/protocol_adapters_demo.py`.

### Verifica simmetrica di B

Se il venditore (B) dichiara un indirizzo (`payee_address`), deve anche
provare di controllarlo — altrimenti il verdetto è negato. La firma va
calcolata da B (o da chi negozia per suo conto) su
`build_counterparty_message(payer_address, payee_id, amount, currency,
nonce)` e passata come `payee_signature`:

```python
from agent_interchange.client import build_counterparty_message

message = build_counterparty_message(payer_address, payee_id, amount, currency, nonce)
payee_signature = "0x" + Account.sign_message(encode_defunct(text=message), private_key=b_private_key).signature.hex()

result = client.verify(
    payer_address=a_address, payee_id="merchant-42", amount=25.0, currency="EUR",
    private_key=a_private_key, nonce=nonce,
    payee_address=b_address, payee_signature=payee_signature,
)
```

### Modello B-driven (protocollo `challenge`)

Più vicino a come funzionano davvero x402/MPP: è il venditore (B) a
fissare prezzo e termini e a firmarli per primo, l'acquirente (A) li
accetta firmando lo stesso testo.

```python
# Lato B — nessuna chiamata di rete, va consegnato ad A fuori banda
challenge = client.issue_challenge(
    payee_address=b_address, payee_id="merchant-42", amount=25.0, currency="EUR",
    private_key=b_private_key, ttl_seconds=600,
)

# Lato A — accetta il challenge e chiede il verdetto in un colpo solo
result = client.verify_challenge(
    challenge, payer_address=a_address, private_key=a_private_key,
    fee_payment_method_id="pm_...",   # o fee_method="x402" per pagare in stablecoin
)
```

Il challenge è valido una sola volta per la transazione esatta che lo
accetta: un ritentativo identico (necessario per completare il
pagamento della commissione dopo un 402) resta ammesso, un riuso con
termini diversi no.

### Verdetto bidirezionale

Entrambe le parti possono leggere l'esito di una transazione specifica
— non solo chi ha chiamato `verify()`/`verify_challenge()`:

```python
verdetto = client.get_verdict(
    payee_address=b_address, nonce=nonce,
    address=b_address, private_key=b_private_key,   # o quella di A
)
```

Richiede una firma che provi di essere il pagante o il ricevente di
quella transazione — a differenza dello storico aggregato
(`GET /ais/reputation/{address}`, pubblico), il dettaglio di una singola
transazione non lo è.

### Caso marketplace

Quando `payee_id`/`payee_address` sono una vetrina e non chi fornisce
davvero il prodotto/servizio, `verify()` accetta anche
`sub_merchant_address`/`sub_merchant_signature` (stesso principio di B:
la firma va calcolata su `build_sub_merchant_message(payer_address,
payee_id, amount, currency, nonce, sub_merchant_address)`). Se
dichiarato, la sua reputazione (`sub_merchant_reputation` nella
risposta) entra nel verdetto tanto quanto quella di B.

Vedi `example.py` per una versione eseguibile del flusso base.

## Metodi degli Agent Vaults — SPENTI

`pay()`, `get_balance()`, `deposit()` e `withdraw()` appartengono al
modello precedente, in cui il servizio custodiva un saldo interno. Il
server risponde ora `410` a quegli endpoint: **non custodiamo più
denaro**, nemmeno per un istante. Il codice resta ed è riattivabile lato
server con `AGENT_VAULTS_ENABLED=true`; la documentazione qui sotto è
conservata come riferimento storico.

## `InterchangeClient`

- **`verify(payer_address, payee_id, amount, currency, private_key, nonce="", payee_address=None, payee_signature=None, sub_merchant_address=None, sub_merchant_signature=None, fee_payment_method_id=None)`**
  → `dict`. Il metodo da usare per il modello "A dichiara, B conferma".
  Firma EIP-191 sul testo canonico della transazione, chiede il verdetto
  e paga la provvigione. Un `402` non è un errore ma una risposta
  prevista ("verifica passata, ora paga"): viene restituito, non
  sollevato.

- **`issue_challenge(payee_address, payee_id, amount, currency, private_key, ttl_seconds=600)`**
  → `dict`. Lato B (venditore), modello B-driven: emette e firma un
  challenge vincolante, nessuna chiamata di rete. Il risultato va
  consegnato ad A fuori banda.

- **`verify_challenge(challenge, payer_address, private_key, fee_payment_method_id=None, fee_method=None)`**
  → `dict`. Lato A (acquirente): accetta il challenge di `issue_challenge()`
  e chiede il verdetto in un'unica chiamata.

- **`get_verdict(payee_address, nonce, address, private_key)`**
  → `dict`. Verdetto bidirezionale: legge l'esito di una transazione
  specifica, utilizzabile da entrambe le parti coinvolte. Solleva
  `InterchangeAPIError` (403) se `address` non è né il pagante né il
  ricevente di quella transazione, (404) se non esiste alcun verdetto
  registrato per quel `payee_address`/`nonce`.

- **`get_agent_reputation` non è un metodo del client** — è pubblico e
  senza autenticazione: `GET {base_url}/ais/reputation/{address}` con
  una semplice richiesta HTTP.

- ~~**`pay(payer_ref, payee_ref, amount, private_key, currency="USDC", task_id=None)`**~~ *(spento, 410)*
  → `PaymentResult`. `private_key` signs an EIP-191 message binding this
  exact transaction (trust-on-first-use — see Usage above); mandatory
  since the Interchange added wallet authentication to `/pay`.
  Auto-derives `agent_request_id` from `task_id` +
  the call's own parameters (see `client._derive_request_id`) — pass your
  agent framework's own task/run id so a genuine retry (same task_id,
  same arguments) is safely idempotent, while a different payment under
  the same task_id never false-collides with it. Omitting `task_id`
  still works but loses the retry-safety property (a fresh random id is
  used, so a real retry would be treated as a brand new transaction).

  Raises:
  - `InsufficientBalanceError` — payer's balance can't cover amount + fee.
  - `RequestConflictError` — HTTP 409: the derived id was already used
    for *different* content (a possible replay/hijack of a captured
    payment proof by untrusted middleware — rejected, not executed) or
    was reserved but never completed (never retried automatically).
  - `InterchangeAPIError` — any other non-2xx response, or the
    Interchange being unreachable. 401 means `private_key` doesn't
    match the signature; 403 means `payer_ref` is already bound to a
    different address (not this key).

  A risk-score `DENY` (as opposed to an insufficient-balance one) is
  *not* raised — it comes back as a normal `PaymentResult` with
  `.success == False`; check `.decision` / `.reasons` for why.

- **`get_balance(agent_ref, private_key)`** → `dict[str, int]`, atomic
  units per currency, e.g. `{"USDC": 500000}`. `private_key` proves
  control of `agent_ref` (same trust-on-first-use binding as `pay()`);
  allowed with any key only if `agent_ref` was never used in `pay()`/
  `withdraw()` yet.

- **`withdraw(agent_ref, amount_usdc, payout_address, private_key, task_id=None)`**
  → `dict`. `private_key` is `agent_ref`'s own key, proving it
  controls the balance being withdrawn — the Interchange's own treasury
  still signs and pays out on-chain, `private_key` here only
  authenticates the withdrawal request itself. Same `task_id`
  derivation and exception contract as `pay()` (`InsufficientBalanceError`
  on HTTP 402, `RequestConflictError` on 409, 401/403 same meaning as
  `pay()`'s); any other non-2xx (e.g. 403 for an unwhitelisted
  platform-treasury withdrawal) raises `InterchangeAPIError`.

- **`await deposit(agent_ref, amount_usdc, private_key, task_id=None)`**
  → `dict`. **Async** (unlike the other three methods) and needs the
  `deposit` extra — `pip install agent-interchange[deposit]` — because
  it signs a real x402 payment with the depositing agent's own key.
  Calling it without the extra installed raises `InterchangeAPIError`
  (not an ImportError) with ins

What people ask about Avel

What is Ensi81/Avel?

+

Ensi81/Avel is tools for the Claude AI ecosystem with 0 GitHub stars.

How do I install Avel?

+

You can install Avel by cloning the repository (https://github.com/Ensi81/Avel) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is Ensi81/Avel safe to use?

+

Our security agent has analyzed Ensi81/Avel and assigned a Trust Score of 77/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.

Who maintains Ensi81/Avel?

+

Ensi81/Avel is maintained by Ensi81. The last recorded GitHub activity is dated 2026-09-16, with 0 open issues.

Are there alternatives to Avel?

+

Yes. On ClaudeWave you can browse similar tools at /categories/tools, sorted by popularity or recent activity.

Deploy Avel to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: Ensi81/Avel
[![Featured on ClaudeWave](https://claudewave.com/api/badge/ensi81-avel)](https://claudewave.com/repo/ensi81-avel)
<a href="https://claudewave.com/repo/ensi81-avel"><img src="https://claudewave.com/api/badge/ensi81-avel" alt="Featured on ClaudeWave: Ensi81/Avel" width="320" height="64" /></a>

More Tools

Avel alternatives