Esempi di Utilizzo
Esempi pratici e completi per integrare Askme Sign nelle tue applicazioni. Tutti gli esempi utilizzano l'autenticazione via API Key (X-SignToken / X-SignUser).
Esempio 1: Creare e Inviare una Pratica per la Firma
Python
import requests
import base64
# Configurazione
BASE_URL = "https://sign.askme.it/api/v2"
HEADERS = {
"X-SignToken": "your-api-token",
"X-SignUser": "your-username",
"Content-Type": "application/json"
}
def create_signing_request(pdf_path, signer_email, signer_name):
"""Crea una pratica con un documento PDF e un firmatario."""
# Leggere e codificare il PDF in Base64
with open(pdf_path, "rb") as f:
pdf_base64 = base64.b64encode(f.read()).decode("utf-8")
payload = {
"documents": [
{
"filename": "contratto.pdf",
"base64content": pdf_base64
}
],
"name": "Contratto di Servizio 2025",
"notes": "Contratto annuale di manutenzione",
"sendNotifications": True,
"expirationDateDays": 30,
"signers": [
{
"firstName": signer_name.split()[0],
"lastName": signer_name.split()[-1],
"email": signer_email,
"action": "S",
"signatureCoordinates": [
{
"document": 0,
"page": 1,
"signatureType": "S",
"positionX": 0.6,
"positionY": 0.8,
"width": 0.2,
"height": 0.08
}
]
}
]
}
response = requests.post(f"{BASE_URL}/files/send", json=payload, headers=HEADERS)
response.raise_for_status()
return response.json()
# Utilizzo
result = create_signing_request(
pdf_path="/path/to/contratto.pdf",
signer_email="[email protected]",
signer_name="Mario Rossi"
)
print(f"Pratica creata con ID: {result['idFile']}")
for signer in result.get("signers", []):
print(f"Link firma per {signer['email']}: {signer.get('signingUrl')}")
JavaScript/Node.js
const fs = require('fs');
const BASE_URL = 'https://sign.askme.it/api/v2';
const HEADERS = {
'X-SignToken': 'your-api-token',
'X-SignUser': 'your-username',
'Content-Type': 'application/json'
};
async function createSigningRequest(pdfPath, signerEmail, signerFirstName, signerLastName) {
// Leggere e codificare il PDF in Base64
const pdfBase64 = fs.readFileSync(pdfPath).toString('base64');
const payload = {
documents: [
{
filename: 'contratto.pdf',
base64content: pdfBase64
}
],
name: 'Contratto di Servizio 2025',
notes: 'Contratto annuale di manutenzione',
sendNotifications: true,
expirationDateDays: 30,
signers: [
{
firstName: signerFirstName,
lastName: signerLastName,
email: signerEmail,
action: 'S',
signatureCoordinates: [
{
document: 0,
page: 1,
signatureType: 'S',
positionX: 0.6,
positionY: 0.8,
width: 0.2,
height: 0.08
}
]
}
]
};
const response = await fetch(`${BASE_URL}/files/send`, {
method: 'POST',
headers: HEADERS,
body: JSON.stringify(payload)
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Errore ${response.status}: ${error.details}`);
}
return response.json();
}
// Utilizzo
(async () => {
const result = await createSigningRequest(
'./contratto.pdf',
'[email protected]',
'Mario',
'Rossi'
);
console.log(`Pratica creata con ID: ${result.idFile}`);
result.signers?.forEach(s =>
console.log(`Link firma per ${s.email}: ${s.signingUrl}`)
);
})();
Esempio 2: Monitorare lo Stato di una Pratica
Python
import requests
BASE_URL = "https://sign.askme.it/api/v2"
HEADERS = {
"X-SignToken": "your-api-token",
"X-SignUser": "your-username"
}
# Mappa dei codici stato
STATUS_LABELS = {
"L": "In lavorazione",
"F": "Firmato",
"R": "Rifiutato",
"E": "Scaduto",
"S": "Sospeso",
"V": "Annullato",
"U": "Caricato",
"A": "Completato",
"C": "Cestinato"
}
def check_practice_status(id_file):
"""Controlla lo stato di una pratica e dei suoi firmatari."""
response = requests.get(f"{BASE_URL}/files/{id_file}", headers=HEADERS)
response.raise_for_status()
data = response.json()
status = data.get("status", "?")
print(f"Pratica: {data['name']}")
print(f"Stato: {STATUS_LABELS.get(status, status)} ({status})")
print(f"Creata: {data['tsIns']}")
if data.get("expirationDate"):
print(f"Scadenza: {data['expirationDate']}")
print("\nFirmatari:")
for signer in data.get("signers", []):
action = signer.get("action", "?")
print(f" - {signer.get('firstName', '')} {signer.get('lastName', '')} "
f"({signer.get('email', '')}) — Azione: {action}")
return data
# Utilizzo
practice = check_practice_status(12345)
Elenco pratiche con filtri
def list_practices(status=None, page=0, size=20):
"""Recupera l'elenco delle pratiche con filtri opzionali."""
params = {"page": page, "size": size, "sort": "tsIns,desc"}
if status:
params["status"] = status
response = requests.get(f"{BASE_URL}/files/", headers=HEADERS, params=params)
response.raise_for_status()
data = response.json()
print(f"Totale pratiche: {data['totalElements']} (pagina {data['number'] + 1}/{data['totalPages']})")
for item in data["content"]:
status_label = STATUS_LABELS.get(item["status"], item["status"])
print(f" [{item['idFile']}] {item['name']} — {status_label}")
return data
# Pratiche in lavorazione
list_practices(status="L")
# Pratiche firmate
list_practices(status="F")
Esempio 3: Download del Documento Firmato
Python
import requests
BASE_URL = "https://sign.askme.it/api/v2"
HEADERS = {
"X-SignToken": "your-api-token",
"X-SignUser": "your-username"
}
def download_signed_file(id_file, output_path=None):
"""Scarica tutti i documenti di una pratica firmata."""
response = requests.get(f"{BASE_URL}/files/download/{id_file}", headers=HEADERS, stream=True)
response.raise_for_status()
# Determina il nome del file dall'header Content-Disposition
content_disp = response.headers.get("Content-Disposition", "")
if "filename=" in content_disp:
filename = content_disp.split("filename=")[1].strip('"')
else:
filename = f"pratica_{id_file}.pdf"
save_path = output_path or filename
with open(save_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"File scaricato: {save_path} ({response.headers.get('Content-Length', '?')} byte)")
return save_path
def download_single_document(id_document, output_path=None):
"""Scarica un singolo documento di una pratica."""
response = requests.get(f"{BASE_URL}/documents/download/{id_document}", headers=HEADERS, stream=True)
response.raise_for_status()
content_disp = response.headers.get("Content-Disposition", "")
if "filename=" in content_disp:
filename = content_disp.split("filename=")[1].strip('"')
else:
filename = f"documento_{id_document}.pdf"
save_path = output_path or filename
with open(save_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"Documento scaricato: {save_path}")
return save_path
# Scaricare tutti i documenti della pratica
download_signed_file(12345)
# Oppure: elencare i documenti e scaricare uno specifico
response = requests.get(f"{BASE_URL}/files/12345/documents", headers=HEADERS)
documents = response.json()
for doc in documents:
print(f" [{doc['idDocument']}] {doc['name']} — {doc['pages']} pagine")
download_single_document(doc["idDocument"])
cURL
# Download di tutti i documenti della pratica
curl -X GET "https://sign.askme.it/api/v2/files/download/12345" \
-H "X-SignToken: your-api-token" \
-H "X-SignUser: your-username" \
-o pratica-firmata.pdf
# Download di un singolo documento
curl -X GET "https://sign.askme.it/api/v2/documents/download/5001" \
-H "X-SignToken: your-api-token" \
-H "X-SignUser: your-username" \
-o documento-firmato.pdf
# Download dell'audit trail
curl -X GET "https://sign.askme.it/api/v2/files/12345/report/download" \
-H "X-SignToken: your-api-token" \
-H "X-SignUser: your-username" \
-o audit-trail.pdf
Esempio 4: Gestire i Webhook
Node.js/Express
const express = require('express');
const app = express();
app.use(express.json());
// Mappa status
const STATUS_LABELS = {
L: 'In lavorazione', F: 'Firmato', R: 'Rifiutato',
E: 'Scaduto', V: 'Annullato', A: 'Completato'
};
app.post('/webhooks/askmesign', (req, res) => {
const { idFile, name, status, action, signerEmail, time, tenantCode } = req.body;
console.log(`[${time}] Pratica ${idFile} "${name}"`);
console.log(` Stato: ${STATUS_LABELS[status] || status}`);
console.log(` Azione: ${action} — Firmatario: ${signerEmail}`);
switch (status) {
case 'F':
// Pratica completata: scaricare il documento firmato
console.log(' → Pratica completata! Avvio download...');
downloadSignedFile(idFile);
break;
case 'R':
// Pratica rifiutata: notificare il responsabile
console.log(' → Pratica rifiutata. Notifica al responsabile.');
break;
case 'E':
// Pratica scaduta: possibile reinvio
console.log(' → Pratica scaduta.');
break;
default:
// Firma intermedia: aggiornare lo stato
console.log(' → Aggiornamento stato nel database.');
}
res.status(200).json({ success: true });
});
app.listen(3000, () => console.log('Webhook server in ascolto sulla porta 3000'));
Python/Flask
from flask import Flask, request, jsonify
app = Flask(__name__)
STATUS_LABELS = {
"L": "In lavorazione", "F": "Firmato", "R": "Rifiutato",
"E": "Scaduto", "V": "Annullato", "A": "Completato"
}
@app.route("/webhooks/askmesign", methods=["POST"])
def handle_webhook():
data = request.get_json()
id_file = data.get("idFile")
status = data.get("status")
action = data.get("action")
signer_email = data.get("signerEmail")
time = data.get("time")
print(f"[{time}] Pratica {id_file} — {STATUS_LABELS.get(status, status)}")
print(f" Azione: {action} — Firmatario: {signer_email}")
if status == "F":
# Pratica completata
print(" → Download documento firmato...")
elif status == "R":
# Pratica rifiutata
print(f" → Rifiutata da {signer_email}: {data.get('notes', '')}")
return jsonify({"success": True}), 200
if __name__ == "__main__":
app.run(port=3000)
Esempio 5: Flusso Completo di Integrazione
Questo esempio mostra un flusso end-to-end: creazione pratica, monitoraggio e download.
Python
import requests
import base64
import time
BASE_URL = "https://sign.askme.it/api/v2"
HEADERS = {
"X-SignToken": "your-api-token",
"X-SignUser": "your-username",
"Content-Type": "application/json"
}
def integration_flow(pdf_path, signer_email, signer_first, signer_last):
"""Flusso completo: invio → monitoraggio → download."""
# 1. Verifica account
account = requests.get(f"{BASE_URL}/account", headers=HEADERS)
account.raise_for_status()
print(f"Autenticato come: {account.json()['firstName']} {account.json()['lastName']}")
# 2. Creazione pratica
with open(pdf_path, "rb") as f:
pdf_base64 = base64.b64encode(f.read()).decode("utf-8")
payload = {
"documents": [{"filename": "documento.pdf", "base64content": pdf_base64}],
"name": f"Pratica per {signer_first} {signer_last}",
"sendNotifications": True,
"expirationDateDays": 15,
"webhook": {
"url": "https://your-server.com/webhooks/askmesign",
"authMode": "basic",
"username": "webhook_user",
"password": "webhook_secret"
},
"signers": [
{
"firstName": signer_first,
"lastName": signer_last,
"email": signer_email,
"action": "S",
"signatureCoordinates": [
{
"document": 0, "page": 1,
"signatureType": "S",
"positionX": 0.6, "positionY": 0.8,
"width": 0.2, "height": 0.08
}
]
}
]
}
result = requests.post(f"{BASE_URL}/files/send", json=payload, headers=HEADERS)
result.raise_for_status()
data = result.json()
id_file = data["idFile"]
print(f"Pratica creata: ID {id_file}")
for signer in data.get("signers", []):
if signer.get("signingUrl"):
print(f"Link firma: {signer['signingUrl']}")
# 3. Monitoraggio (polling — in produzione usare i webhook)
print("\nIn attesa della firma (polling ogni 30s)...")
while True:
status_resp = requests.get(f"{BASE_URL}/files/{id_file}", headers=HEADERS)
status_data = status_resp.json()
current_status = status_data.get("status")
if current_status == "F":
print("Pratica firmata!")
break
elif current_status in ("R", "E", "V"):
print(f"Pratica terminata con stato: {current_status}")
return
else:
print(f" Stato: {current_status} — in attesa...")
time.sleep(30)
# 4. Download documento firmato
download = requests.get(f"{BASE_URL}/files/download/{id_file}", headers=HEADERS, stream=True)
output_file = f"pratica_{id_file}_firmata.pdf"
with open(output_file, "wb") as f:
for chunk in download.iter_content(chunk_size=8192):
f.write(chunk)
print(f"Documento firmato salvato: {output_file}")
# 5. Invio copia via email
copy_payload = {
"idFile": id_file,
"emails": ["[email protected]"],
"subject": f"Documento firmato — Pratica #{id_file}",
"message": "In allegato il documento firmato per archiviazione.",
"sendCopySender": True
}
requests.post(f"{BASE_URL}/files/send-copy", json=copy_payload, headers=HEADERS)
print("Copia inviata via email.")
# Esecuzione
integration_flow(
pdf_path="/path/to/contratto.pdf",
signer_email="[email protected]",
signer_first="Mario",
signer_last="Rossi"
)
Troubleshooting Comune
Token non valido (401)
{
"status": 401,
"details": "Token non valido o scaduto",
"reference": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Soluzione: verificare che gli header X-SignToken e X-SignUser siano corretti e che l'API Key sia attiva.
Permessi insufficienti (403)
{
"status": 403,
"details": "Utente non autorizzato per l'azione DOC_SUBMIT"
}
Soluzione: verificare che l'utente associato all'API Key abbia i permessi necessari (es. DOC_SUBMIT per creare pratiche, DOC_DOWNLOAD per scaricare documenti).
Documenti mancanti (400)
{
"status": 400,
"details": "Documenti mancanti o non validi",
"messageKey": "error.file.missingData"
}
Soluzione: verificare che l'array documents contenga almeno un elemento con base64content o externalUrl validi.
File PDF non valido (400)
Soluzione: assicurarsi che il contenuto Base64 sia codificato correttamente, senza interruzioni di riga. Verificare che il file sorgente sia un PDF valido.
Best Practices
- Usare i webhook: preferire i webhook al polling per monitorare lo stato delle pratiche
- Gestire gli errori: implementare retry con backoff esponenziale per errori 5xx
- Validare i PDF: verificare che i file siano PDF validi prima dell'invio
- Coordinate firma: le coordinate sono normalizzate (0–1), usare le dimensioni pagina da
pagesSizeper il posizionamento preciso - Scadenze: impostare sempre una scadenza (
expirationDateDays) per evitare pratiche dimenticate - Log: mantenere un log di tutte le chiamate API e dei webhook ricevuti per troubleshooting