API degli scontratti
L'API è JSON su HTTP, su https://scontratto-api.scontratto.workers.dev. È la stessa API degli agenti: un solo Worker, un solo database, rotte diverse.
Gli importi viaggiano come stringhe decimali in unità minime di EURC, con 6 decimali. Le scadenze sono interi in secondi Unix.
Le letture sono aperte. Le scritture, nel pilota, vogliono il token del pilota:
Authorization: Bearer <token del pilota>
Lettura
GET /health
{ ok, chainId, escrow, attestor, acp, mandateHook }: la chain, l'indirizzo dell'escrow e del suo attestatore, e quelli dei contratti degli agenti.
GET /contratti
Gli ultimi 100 scontratti, dal più recente: { contratti: [{ id, stato, tracking, scadenza }] }.
GET /contratti/:id
Lo scontratto intero: termini, stato, hash della condizione, nonce, firma di chi riceve, attestazione con la prova dell'oracolo, riferimento della transazione di regolamento, e la storia degli eventi.
Scrittura
POST /contratti/prepara
Il mandato da far firmare a chi riceve.
{
"terms": {
"payer": { "id": "payer", "proof": "wallet", "address": "0x...", "display": "Chi compra" },
"payee": { "id": "payee", "proof": "wallet", "address": "0x...", "display": "Chi spedisce" },
"money": { "amount": "5000000", "token": "EURC", "address": "0x808456652fdb597867f38412077A9182bf77359F" },
"condition": { "kind": "parcel-delivered", "carrier": "dhl", "trackingNumber": "1234567890" },
"deadline": 1792000000,
"onExpiry": "refund"
}
}
Risponde { id, nonce, mandate, domain }. mandate è il documento EIP-712 da firmare, nonce va conservato per il passo dopo, domain è l'indirizzo dell'escrow.
Chi riceve lo firma con eth_signTypedData_v4, nel dominio { name: "Scontratto", version: "1", chainId: 84532, verifyingContract: <escrow> }, con il tipo:
Mandate(address payer, address payee, address token, uint256 amount,
bytes32 conditionHash, uint64 deadline, bool executeOnExpiry, bytes32 nonce)
POST /contratti
Crea lo scontratto con la firma di chi riceve: { terms, nonce, payeeSignature }. Risponde 201 con lo stato draft. Rifiuta con 400 se la firma non è di chi riceve, o non è su questi termini.
Poi chi versa agisce sulla chain, dal suo wallet:
approve(escrow, amount)sul token EURC;Escrow.open(mandate, payeeSignature, attestor), doveattestorè l'indirizzo restituito da/health;Escrow.fund(id).
POST /contratti/:id/finanziato
Dopo il versamento: l'API controlla sulla chain che lo scontratto sia davvero finanziato e lo registra. Rifiuta con 409 se non lo è.
POST /contratti/:id/osserva
Osserva la condizione adesso, senza aspettare il cron. Se è verificata, l'attestatore firma e lo scontratto si esegue. Se è scaduto, si chiude. Si può chiamare quante volte si vuole.
POST /webhooks/aftership
Il webhook di AfterShip. Vale solo con la firma HMAC del corpo, nell'header aftership-hmac-sha256, e il token del webhook in x-scontratto-token. Osserva subito gli scontratti finanziati con quel numero di tracking.
Errori
Ogni errore è { "errore": "..." }.
Gli errori sono in italiano per default. Con Accept-Language: en, o con ?lang=en, arrivano in inglese. Gli stati HTTP e i codici non cambiano.
| Stato | Quando |
|---|---|
400 |
Termini malformati, per esempio un indirizzo non valido o un importo non intero, o una firma che non è di chi riceve. |
401 |
Manca il token del pilota, o non è quello giusto. |
404 |
Lo scontratto non esiste. |
409 |
Lo scontratto non è finanziato sulla chain. |
Il cron
Ogni cinque minuti il Worker osserva tutti gli scontratti finanziati e chiude quelli scaduti. Uno scontratto che fallisce, per esempio perché il corriere non risponde, non ferma gli altri: si riprova al giro dopo.