Mail2Webhook Service
The Mail2Webhook service assigns each wallet a dedicated email address at <token>@hook.echovalue.dev. Emails sent to that address are forwarded as JSON POST requests to your configured webhook URL.
Each wallet supports one webhook configuration.
Configure Webhook
Section titled “Configure Webhook”POST https://api.echovalue.dev/webhook
Creates or updates the webhook for your wallet (upsert).
Request headers:
| Header | Description |
|---|---|
x-token | Your API token |
Content-Type | Must be application/json |
Request body (application/json):
| Field | Type | Description | Required |
|---|---|---|---|
url | string | Callback URL (must be HTTPS, publicly reachable) | Yes |
headers | object | Custom headers to include in the callback request | No |
Response: 200 OK
OKHTTP status codes:
| Status | Meaning |
|---|---|
200 | Webhook saved |
400 | Invalid URL or malformed request |
401 | Invalid token |
402 | Insufficient credits |
curl 'https://api.echovalue.dev/webhook' \ -H 'x-token: mytoken' \ -H 'Content-Type: application/json' \ -d '{"url":"https://yourdomain.com/webhook","headers":{"Authorization":"Bearer secret"}}'fetch('https://api.echovalue.dev/webhook', { method: 'POST', headers: { 'x-token': 'mytoken', 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://yourdomain.com/webhook', headers: { 'Authorization': 'Bearer secret' } })});import requests
requests.post('https://api.echovalue.dev/webhook', headers={ 'x-token': 'mytoken', 'Content-Type': 'application/json' }, json={ 'url': 'https://yourdomain.com/webhook', 'headers': { 'Authorization': 'Bearer secret' } })<?php$data = json_encode([ 'url' => 'https://yourdomain.com/webhook', 'headers' => ['Authorization' => 'Bearer secret']]);$ch = curl_init('https://api.echovalue.dev/webhook');curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $data);curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'x-token: mytoken', 'Content-Type: application/json']);curl_exec($ch);curl_close($ch);?>package main
import ( "bytes" "encoding/json" "net/http")
func main() { payload := map[string]interface{}{ "url": "https://yourdomain.com/webhook", "headers": map[string]string{"Authorization": "Bearer secret"}, } jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.echovalue.dev/webhook", bytes.NewBuffer(jsonData)) req.Header.Set("x-token", "mytoken") req.Header.Set("Content-Type", "application/json")
client := &http.Client{} client.Do(req)}Get Webhook Configuration
Section titled “Get Webhook Configuration”GET https://api.echovalue.dev/webhook
Returns the current webhook configuration for your wallet.
Request headers:
| Header | Description |
|---|---|
x-token | Your API token |
Response: 200 — JSON object.
If a webhook is configured:
{ "webhook": "https://yourdomain.com/webhook", "headers": { "Authorization": "<redacted>" }, "email": "mytoken@hook.echovalue.dev", "hash": "a1b2c3d4e5f6..."}If no webhook is configured, only email and hash are returned:
{ "email": "mytoken@hook.echovalue.dev", "hash": "a1b2c3d4e5f6..."}| Field | Type | Description |
|---|---|---|
webhook | string | Your configured callback URL |
headers | object | Custom headers (values are redacted) |
email | string | The email address that triggers this webhook |
hash | string | SHA256 hash of your token — use this to identify incoming payloads |
HTTP status codes:
| Status | Meaning |
|---|---|
200 | Configuration returned |
401 | Invalid token |
402 | Insufficient credits |
curl 'https://api.echovalue.dev/webhook' \ -H 'x-token: mytoken'fetch('https://api.echovalue.dev/webhook', { headers: { 'x-token': 'mytoken' }}).then(response => response.json()).then(data => console.log(data));import requests
response = requests.get('https://api.echovalue.dev/webhook', headers={'x-token': 'mytoken'})print(response.json())<?php$ch = curl_init('https://api.echovalue.dev/webhook');curl_setopt($ch, CURLOPT_HTTPHEADER, ['x-token: mytoken']);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);$response = curl_exec($ch);curl_close($ch);print_r(json_decode($response));?>package main
import ( "fmt" "io" "net/http")
func main() { req, _ := http.NewRequest("GET", "https://api.echovalue.dev/webhook", nil) req.Header.Set("x-token", "mytoken")
client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}Delete Webhook
Section titled “Delete Webhook”DELETE https://api.echovalue.dev/webhook
Removes the webhook configuration from your wallet.
Request headers:
| Header | Description |
|---|---|
x-token | Your API token |
Response: 200 OK
OKHTTP status codes:
| Status | Meaning |
|---|---|
200 | Webhook deleted |
401 | Invalid token |
402 | Insufficient credits |
404 | No webhook configured |
curl 'https://api.echovalue.dev/webhook' \ -H 'x-token: mytoken' \ -X DELETEfetch('https://api.echovalue.dev/webhook', { method: 'DELETE', headers: { 'x-token': 'mytoken' }});import requests
requests.delete('https://api.echovalue.dev/webhook', headers={'x-token': 'mytoken'})<?php$ch = curl_init('https://api.echovalue.dev/webhook');curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');curl_setopt($ch, CURLOPT_HTTPHEADER, ['x-token: mytoken']);curl_exec($ch);curl_close($ch);?>package main
import "net/http"
func main() { req, _ := http.NewRequest("DELETE", "https://api.echovalue.dev/webhook", nil) req.Header.Set("x-token", "mytoken")
client := &http.Client{} client.Do(req)}Webhook Payload
Section titled “Webhook Payload”When an email arrives at <token>@hook.echovalue.dev, echoValue sends a POST request to your webhook URL with this JSON body:
{ "externalMessageId": "<CA+abc123@mail.gmail.com>", "receivedAt": "2026-04-04T09:21:35.218Z", "from": { "email": "john@gmail.com", "name": "John Snow" }, "to": { "hash": "a1b2c3d4e5f6..." }, "subject": "Alert: Server down", "text": "Server #3 is not responding", "html": "<div>Server #3 is not responding</div>", "headers": {}, "attachments": [ { "filename": "attachment.pdf", "contentType": "application/pdf", "size": 33380, "downloadUrl": "<presigned_url>", "downloadUrlExpiresAt": "2026-04-04T09:26:35.218Z" } ]}Payload Fields
Section titled “Payload Fields”| Field | Type | Description |
|---|---|---|
externalMessageId | string | Unique identifier for the email message |
receivedAt | string (ISO 8601) | When the email was received |
from | object | Sender: email and optional name |
to | object | Recipient: hash (SHA256 of your token) |
subject | string | Email subject line |
text | string | Plain text body |
html | string | HTML body (if present) |
headers | object | Raw email headers as key-value pairs |
attachments | array | File attachments (empty array if none) |
Attachment Fields
Section titled “Attachment Fields”| Field | Type | Description |
|---|---|---|
filename | string | Original filename |
contentType | string | MIME type |
size | integer | File size in bytes |
downloadUrl | string | Presigned URL to download the file |
downloadUrlExpiresAt | string (ISO 8601) | When the download URL expires (1 hour) |