Passa al contenuto principale

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

  1. Usare i webhook: preferire i webhook al polling per monitorare lo stato delle pratiche
  2. Gestire gli errori: implementare retry con backoff esponenziale per errori 5xx
  3. Validare i PDF: verificare che i file siano PDF validi prima dell'invio
  4. Coordinate firma: le coordinate sono normalizzate (0–1), usare le dimensioni pagina da pagesSize per il posizionamento preciso
  5. Scadenze: impostare sempre una scadenza (expirationDateDays) per evitare pratiche dimenticate
  6. Log: mantenere un log di tutte le chiamate API e dei webhook ricevuti per troubleshooting