L'API di LegallyMail ti permette di inviare email certificate dalla tua applicazione. Tutti gli invii vengono registrati e puoi ottenere certificati legali di consegna e lettura.
Tutte le richieste all'API richiedono autenticazione tramite un token di accesso. Puoi ottenere il tuo token dal pannello utente.
Includi il token nell'header Authorization:
Authorization: Bearer YOUR_TOKEN_HERE
Includi il token nel JSON del corpo:
{
"token": "YOUR_TOKEN_HERE",
"recipient": "[email protected]",
...
}
Per ottenere un token API, devi prima aver effettuato almeno un pagamento. Successivamente puoi creare token dal tuo pannello utente.
Accedi/api/send
Invia un'email certificata.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
Authorization |
string (header) | Sì | Token di autenticazione in formato "Bearer {token}" o solo il token |
recipient / to |
string | Sì |
Indirizzo email del destinatario
Destinatari Multipli:
È possibile inviare a più destinatari separando gli indirizzi email con virgole (es: "[email protected], [email protected], [email protected]")
Limite predefinito: 10 destinatari. Questo limite può essere esteso su richiesta contattando il supporto. |
subject |
string | Sì | Oggetto dell'email |
message / body / content |
string (HTML) | Sì | Contenuto dell'email in formato HTML |
reply_to |
string (email) | No | Indirizzo e-mail per le risposte. Deve essere un mittente registrato e verificato nel tuo account (opzionale). |
reply_to_name |
string | No | Nome per le risposte (opzionale) |
attachments |
array | No | Array di file allegati (opzionale). Ogni file deve avere: filename, content (base64), mime_type |
webhook_url |
string | No | URL HTTPS pubblico in cui LegallyMail invierà un POST in tempo reale con gli eventi (opzionale). |
webhook_secret |
string | No | Segreto condiviso per convalidare la firma HMAC-SHA256 nell'intestazione X-LegallyMail-Signature (opzionale ma consigliato). |
curl -X POST https://legallymail.com/api/send \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"recipient": "[email protected], [email protected], [email protected]",
"subject": "Test Email with Multiple Recipients",
"message": "<h1>Hello World</h1><p>This email is sent to multiple recipients.</p>",
"attachments": [
{
"filename": "document.pdf",
"content": "base64_encoded_file_content_here",
"mime_type": "application/pdf"
}
]
}'
<?php
$token = 'YOUR_TOKEN_HERE';
$url = 'https://legallymail.com/api/send';
// Leer el archivo y codificarlo en base64
$filePath = '/path/to/document.pdf';
$fileContent = base64_encode(file_get_contents($filePath));
$data = [
'recipient' => '[email protected], [email protected], [email protected]',
'subject' => 'Test Email with Multiple Recipients',
'message' => '<h1>Hello World</h1><p>This email is sent to multiple recipients.</p>',
'attachments' => [
[
'filename' => 'document.pdf',
'content' => $fileContent,
'mime_type' => 'application/pdf'
]
]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
?>
import requests
import base64
token = 'YOUR_TOKEN_HERE'
url = 'https://legallymail.com/api/send'
# Leer el archivo y codificarlo en base64
with open('/path/to/document.pdf', 'rb') as file:
file_content = base64.b64encode(file.read()).decode('utf-8')
data = {
'recipient': '[email protected], [email protected], [email protected]',
'subject': 'Test Email with Multiple Recipients',
'message': '<h1>Hello World</h1><p>This email is sent to multiple recipients.</p>',
'attachments': [
{
'filename': 'document.pdf',
'content': file_content,
'mime_type': 'application/pdf'
}
]
}
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
response = requests.post(url, json=data, headers=headers)
result = response.json()
const token = 'YOUR_TOKEN_HERE';
const url = 'https://legallymail.com/api/send';
// Leer el archivo y codificarlo en base64 (Node.js)
const fs = require('fs');
const filePath = '/path/to/document.pdf';
const fileContent = fs.readFileSync(filePath).toString('base64');
const data = {
recipient: '[email protected], [email protected], [email protected]',
subject: 'Test Email with Multiple Recipients',
message: '<h1>Hello World</h1><p>This email is sent to multiple recipients.</p>',
attachments: [
{
filename: 'document.pdf',
content: fileContent,
mime_type: 'application/pdf'
}
]
};
fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.error('Error:', error));
package main
import (
'bytes'
'encoding/base64'
'encoding/json'
'io/ioutil'
'net/http'
)
func main() {
token := 'YOUR_TOKEN_HERE'
url := 'https://legallymail.com/api/send'
// Leer el archivo y codificarlo en base64
filePath := '/path/to/document.pdf'
fileContent, _ := ioutil.ReadFile(filePath)
fileBase64 := base64.StdEncoding.EncodeToString(fileContent)
data := map[string]interface{}{
'recipient': '[email protected], [email protected], [email protected]',
'subject': 'Test Email with Multiple Recipients',
'message': '<h1>Hello World</h1><p>This email is sent to multiple recipients.</p>',
'attachments': []map[string]string{
{
'filename': 'document.pdf',
'content': fileBase64,
'mime_type': 'application/pdf',
},
},
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest('POST', url, bytes.NewBuffer(jsonData))
req.Header.Set('Authorization', 'Bearer '+token)
req.Header.Set('Content-Type', 'application/json')
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import com.google.gson.Gson;
public class SendEmail {
public static void main(String[] args) throws IOException, InterruptedException {
String token = 'YOUR_TOKEN_HERE';
String url = 'https://legallymail.com/api/send';
// Leer el archivo y codificarlo en base64
String filePath = '/path/to/document.pdf';
byte[] fileBytes = Files.readAllBytes(Paths.get(filePath));
String fileBase64 = Base64.getEncoder().encodeToString(fileBytes);
Map<String, Object> attachment = new HashMap<>();
attachment.put('filename', 'document.pdf');
attachment.put('content', fileBase64);
attachment.put('mime_type', 'application/pdf');
Map<String, Object> data = new HashMap<>();
data.put('recipient', '[email protected]');
data.put('subject', 'Test Email with Attachment');
data.put('message', '<h1>Hello World</h1><p>This email contains an attachment.</p>');
data.put('attachments', Arrays.asList(attachment));
Gson gson = new Gson();
String jsonData = gson.toJson(data);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header('Authorization', 'Bearer ' + token)
.header('Content-Type', 'application/json')
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
}
}
const https = require('https');
const fs = require('fs');
const token = 'YOUR_TOKEN_HERE';
const url = 'https://legallymail.com/api/send';
// Leer el archivo y codificarlo en base64
const filePath = '/path/to/document.pdf';
const fileContent = fs.readFileSync(filePath).toString('base64');
const data = {
recipient: '[email protected]',
subject: 'Test Email with Attachment',
message: '<h1>Hello World</h1><p>This email contains an attachment.</p>',
attachments: [
{
filename: 'document.pdf',
content: fileContent,
mime_type: 'application/pdf'
}
]
};
const options = {
hostname: 'legallymail.com',
path: '/api/send',
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
};
const req = https.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
const result = JSON.parse(responseData);
console.log(result);
});
});
req.on('error', (error) => {
console.error('Error:', error);
});
req.write(JSON.stringify(data));
req.end();
using System;
using System.Net.Http;
using System.Text;
using System.IO;
using Newtonsoft.Json;
class Program
{
static async System.Threading.Tasks.Task Main()
{
string token = 'YOUR_TOKEN_HERE';
string url = 'https://legallymail.com/api/send';
// Leer el archivo y codificarlo en base64
string filePath = '/path/to/document.pdf';
byte[] fileBytes = File.ReadAllBytes(filePath);
string fileBase64 = Convert.ToBase64String(fileBytes);
var attachment = new
{
filename = 'document.pdf',
content = fileBase64,
mime_type = 'application/pdf'
};
var data = new
{
recipient = '[email protected], [email protected], [email protected]',
subject = 'Test Email with Multiple Recipients',
message = '<h1>Hello World</h1><p>This email is sent to multiple recipients.</p>',
attachments = new[] { attachment }
};
string jsonData = JsonConvert.SerializeObject(data);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add('Authorization', 'Bearer ' + token);
var content = new StringContent(jsonData, Encoding.UTF8, 'application/json');
var response = await client.PostAsync(url, content);
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}
}
{
"success": true,
"message": "Email sent to 2 of 2 recipients",
"data": {
"tracking_id": "cm_parent_abc123",
"recipients": [
{
"email": "[email protected]",
"status": "sent",
"tracking_id": "cm_rec1_xyz",
"error_details": null
},
{
"email": "[email protected]",
"status": "sent",
"tracking_id": "cm_rec2_abc",
"error_details": null
}
],
"subject": "Test Email",
"sent_at": "2024-01-15 10:30:00",
"success_count": 2,
"fail_count": 0,
"error_status": null
}
}
/api/info
Ottiene informazioni sull'API e l'utente autenticato
Restituisce informazioni sull'API e l'utente autenticato, inclusi email, piano sottoscritto ed email rimanenti.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
Authorization |
string (header) | Sì | Token di autenticazione in formato "Bearer {token}" o solo il token |
curl -X GET https://legallymail.com/api/info \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
<?php
$token = 'YOUR_TOKEN_HERE';
$url = 'https://legallymail.com/api/info';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
?>
import requests
token = 'YOUR_TOKEN_HERE'
url = 'https://legallymail.com/api/info'
headers = {
'Authorization': f'Bearer {token}'
}
response = requests.get(url, headers=headers)
result = response.json()
const token = 'YOUR_TOKEN_HERE';
const url = 'https://legallymail.com/api/info';
fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.error('Error:', error));
package main
import (
'net/http'
'io/ioutil'
)
func main() {
token := 'YOUR_TOKEN_HERE'
url := 'https://legallymail.com/api/info'
req, _ := http.NewRequest('GET', url, nil)
req.Header.Set('Authorization', 'Bearer '+token)
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class GetInfo {
public static void main(String[] args) throws Exception {
String token = 'YOUR_TOKEN_HERE';
String url = 'https://legallymail.com/api/info';
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header('Authorization', 'Bearer ' + token)
.GET()
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
}
}
const https = require('https');
const token = 'YOUR_TOKEN_HERE';
const url = 'https://legallymail.com/api/info';
const options = {
hostname: 'legallymail.com',
path: '/api/info',
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
};
const req = https.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
const result = JSON.parse(responseData);
console.log(result);
});
});
req.on('error', (error) => {
console.error('Error:', error);
});
req.end();
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string token = 'YOUR_TOKEN_HERE';
string url = 'https://legallymail.com/api/info';
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add('Authorization', 'Bearer ' + token);
var response = await client.GetAsync(url);
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}
}
{
"name": "LegallyMail API",
"version": "1.0.0",
"user": {
"email": "[email protected]",
"name": "Nombre Usuario",
"plan": "professional",
"plan_name": "Profesional",
"plan_limit": 100,
"extra_emails": 0,
"remaining_emails": 75
}
}
/api/emails
Ottiene le ultime email inviate
Restituisce un elenco delle ultime email inviate dall'utente autenticato, incluso il loro stato (sent, read, failed). Massimo 25 risultati.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
Authorization |
string (header) | Sì | Token di autenticazione in formato "Bearer {token}" o solo il token |
limit |
integer (query) | Sì | Numero di email da restituire (tra 1 e 25). Obbligatorio. |
curl -X GET "https://legallymail.com/api/emails?limit=10" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
<?php
$token = 'YOUR_TOKEN_HERE';
$url = 'https://legallymail.com/api/emails?limit=10';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
?>
import requests
token = 'YOUR_TOKEN_HERE'
url = 'https://legallymail.com/api/emails'
params = {'limit': 10}
headers = {
'Authorization': f'Bearer {token}'
}
response = requests.get(url, params=params, headers=headers)
result = response.json()
const token = 'YOUR_TOKEN_HERE';
const url = 'https://legallymail.com/api/emails?limit=10';
fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.error('Error:', error));
package main
import (
'net/http'
'io/ioutil'
)
func main() {
token := 'YOUR_TOKEN_HERE'
url := 'https://legallymail.com/api/emails?limit=10'
req, _ := http.NewRequest('GET', url, nil)
req.Header.Set('Authorization', 'Bearer '+token)
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class GetEmails {
public static void main(String[] args) throws Exception {
String token = 'YOUR_TOKEN_HERE';
String url = 'https://legallymail.com/api/emails?limit=10';
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header('Authorization', 'Bearer ' + token)
.GET()
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
}
}
const https = require('https');
const token = 'YOUR_TOKEN_HERE';
const url = 'https://legallymail.com/api/emails?limit=10';
const options = {
hostname: 'legallymail.com',
path: '/api/emails?limit=10',
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
};
const req = https.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
const result = JSON.parse(responseData);
console.log(result);
});
});
req.on('error', (error) => {
console.error('Error:', error);
});
req.end();
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string token = 'YOUR_TOKEN_HERE';
string url = 'https://legallymail.com/api/emails?limit=10';
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add('Authorization', 'Bearer ' + token);
var response = await client.GetAsync(url);
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}
}
{
"success": true,
"count": 2,
"limit": 10,
"max_limit": 25,
"emails": [
{
"id": 123,
"tracking_id": "cm_abc123",
"recipient": "[email protected]",
"subject": "Test Email",
"status": "read",
"sent_at": "2024-01-15 10:30:00",
"read_at": "2024-01-15 11:00:00",
"created_at": "2024-01-15 10:30:00",
"mailsender_id": "mail_xyz789",
"is_multi_recipient": false,
"recipient_count": 1,
"error_status": null
},
{
"id": 122,
"tracking_id": "cm_def456",
"recipient": "Multiple Recipients",
"subject": "Group Email",
"status": "pending",
"sent_at": "2024-01-14 15:20:00",
"read_at": null,
"created_at": "2024-01-14 15:20:00",
"mailsender_id": "mail_uvw012",
"is_multi_recipient": true,
"recipient_count": 5,
"error_status": "Soft Bounce"
}
]
}
/api/email
Ottiene lo stato di un'email specifica
Restituisce le informazioni dettagliate di un'email specifica identificata dal suo tracking_id, incluso il suo stato attuale (sent, read, failed), le date di invio e lettura, e i certificati di timestamp (TSQ/TSR) se esistono.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
Authorization |
string (header) | Sì | Token di autenticazione in formato "Bearer {token}" o solo il token |
tracking_id |
string (query) | Sì | L'identificatore unico di tracciamento dell'email (tracking_id) restituito all'invio dell'email. |
curl -X GET "https://legallymail.com/api/email?tracking_id=cm_abc123" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
<?php
$token = 'YOUR_TOKEN_HERE';
$trackingId = 'cm_abc123';
$url = 'https://legallymail.com/api/email?tracking_id=' . urlencode($trackingId);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
?>
import requests
token = 'YOUR_TOKEN_HERE'
url = 'https://legallymail.com/api/email'
params = {'tracking_id': 'cm_abc123'}
headers = {
'Authorization': f'Bearer {token}'
}
response = requests.get(url, params=params, headers=headers)
result = response.json()
const token = 'YOUR_TOKEN_HERE';
const trackingId = 'cm_abc123';
const url = `https://legallymail.com/api/email?tracking_id=${trackingId}`;
fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.error('Error:', error));
package main
import (
'net/http'
'io/ioutil'
'net/url'
)
func main() {
token := 'YOUR_TOKEN_HERE'
trackingId := 'cm_abc123'
baseUrl := 'https://legallymail.com/api/email'
params := url.Values{}
params.Add('tracking_id', trackingId)
fullUrl := baseUrl + '?' + params.Encode()
req, _ := http.NewRequest('GET', fullUrl, nil)
req.Header.Set('Authorization', 'Bearer '+token)
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class GetEmail {
public static void main(String[] args) throws Exception {
String token = 'YOUR_TOKEN_HERE';
String trackingId = 'cm_abc123';
String url = 'https://legallymail.com/api/email?tracking_id=' + trackingId;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header('Authorization', 'Bearer ' + token)
.GET()
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
}
}
const https = require('https');
const token = 'YOUR_TOKEN_HERE';
const trackingId = 'cm_abc123';
const url = `https://legallymail.com/api/email?tracking_id=${trackingId}`;
const options = {
hostname: 'legallymail.com',
path: `/api/email?tracking_id=${trackingId}`,
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
};
const req = https.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
const result = JSON.parse(responseData);
console.log(result);
});
});
req.on('error', (error) => {
console.error('Error:', error);
});
req.end();
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string token = 'YOUR_TOKEN_HERE';
string trackingId = 'cm_abc123';
string url = $"https://legallymail.com/api/email?tracking_id={trackingId}";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add('Authorization', 'Bearer ' + token);
var response = await client.GetAsync(url);
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}
}
{
"success": true,
"email": {
"id": 123,
"tracking_id": "cm_abc123",
"recipient": "Multiple Recipients",
"subject": "Group Email",
"status": "pending",
"sent_at": "2024-01-15 10:30:00",
"read_at": null,
"created_at": "2024-01-15 10:30:00",
"mailsender_id": "mail_xyz789",
"is_multi_recipient": true,
"recipient_count": 2,
"error_status": null,
"certificates": [],
"recipients": [
{
"email": "[email protected]",
"name": "Recipient One",
"status": "read",
"tracking_id": "cm_rec1_xyz",
"sent_at": "2024-01-15 10:30:05",
"delivered_at": "2024-01-15 10:30:10",
"read_at": "2024-01-15 11:00:00",
"error_details": null,
"certificates": [
{
"certificate_type": "read",
"file_hash": "sha256_hash_read_1",
"confirmed_at": "2024-01-15 11:00:00",
"has_tsr": true,
"has_tsq": true,
"pdf_download_url": "https://legallymail.com/emails/download-certificate?id=cm_rec1_xyz&status=read"
}
]
},
{
"email": "[email protected]",
"name": "Recipient Two",
"status": "delivered",
"tracking_id": "cm_rec2_abc",
"sent_at": "2024-01-15 10:30:05",
"delivered_at": "2024-01-15 10:30:12",
"read_at": null,
"error_details": "Recipient inbox full",
"certificates": [
{
"certificate_type": "delivered",
"file_hash": "sha256_hash_del_2",
"confirmed_at": "2024-01-15 10:30:12",
"has_tsr": true,
"has_tsq": true,
"pdf_download_url": "https://legallymail.com/emails/download-certificate?id=cm_rec2_abc&status=delivered"
}
]
}
]
}
}
/api/signature/send
Richiedi una firma elettronica
Crea una nuova richiesta di firma elettronica inviando un documento in formato base64.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
signer_name |
string | Sì | Nome completo del firmatario. |
signer_email |
string | Sì | Email del firmatario dove riceverà la richiesta. |
signer_phone |
string | No | Telefono del firmatario per la validazione SMS (opzionale). |
signers |
array | No | Array di firmatari del documento (max 5). Ogni firmatario deve avere: name, email, phone (opzionale). |
document |
string (base64) | Sì | Contenuto del documento PDF codificato in base64 (max 10MB). |
document_name |
string | Sì | Nome del file che il firmatario vedrà. |
language |
string | No | Lingua per l'interfaccia di firma e le email (es, en, fr, it). (default: es) |
webhook_url |
string | No | URL HTTPS pubblico in cui LegallyMail invierà un POST in tempo reale con gli eventi (opzionale). |
webhook_secret |
string | No | Segreto condiviso per convalidare la firma HMAC-SHA256 nell'intestazione X-LegallyMail-Signature (opzionale ma consigliato). |
curl -X POST https://legallymail.com/api/signature/send \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"signer_name": "John Doe",
"signer_email": "[email protected]",
"document": "BASE64_CONTENT_HERE",
"document_name": "Contract.pdf",
"language": "es"
}'
curl -X POST https://legallymail.com/api/signature/send \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"signers": [
{"name": "Firmante 1", "email": "[email protected]"},
{"name": "Firmante 2", "email": "[email protected]", "phone": "+34600000000"}
],
"document": "BASE64_CONTENT_HERE",
"document_name": "Contract.pdf",
"language": "es"
}'
<?php
$url = "https://legallymail.com/api/signature/send";
$token = "YOUR_TOKEN_HERE";
$data = [
"signer_name" => "John Doe",
"signer_email" => "[email protected]",
"document" => base64_encode(file_get_contents("document.pdf")),
"document_name" => "Contract.pdf",
"language" => "es"
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $token",
"Content-Type: application/json"
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
<?php
$url = "https://legallymail.com/api/signature/send";
$token = "YOUR_TOKEN_HERE";
$data = [
"signers" => [
["name" => "Firmante 1", "email" => "[email protected]"],
["name" => "Firmante 2", "email" => "[email protected]", "phone" => "+34600000000"]
],
"document" => base64_encode(file_get_contents("document.pdf")),
"document_name" => "Contract.pdf",
"language" => "es"
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $token",
"Content-Type: application/json"
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
import base64
url = "https://legallymail.com/api/signature/send"
token = "YOUR_TOKEN_HERE"
with open("document.pdf", "rb") as f:
doc_base64 = base64.b64encode(f.read()).decode("utf-8")
payload = {
"signer_name": "John Doe",
"signer_email": "[email protected]",
"document": doc_base64,
"document_name": "Contract.pdf",
"language": "es"
}
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
import requests
import base64
url = "https://legallymail.com/api/signature/send"
token = "YOUR_TOKEN_HERE"
with open("document.pdf", "rb") as f:
doc_base64 = base64.b64encode(f.read()).decode("utf-8")
payload = {
"signers": [
{"name": "Firmante 1", "email": "[email protected]"},
{"name": "Firmante 2", "email": "[email protected]", "phone": "+34600000000"}
],
"document": doc_base64,
"document_name": "Contract.pdf",
"language": "es"
}
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://legallymail.com/api/signature/send";
const token = "YOUR_TOKEN_HERE";
const payload = {
signer_name: "John Doe",
signer_email: "[email protected]",
document: "BASE64_CONTENT_HERE",
document_name: "Contract.pdf",
language: "es"
};
fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("Error:", error));
const url = "https://legallymail.com/api/signature/send";
const token = "YOUR_TOKEN_HERE";
const payload = {
signers: [
{name: "Firmante 1", email: "[email protected]"},
{name: "Firmante 2", email: "[email protected]", phone: "+34600000000"}
],
document: "BASE64_CONTENT_HERE",
document_name: "Contract.pdf",
language: "es"
};
fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("Error:", error));
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
url := "https://legallymail.com/api/signature/send"
token := "YOUR_TOKEN_HERE"
payload := map[string]string{
"signer_name": "John Doe",
"signer_email": "[email protected]",
"document": "BASE64_CONTENT_HERE",
"document_name": "Contract.pdf",
"language": "es",
}
jsonPayload, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class SendSignature {
public static void main(String[] args) throws Exception {
String url = "https://legallymail.com/api/signature/send";
String token = "YOUR_TOKEN_HERE";
String json = "{\"signer_name\":\"John Doe\",\"signer_email\":\"[email protected]\",\"document\":\"BASE64\",\"document_name\":\"Contract.pdf\"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
const axios = require('axios');
const fs = require('fs');
const url = "https://legallymail.com/api/signature/send";
const token = "YOUR_TOKEN_HERE";
const docBase64 = fs.readFileSync('document.pdf', { encoding: 'base64' });
const payload = {
signer_name: "John Doe",
signer_email: "[email protected]",
document: docBase64,
document_name: "Contract.pdf",
language: "es"
};
axios.post(url, payload, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
using System;
using System.Net.Http;
using System.Text;
using System.IO;
using Newtonsoft.Json;
class Program {
static async System.Threading.Tasks.Task Main() {
string url = "https://legallymail.com/api/signature/send";
string token = "YOUR_TOKEN_HERE";
byte[] fileBytes = File.ReadAllBytes("document.pdf");
string docBase64 = Convert.ToBase64String(fileBytes);
var payload = new {
signer_name = "John Doe",
signer_email = "[email protected]",
document = docBase64,
document_name = "Contract.pdf",
language = "es"
};
using (var client = new HttpClient()) {
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}
}
{
"success": true,
"message": "Signature request sent successfully",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"signer_name": "John Doe",
"signer_email": "[email protected]",
"document_name": "Contract.pdf",
"status": "pending",
"created_at": "2024-01-15 10:30:00"
}
}
/api/signatures
Elenca le tue richieste di firma
Restituisce un elenco delle richieste di firma elettronica effettuate.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
limit |
int | No | Numero di email da restituire (tra 1 e 25). Obbligatorio. (max 25) |
curl -X GET "https://legallymail.com/api/signatures?limit=10" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
<?php
$token = "YOUR_TOKEN_HERE";
$url = "https://legallymail.com/api/signatures?limit=10";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $token"
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = "https://legallymail.com/api/signatures"
headers = {"Authorization": "Bearer YOUR_TOKEN_HERE"}
params = {"limit": 10}
response = requests.get(url, headers=headers, params=params)
print(response.json())
fetch("https://legallymail.com/api/signatures?limit=10", {
headers: {
"Authorization": "Bearer YOUR_TOKEN_HERE"
}
})
.then(res => res.json())
.then(data => console.log(data));
package main
import ("net/http"; "io/ioutil")
func main() {
req, _ := http.NewRequest("GET", "https://legallymail.com/api/signatures?limit=10", nil)
req.Header.Set("Authorization", "Bearer YOUR_TOKEN_HERE")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
_ = body
}
import java.net.http.*;
import java.net.URI;
public class Main {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://legallymail.com/api/signatures?limit=10"))
.header("Authorization", "Bearer YOUR_TOKEN_HERE")
.build();
System.out.println(client.send(req, HttpResponse.BodyHandlers.ofString()).body());
}
}
const axios = require("axios");
axios.get("https://legallymail.com/api/signatures?limit=10", {
headers: { Authorization: "Bearer YOUR_TOKEN_HERE" }
}).then(res => console.log(res.data));
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_TOKEN_HERE");
var res = await client.GetStringAsync("https://legallymail.com/api/signatures?limit=10");
Console.WriteLine(res);
{
"success": true,
"data": [
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"signer_name": "John Doe",
"signer_email": "[email protected]",
"document_name": "Contract.pdf",
"status": "signed",
"created_at": "2024-01-15 10:30:00",
"signed_at": "2024-01-15 11:00:00"
},
...
]
}
/api/signature
Controlla lo stato di una firma
Ottieni i dettagli e lo stato attuale di una specifica richiesta di firma.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
uuid |
string | Sì | L'identificatore unico (UUID) della firma elettronica. |
curl -X GET "https://legallymail.com/api/signature?uuid=YOUR_UUID_HERE" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
<?php
$token = "YOUR_TOKEN_HERE";
$uuid = "YOUR_UUID_HERE";
$url = "https://legallymail.com/api/signature?uuid=$uuid";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer $token"]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = "https://legallymail.com/api/signature"
headers = {"Authorization": "Bearer YOUR_TOKEN_HERE"}
params = {"uuid": "YOUR_UUID_HERE"}
response = requests.get(url, headers=headers, params=params)
print(response.json())
fetch("https://legallymail.com/api/signature?uuid=YOUR_UUID_HERE", {
headers: { Authorization: "Bearer YOUR_TOKEN_HERE" }
}).then(res => res.json()).then(data => console.log(data));
package main
import ("net/http"; "io/ioutil")
func main() {
req, _ := http.NewRequest("GET", "https://legallymail.com/api/signature?uuid=YOUR_UUID_HERE", nil)
req.Header.Set("Authorization", "Bearer YOUR_TOKEN_HERE")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
_ = body
}
import java.net.http.*;
import java.net.URI;
public class Main {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://legallymail.com/api/signature?uuid=YOUR_UUID_HERE"))
.header("Authorization", "Bearer YOUR_TOKEN_HERE")
.build();
System.out.println(client.send(req, HttpResponse.BodyHandlers.ofString()).body());
}
}
const axios = require("axios");
axios.get("https://legallymail.com/api/signature?uuid=YOUR_UUID_HERE", {
headers: { Authorization: "Bearer YOUR_TOKEN_HERE" }
}).then(res => console.log(res.data));
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_TOKEN_HERE");
var res = await client.GetStringAsync("https://legallymail.com/api/signature?uuid=YOUR_UUID_HERE");
Console.WriteLine(res);
{
"success": true,
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"signer_name": "John Doe",
"signer_email": "[email protected]",
"document_name": "Contract.pdf",
"status": "signed",
"created_at": "2024-01-15 10:30:00",
"signed_at": "2024-01-15 11:00:00",
"expires_at": "2024-01-22 10:30:00",
"document_hash": "...",
"signed_document_hash": "...",
"signers": [
{
"signer_name": "John Doe",
"signer_email": "[email protected]",
"signer_phone": "+34600000000",
"status": "signed",
"signed_at": "2024-01-15 11:00:00"
}
],
"download_original_url": "https://legallymail.com/dashboard/electronic-signature/download-original/...",
"download_acta_url": "https://legallymail.com/dashboard/electronic-signature/download-acta/..."
}
}
/api/sms/send
Invia un SMS certificato. Viene detratto 1 credito SMS certificato dal tuo account (fino a 320 caratteri).
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
Authorization |
string (header) | Sì | api.documentation.auth_desc |
phone / recipient |
string | Sì | Numero di telefono con prefisso internazionale (es: +34600000000). |
message / text |
string | Sì | Contenuto dell'SMS. 1 credito per messaggio fino a 320 caratteri. |
{
"success": true,
"uuid": "...",
"status": "sent",
"credits_deducted": 1,
"message": "Certified SMS sent successfully"
}
/api/sms
Ottiene lo stato di un SMS certificato precedentemente inviato.
| Parametro | Tipo | Richiesto | Descrizione |
|---|---|---|---|
Authorization |
string (header) | Sì | api.documentation.auth_desc |
uuid / id |
string (query) | Sì | Identificatore unico dell'SMS restituito al momento dell'invio. |
{
"success": true,
"data": {
"uuid": "...",
"recipient": "+34600000000",
"message": "Contenido del SMS",
"status": "delivered",
"credits": 1,
"sent_at": "2024-01-15 10:30:00",
"delivered_at": "2024-01-15 10:30:05",
"failed_at": null,
"ts_confirmed_at": "2024-01-15 10:30:10",
"download_certificate_url": "https://legallymail.com/dashboard/certified-sms/download-certificate/..."
}
}
Ricevi eventi istantanei (consegna, lettura, firma) con firma crittografica senza bisogno di polling o cronjobs continui.
Interrogare lo stato tramite chiamate continue (GET /api/email, GET /api/signature) sovraccarica i server e introduce latenza inutile. Il nostro sistema di webhook invia un HTTP POST nell'esatto millisecondo in cui l'email viene consegnata, aperta o quando viene completata la firma eIDAS.
Puedes configurar el endpoint receptor de dos formas:
Incluye los parámetros opcionales webhook_url y webhook_secret directamente en el cuerpo JSON de tus peticiones POST /api/send o POST /api/signature/send.
Configura y gestiona tus endpoints de webhook directamente desde tu panel de usuario para recibir automáticamente todos los eventos de correos y firmas.
| Evento | Servicio | Disparador y Contenido |
|---|---|---|
email.sent |
Correo Certificado | Se emite inmediatamente cuando el correo certificado es procesado y aceptado en cola por los servidores de envío de LegallyMail. |
email.delivered |
Correo Certificado | Se despacha en el milisegundo en que el servidor MX del destinatario confirma la recepción del mensaje con evidencia SHA-256. |
email.opened |
Correo Certificado | Se dispara cuando el destinatario abre o visualiza el correo certificado (primera lectura fehaciente confirmada). |
email.failed |
Correo Certificado | Se notifica si la entrega falla de forma definitiva (rebote duro, buzón inexistente o bloqueo) con el código de diagnóstico SMTP. |
signature.completed |
Firma Electrónica | Se envía cuando todos los firmantes han completado su rúbrica eIDAS. Incluye URLs para descarga del PDF sellado y del acta probatoria. |
signature.rejected |
Firma Electrónica | Se despacha si un firmante rechaza formalmente la firma, adjuntando el motivo y fecha exacta. |
sms.delivered |
SMS Certificado | Confirmación inmediata de entrega del SMS certificado por parte de la red del operador móvil. |
Cada petición enviada por LegallyMail a tu servidor incluye encabezados HTTP de seguridad que garantizan que el webhook proviene legítimamente de nuestros servidores y protegen contra ataques de repetición (Replay Attacks):
| Encabezado HTTP | Descripción y Formato |
|---|---|
X-LegallyMail-Signature |
Firma criptográfica HMAC-SHA256 con formato: t={timestamp},v1={hash_hex} |
X-LegallyMail-Timestamp |
Marca temporal UNIX en segundos del momento de emisión del evento. |
X-LegallyMail-Event |
Nombre del evento disparado (ej: email.delivered, signature.completed). |
X-LegallyMail-Delivery |
Identificador único del despacho (UUID v4) para garantizar idempotencia en tu backend. |
User-Agent |
LegallyMail-Webhooks/1.0 (+https://legallymail.com) |
{
"id": "evt_94a7e3d12c9b",
"event": "email.delivered",
"timestamp": 1729722300,
"created_at": "2026-10-23T22:30:15+02:00",
"api_version": "2026-01-01",
"data": {
"tracking_id": "em_8f431b920ca7",
"recipient": "[email protected]",
"subject": "Comunicación formal de fin de contrato",
"status": "delivered",
"sent_at": "2026-10-23 22:30:02",
"delivered_at": "2026-10-23 22:30:15",
"delivery_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"delivery_ts_confirmed": "2026-10-23 22:30:15",
"download_certificate_url": "https://legallymail.com/emails/certificate/em_8f431b920ca7"
}
}
{
"id": "evt_6b1e84fa920d",
"event": "email.opened",
"timestamp": 1729722340,
"created_at": "2026-10-23T22:30:55+02:00",
"api_version": "2026-01-01",
"data": {
"tracking_id": "em_8f431b920ca7",
"recipient": "[email protected]",
"subject": "Comunicación formal de fin de contrato",
"status": "opened",
"sent_at": "2026-10-23 22:30:02",
"delivered_at": "2026-10-23 22:30:15",
"read_at": "2026-10-23 22:30:55",
"read_hash": "a45f93b18c0e9b119dc2345eaf8896fb92427ae41e4649b934ca495991b78912",
"read_ts_confirmed": "2026-10-23 22:30:55",
"download_certificate_url": "https://legallymail.com/emails/certificate/em_8f431b920ca7"
}
}
{
"id": "evt_1a98c7e42d31",
"event": "signature.completed",
"timestamp": 1729722420,
"created_at": "2026-10-23T22:32:15+02:00",
"api_version": "2026-01-01",
"data": {
"uuid": "sig_49f8021c-a81e-450b-bb99-35a9d821e901",
"document_name": "Acuerdo_Confidencialidad_NDA.pdf",
"status": "signed",
"signed_at": "2026-10-23 22:32:15",
"document_hash": "b2f0a1c9...",
"signed_document_hash": "f183d02a...",
"ts_confirmed_at": "2026-10-23 22:32:16",
"download_signed_pdf_url": "https://legallymail.com/electronic-signature/download/sig_49f8021c-a81e-450b-bb99-35a9d821e901?signed=1",
"download_acta_url": "https://legallymail.com/electronic-signature/download/sig_49f8021c-a81e-450b-bb99-35a9d821e901?acta=1"
}
}
<?php
$webhookSecret = 'whsec_tu_secreto_configurado';
$payload = file_get_contents('php://input');
$sigHeader = $_SERVER['HTTP_X_LEGALLYMAIL_SIGNATURE'] ?? '';
// Extraer t (timestamp) y v1 (hash)
preg_match('/t=(\d+),v1=([a-f0-9]+)/', $sigHeader, $matches);
if (count($matches) !== 3) {
http_response_code(400);
exit('Firma no proporcionada o formato inválido');
}
$timestamp = $matches[1];
$receivedHash = $matches[2];
// Proteger contra ataques de repetición (tolerancia de 5 minutos = 300 segundos)
if (abs(time() - $timestamp) > 300) {
http_response_code(400);
exit('Firma expirada (Timestamp fuera de tolerancia)');
}
// Calcular firma esperada
$expectedHash = hash_hmac('sha256', $timestamp . '.' . $payload, $webhookSecret);
if (!hash_equals($expectedHash, $receivedHash)) {
http_response_code(401);
exit('Firma criptográfica inválida');
}
// Firma verificada con éxito
$event = json_decode($payload, true);
switch ($event['event']) {
case 'email.delivered':
// Procesar entrega inmediata
break;
case 'email.opened':
// Procesar lectura fehaciente
break;
case 'signature.completed':
// Procesar documento firmado
break;
}
http_response_code(200);
echo json_encode(['status' => 'received']);
const express = require('express');
const crypto = require('crypto');
const app = express();
const WEBHOOK_SECRET = 'whsec_tu_secreto_configurado';
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sigHeader = req.headers['x-legallymail-signature'];
const rawBody = req.body.toString('utf8');
if (!sigHeader) return res.status(400).send('Missing signature');
const match = sigHeader.match(/t=(\d+),v1=([a-f0-9]+)/);
if (!match) return res.status(400).send('Invalid signature format');
const [_, timestamp, receivedHash] = match;
// Tolerancia anti-replay: 5 minutos
if (Math.abs(Date.now() / 1000 - timestamp) > 300) {
return res.status(400).send('Timestamp expired');
}
const expectedHash = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expectedHash), Buffer.from(receivedHash))) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(rawBody);
console.log(`Evento recibido: ${event.event}`, event.data);
res.status(200).json({ received: true });
});
app.listen(3000);
import hmac
import hashlib
import time
import re
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
WEBHOOK_SECRET = "whsec_tu_secreto_configurado"
@app.post("/webhook")
async def handle_legallymail_webhook(request: Request):
sig_header = request.headers.get("x-legallymail-signature")
if not sig_header:
raise HTTPException(status_code=400, detail="Missing signature")
match = re.search(r"t=(\d+),v1=([a-f0-9]+)", sig_header)
if not match:
raise HTTPException(status_code=400, detail="Invalid signature header format")
timestamp, received_hash = match.group(1), match.group(2)
# Validar tolerancia de 5 minutos
if abs(time.time() - int(timestamp)) > 300:
raise HTTPException(status_code=400, detail="Timestamp expired")
raw_body = await request.body()
expected_hash = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
f"{timestamp}.".encode('utf-8') + raw_body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected_hash, received_hash):
raise HTTPException(status_code=401, detail="Invalid HMAC signature")
event = await request.json()
# Procesar event["event"]
return {"status": "ok"}
200 o 204 en un máximo de 5 segundos.X-LegallyMail-Delivery para descartar eventos duplicados si tu servidor ya procesó la notificación anteriormente.| Codice | Messaggio | Descrizione |
|---|---|---|
400 |
Bad Request | I dati forniti non sono validi |
401 |
Unauthorized | Token non valido o non fornito |
403 |
Forbidden |
Non hai il permesso per eseguire questa azione Viene restituito anche quando l'utente non ha crediti/email rimanenti disponibili. |
404 |
Not Found | Risorsa non trovata. Verifica che la risorsa richiesta esista (ad esempio, un'email con il tracking_id specificato). |
405 |
Method Not Allowed | Metodo HTTP non consentito |
429 |
Too Many Requests | Troppe richieste. Limite di rate limiting superato. |
500 |
Internal Server Error | Errore interno del server |
L'API ha le seguenti restrizioni: