Submit a pay-out route ownership proof
curl --request POST \
--url https://api.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"message": "I confirm ownership of wallet 0x7c6b9095... on 20/08/2026",
"signature": "0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b"
}
'import requests
url = "https://api.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete"
payload = {
"message": "I confirm ownership of wallet 0x7c6b9095... on 20/08/2026",
"signature": "0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
message: 'I confirm ownership of wallet 0x7c6b9095... on 20/08/2026',
signature: '0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b'
})
};
fetch('https://api.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete', 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.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete",
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([
'message' => 'I confirm ownership of wallet 0x7c6b9095... on 20/08/2026',
'signature' => '0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete"
payload := strings.NewReader("{\n \"message\": \"I confirm ownership of wallet 0x7c6b9095... on 20/08/2026\",\n \"signature\": \"0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"message\": \"I confirm ownership of wallet 0x7c6b9095... on 20/08/2026\",\n \"signature\": \"0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"message\": \"I confirm ownership of wallet 0x7c6b9095... on 20/08/2026\",\n \"signature\": \"0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"result": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "PENDING",
"depositAsset": {
"chain": "AVALANCHE",
"name": "USDC"
},
"fiatCurrency": "<string>",
"depositAddress": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}{
"success": false,
"errors": [
{
"code": "unauthenticated",
"message": "Please authenticate to perform this action."
}
]
}{
"success": false,
"errors": [
{
"code": "forbidden",
"message": "You do not have permission to access this resource."
}
]
}{
"success": false,
"errors": [
{
"code": "account-not-found",
"message": "The requested resource was not found."
}
]
}{
"success": false,
"errors": [
{
"code": "internal-error",
"message": "An unexpected error occurred. Please try again later."
}
]
}Payout Routes
Submit a route ownership proof
Submit the signed message and resume a paused pay-out route registration.
POST
/
accounts
/
{accountId}
/
payout-routes
/
{routeId}
/
ownership-proof
/
complete
Submit a pay-out route ownership proof
curl --request POST \
--url https://api.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"message": "I confirm ownership of wallet 0x7c6b9095... on 20/08/2026",
"signature": "0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b"
}
'import requests
url = "https://api.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete"
payload = {
"message": "I confirm ownership of wallet 0x7c6b9095... on 20/08/2026",
"signature": "0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
message: 'I confirm ownership of wallet 0x7c6b9095... on 20/08/2026',
signature: '0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b'
})
};
fetch('https://api.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete', 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.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete",
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([
'message' => 'I confirm ownership of wallet 0x7c6b9095... on 20/08/2026',
'signature' => '0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete"
payload := strings.NewReader("{\n \"message\": \"I confirm ownership of wallet 0x7c6b9095... on 20/08/2026\",\n \"signature\": \"0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"message\": \"I confirm ownership of wallet 0x7c6b9095... on 20/08/2026\",\n \"signature\": \"0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.venlyfinance.com/v1/accounts/{accountId}/payout-routes/{routeId}/ownership-proof/complete")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"message\": \"I confirm ownership of wallet 0x7c6b9095... on 20/08/2026\",\n \"signature\": \"0x9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a01b\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"result": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "PENDING",
"depositAsset": {
"chain": "AVALANCHE",
"name": "USDC"
},
"fiatCurrency": "<string>",
"depositAddress": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}{
"success": false,
"errors": [
{
"code": "unauthenticated",
"message": "Please authenticate to perform this action."
}
]
}{
"success": false,
"errors": [
{
"code": "forbidden",
"message": "You do not have permission to access this resource."
}
]
}{
"success": false,
"errors": [
{
"code": "account-not-found",
"message": "The requested resource was not found."
}
]
}{
"success": false,
"errors": [
{
"code": "internal-error",
"message": "An unexpected error occurred. Please try again later."
}
]
}Requires scope:
Send
manage:pay-outs — see Required scopes.
Submits the signed message and resumes the route’s registration. On success the route leaves AWAITING_OWNERSHIP_PROOF and continues to ACTIVE asynchronously.
A
200 means the proof was accepted, not that the route is ready. Poll the route or register a webhook to hear when it reaches ACTIVE — only then does it have a depositAddress.message exactly as prepare returned it. It must match the canonical text for this route, which embeds the route’s own wallet, and the signature must recover that wallet.
That’s what makes the stateless design safe, and it has two consequences worth knowing:
- A proof signed for a different wallet, route or tenant is rejected — it can’t be replayed here.
- A message with extra text wrapped around the expected content is rejected too, even if the signature is valid.
prepare first. This endpoint only cares that the message is canonical and the signature matches.
The proof is never stored or logged. It’s verified in memory, forwarded once, and discarded — only the outcome is persisted.
| Code | Meaning |
|---|---|
ownership-proof-not-applicable | This route needs no owner-signed proof, or its source wallet is Venly-managed. |
invalid-proof-message | message isn’t the canonical text for this route. |
signature-mismatch | signature doesn’t recover the route’s wallet address. |
Authorizations
OAuth2 client credentials flow. Token endpoints:
Path Parameters
Unique account identifier
Unique pay-out route identifier
Body
application/json
Was this page helpful?

