curl --request POST \
--url https://api.sumvin.com/v0/webhooks/para/wallet-claimed \
--header 'Content-Type: application/json' \
--data '
{
"id": "evt_550e8400-e29b-41d4-a716-446655440000",
"type": "wallet.pregen_claimed",
"data": {
"walletId": "<string>",
"walletAddress": "<string>",
"walletType": "<string>",
"claimedAt": "<string>"
},
"createdAt": "<string>"
}
'import requests
url = "https://api.sumvin.com/v0/webhooks/para/wallet-claimed"
payload = {
"id": "evt_550e8400-e29b-41d4-a716-446655440000",
"type": "wallet.pregen_claimed",
"data": {
"walletId": "<string>",
"walletAddress": "<string>",
"walletType": "<string>",
"claimedAt": "<string>"
},
"createdAt": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: 'evt_550e8400-e29b-41d4-a716-446655440000',
type: 'wallet.pregen_claimed',
data: {
walletId: '<string>',
walletAddress: '<string>',
walletType: '<string>',
claimedAt: '<string>'
},
createdAt: '<string>'
})
};
fetch('https://api.sumvin.com/v0/webhooks/para/wallet-claimed', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sumvin.com/v0/webhooks/para/wallet-claimed",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'id' => 'evt_550e8400-e29b-41d4-a716-446655440000',
'type' => 'wallet.pregen_claimed',
'data' => [
'walletId' => '<string>',
'walletAddress' => '<string>',
'walletType' => '<string>',
'claimedAt' => '<string>'
],
'createdAt' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sumvin.com/v0/webhooks/para/wallet-claimed"
payload := strings.NewReader("{\n \"id\": \"evt_550e8400-e29b-41d4-a716-446655440000\",\n \"type\": \"wallet.pregen_claimed\",\n \"data\": {\n \"walletId\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"walletType\": \"<string>\",\n \"claimedAt\": \"<string>\"\n },\n \"createdAt\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sumvin.com/v0/webhooks/para/wallet-claimed")
.header("Content-Type", "application/json")
.body("{\n \"id\": \"evt_550e8400-e29b-41d4-a716-446655440000\",\n \"type\": \"wallet.pregen_claimed\",\n \"data\": {\n \"walletId\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"walletType\": \"<string>\",\n \"claimedAt\": \"<string>\"\n },\n \"createdAt\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sumvin.com/v0/webhooks/para/wallet-claimed")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"id\": \"evt_550e8400-e29b-41d4-a716-446655440000\",\n \"type\": \"wallet.pregen_claimed\",\n \"data\": {\n \"walletId\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"walletType\": \"<string>\",\n \"claimedAt\": \"<string>\"\n },\n \"createdAt\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"received": true
}{
"detail": "No wallet found with ID 12345 for this user.",
"error_code": "WAL-404-001",
"instance": "/v0/wallets/12345",
"status": 404,
"title": "Wallet Not Found",
"trace_id": "abc123-def456-ghi789",
"type": "https://api.sumvin.com/errors/wal-404-001"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}Receive a wallet-claim webhook from the embedded-wallet provider
Receives a signed webhook reporting that a user has taken ownership of a wallet this server requested for them in advance, and records that fact against the matching user.
This endpoint records the claim and nothing else. Everything that follows from a claim happens downstream, driven by the recorded fact.
Signature scheme: Each request carries three headers:
webhook-signature— one or more space-delimitedv1,-prefixed values, each the base64-encoded HMAC-SHA256 over the canonical string"{webhook-timestamp}.{body}". During a signing-secret rotation more than one value may be present; a delivery is accepted if any of them verifies.webhook-timestamp— unix epoch seconds at which the request was signed.webhook-id— unique event identifier, mirroring the envelope’sid.
Timestamp tolerance: Requests with a timestamp more than 300 seconds from server time are rejected before the HMAC is computed, in either direction.
Failure modes:
A missing or invalid signature returns 401 with error code PAR-401-001. The
detail is a fixed string and never echoes the client-supplied signature or
timestamp. Successful delivery returns 200; replays of the same event id, event
types other than wallet claims, and wallet references this server does not
recognise are all accepted as 200 no-ops so retries are safe. Handler
exceptions surface as 5xx so the provider will retry.
curl --request POST \
--url https://api.sumvin.com/v0/webhooks/para/wallet-claimed \
--header 'Content-Type: application/json' \
--data '
{
"id": "evt_550e8400-e29b-41d4-a716-446655440000",
"type": "wallet.pregen_claimed",
"data": {
"walletId": "<string>",
"walletAddress": "<string>",
"walletType": "<string>",
"claimedAt": "<string>"
},
"createdAt": "<string>"
}
'import requests
url = "https://api.sumvin.com/v0/webhooks/para/wallet-claimed"
payload = {
"id": "evt_550e8400-e29b-41d4-a716-446655440000",
"type": "wallet.pregen_claimed",
"data": {
"walletId": "<string>",
"walletAddress": "<string>",
"walletType": "<string>",
"claimedAt": "<string>"
},
"createdAt": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: 'evt_550e8400-e29b-41d4-a716-446655440000',
type: 'wallet.pregen_claimed',
data: {
walletId: '<string>',
walletAddress: '<string>',
walletType: '<string>',
claimedAt: '<string>'
},
createdAt: '<string>'
})
};
fetch('https://api.sumvin.com/v0/webhooks/para/wallet-claimed', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sumvin.com/v0/webhooks/para/wallet-claimed",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'id' => 'evt_550e8400-e29b-41d4-a716-446655440000',
'type' => 'wallet.pregen_claimed',
'data' => [
'walletId' => '<string>',
'walletAddress' => '<string>',
'walletType' => '<string>',
'claimedAt' => '<string>'
],
'createdAt' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sumvin.com/v0/webhooks/para/wallet-claimed"
payload := strings.NewReader("{\n \"id\": \"evt_550e8400-e29b-41d4-a716-446655440000\",\n \"type\": \"wallet.pregen_claimed\",\n \"data\": {\n \"walletId\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"walletType\": \"<string>\",\n \"claimedAt\": \"<string>\"\n },\n \"createdAt\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sumvin.com/v0/webhooks/para/wallet-claimed")
.header("Content-Type", "application/json")
.body("{\n \"id\": \"evt_550e8400-e29b-41d4-a716-446655440000\",\n \"type\": \"wallet.pregen_claimed\",\n \"data\": {\n \"walletId\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"walletType\": \"<string>\",\n \"claimedAt\": \"<string>\"\n },\n \"createdAt\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sumvin.com/v0/webhooks/para/wallet-claimed")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"id\": \"evt_550e8400-e29b-41d4-a716-446655440000\",\n \"type\": \"wallet.pregen_claimed\",\n \"data\": {\n \"walletId\": \"<string>\",\n \"walletAddress\": \"<string>\",\n \"walletType\": \"<string>\",\n \"claimedAt\": \"<string>\"\n },\n \"createdAt\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"received": true
}{
"detail": "No wallet found with ID 12345 for this user.",
"error_code": "WAL-404-001",
"instance": "/v0/wallets/12345",
"status": 404,
"title": "Wallet Not Found",
"trace_id": "abc123-def456-ghi789",
"type": "https://api.sumvin.com/errors/wal-404-001"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}Headers
Controls how timestamp fields are serialized in JSON response bodies.
Default (header omitted or any other value): epoch milliseconds as integers.
iso8601: UTC ISO 8601 strings of the form YYYY-MM-DDTHH:MM:SSZ.
Example: with X-Timestamp-Format: iso8601, the field value 1704067200000 becomes "2024-01-01T00:00:00Z".
Affected fields (recursively, in dicts and arrays): any field whose name ends in _at, plus the literal field names timestamp, period_start, and period_end. All other fields are passed through unchanged.
Only iso8601 is recognized. Any other value (or omitting the header) yields the default epoch-ms representation; the server does not reject unknown values, so this is documented as an example rather than an enum to keep generated clients permissive.
"iso8601"
Body
Unique identifier for the event, used for replay dedup.
"evt_550e8400-e29b-41d4-a716-446655440000"
Event type. Only wallet-claim events are acted on.
"wallet.pregen_claimed"
Show child attributes
Show child attributes
ISO 8601 timestamp at which the event was created.
Response
Webhook received
Acknowledgement returned for every accepted webhook delivery (incl. no-op replays).