Verify a Refusal Record's signature
Verifies a Refusal Record’s signature (RFC-0021). Deliberately mounted before this app’s caller-auth middleware, see packages/api/src/app.ts: no caller authentication or API key is required, by design. This is the capability that makes a refusal independently third-party verifiable. It takes the record itself, not a lookup by ID, no database access, no ownership check, nothing but the artifact and Parmana’s public key.
curl --request POST \
--url http://localhost:3000/refusal/verify \
--header 'Content-Type: application/json' \
--data '
{
"refusalRecordId": "eddc5dd1-a791-4470-9534-11b3fc573ab8",
"businessTransactionId": "353c73fb-5e87-4dbe-8bfc-c15c8f18d871",
"decision": {
"decisionId": "3919f4b6-cbc8-44ec-a6a1-8887ee85f314",
"intentId": "4ba6b14a-c593-4f5c-ab58-dcef38a29364",
"policy": {
"name": "vendor-payment",
"version": "2.0.0",
"schemaVersion": "1.0.0"
},
"signals": {
"vendorVerified": false,
"invoiceVerified": true,
"paymentApproved": true,
"sufficientFunds": true,
"paymentAmount": 1000,
"riskScore": 5,
"vendorId": "vendor://payments"
},
"outcome": "REJECTED",
"reason": "Vendor payment rejected because the vendor has not been verified.",
"evaluatedAt": "2026-09-15T03:27:45.666Z"
},
"evaluatedIntent": {
"target": "vendor://payments",
"parameters": {
"amount": 1000,
"currency": "USD"
}
},
"createdAt": "2026-09-15T03:27:45.666Z",
"refusalRecordHash": "47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca",
"signature": {
"algorithm": "ed25519",
"keyId": "default",
"value": "tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==",
"signedAt": "2026-09-15T03:27:45.668Z"
}
}
'import requests
url = "http://localhost:3000/refusal/verify"
payload = {
"refusalRecordId": "eddc5dd1-a791-4470-9534-11b3fc573ab8",
"businessTransactionId": "353c73fb-5e87-4dbe-8bfc-c15c8f18d871",
"decision": {
"decisionId": "3919f4b6-cbc8-44ec-a6a1-8887ee85f314",
"intentId": "4ba6b14a-c593-4f5c-ab58-dcef38a29364",
"policy": {
"name": "vendor-payment",
"version": "2.0.0",
"schemaVersion": "1.0.0"
},
"signals": {
"vendorVerified": False,
"invoiceVerified": True,
"paymentApproved": True,
"sufficientFunds": True,
"paymentAmount": 1000,
"riskScore": 5,
"vendorId": "vendor://payments"
},
"outcome": "REJECTED",
"reason": "Vendor payment rejected because the vendor has not been verified.",
"evaluatedAt": "2026-09-15T03:27:45.666Z"
},
"evaluatedIntent": {
"target": "vendor://payments",
"parameters": {
"amount": 1000,
"currency": "USD"
}
},
"createdAt": "2026-09-15T03:27:45.666Z",
"refusalRecordHash": "47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca",
"signature": {
"algorithm": "ed25519",
"keyId": "default",
"value": "tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==",
"signedAt": "2026-09-15T03:27:45.668Z"
}
}
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({
refusalRecordId: 'eddc5dd1-a791-4470-9534-11b3fc573ab8',
businessTransactionId: '353c73fb-5e87-4dbe-8bfc-c15c8f18d871',
decision: {
decisionId: '3919f4b6-cbc8-44ec-a6a1-8887ee85f314',
intentId: '4ba6b14a-c593-4f5c-ab58-dcef38a29364',
policy: {name: 'vendor-payment', version: '2.0.0', schemaVersion: '1.0.0'},
signals: {
vendorVerified: false,
invoiceVerified: true,
paymentApproved: true,
sufficientFunds: true,
paymentAmount: 1000,
riskScore: 5,
vendorId: 'vendor://payments'
},
outcome: 'REJECTED',
reason: 'Vendor payment rejected because the vendor has not been verified.',
evaluatedAt: '2026-09-15T03:27:45.666Z'
},
evaluatedIntent: {target: 'vendor://payments', parameters: {amount: 1000, currency: 'USD'}},
createdAt: '2026-09-15T03:27:45.666Z',
refusalRecordHash: '47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca',
signature: {
algorithm: 'ed25519',
keyId: 'default',
value: 'tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==',
signedAt: '2026-09-15T03:27:45.668Z'
}
})
};
fetch('http://localhost:3000/refusal/verify', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "3000",
CURLOPT_URL => "http://localhost:3000/refusal/verify",
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([
'refusalRecordId' => 'eddc5dd1-a791-4470-9534-11b3fc573ab8',
'businessTransactionId' => '353c73fb-5e87-4dbe-8bfc-c15c8f18d871',
'decision' => [
'decisionId' => '3919f4b6-cbc8-44ec-a6a1-8887ee85f314',
'intentId' => '4ba6b14a-c593-4f5c-ab58-dcef38a29364',
'policy' => [
'name' => 'vendor-payment',
'version' => '2.0.0',
'schemaVersion' => '1.0.0'
],
'signals' => [
'vendorVerified' => false,
'invoiceVerified' => true,
'paymentApproved' => true,
'sufficientFunds' => true,
'paymentAmount' => 1000,
'riskScore' => 5,
'vendorId' => 'vendor://payments'
],
'outcome' => 'REJECTED',
'reason' => 'Vendor payment rejected because the vendor has not been verified.',
'evaluatedAt' => '2026-09-15T03:27:45.666Z'
],
'evaluatedIntent' => [
'target' => 'vendor://payments',
'parameters' => [
'amount' => 1000,
'currency' => 'USD'
]
],
'createdAt' => '2026-09-15T03:27:45.666Z',
'refusalRecordHash' => '47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca',
'signature' => [
'algorithm' => 'ed25519',
'keyId' => 'default',
'value' => 'tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==',
'signedAt' => '2026-09-15T03:27:45.668Z'
]
]),
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 := "http://localhost:3000/refusal/verify"
payload := strings.NewReader("{\n \"refusalRecordId\": \"eddc5dd1-a791-4470-9534-11b3fc573ab8\",\n \"businessTransactionId\": \"353c73fb-5e87-4dbe-8bfc-c15c8f18d871\",\n \"decision\": {\n \"decisionId\": \"3919f4b6-cbc8-44ec-a6a1-8887ee85f314\",\n \"intentId\": \"4ba6b14a-c593-4f5c-ab58-dcef38a29364\",\n \"policy\": {\n \"name\": \"vendor-payment\",\n \"version\": \"2.0.0\",\n \"schemaVersion\": \"1.0.0\"\n },\n \"signals\": {\n \"vendorVerified\": false,\n \"invoiceVerified\": true,\n \"paymentApproved\": true,\n \"sufficientFunds\": true,\n \"paymentAmount\": 1000,\n \"riskScore\": 5,\n \"vendorId\": \"vendor://payments\"\n },\n \"outcome\": \"REJECTED\",\n \"reason\": \"Vendor payment rejected because the vendor has not been verified.\",\n \"evaluatedAt\": \"2026-09-15T03:27:45.666Z\"\n },\n \"evaluatedIntent\": {\n \"target\": \"vendor://payments\",\n \"parameters\": {\n \"amount\": 1000,\n \"currency\": \"USD\"\n }\n },\n \"createdAt\": \"2026-09-15T03:27:45.666Z\",\n \"refusalRecordHash\": \"47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca\",\n \"signature\": {\n \"algorithm\": \"ed25519\",\n \"keyId\": \"default\",\n \"value\": \"tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==\",\n \"signedAt\": \"2026-09-15T03:27:45.668Z\"\n }\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("http://localhost:3000/refusal/verify")
.header("Content-Type", "application/json")
.body("{\n \"refusalRecordId\": \"eddc5dd1-a791-4470-9534-11b3fc573ab8\",\n \"businessTransactionId\": \"353c73fb-5e87-4dbe-8bfc-c15c8f18d871\",\n \"decision\": {\n \"decisionId\": \"3919f4b6-cbc8-44ec-a6a1-8887ee85f314\",\n \"intentId\": \"4ba6b14a-c593-4f5c-ab58-dcef38a29364\",\n \"policy\": {\n \"name\": \"vendor-payment\",\n \"version\": \"2.0.0\",\n \"schemaVersion\": \"1.0.0\"\n },\n \"signals\": {\n \"vendorVerified\": false,\n \"invoiceVerified\": true,\n \"paymentApproved\": true,\n \"sufficientFunds\": true,\n \"paymentAmount\": 1000,\n \"riskScore\": 5,\n \"vendorId\": \"vendor://payments\"\n },\n \"outcome\": \"REJECTED\",\n \"reason\": \"Vendor payment rejected because the vendor has not been verified.\",\n \"evaluatedAt\": \"2026-09-15T03:27:45.666Z\"\n },\n \"evaluatedIntent\": {\n \"target\": \"vendor://payments\",\n \"parameters\": {\n \"amount\": 1000,\n \"currency\": \"USD\"\n }\n },\n \"createdAt\": \"2026-09-15T03:27:45.666Z\",\n \"refusalRecordHash\": \"47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca\",\n \"signature\": {\n \"algorithm\": \"ed25519\",\n \"keyId\": \"default\",\n \"value\": \"tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==\",\n \"signedAt\": \"2026-09-15T03:27:45.668Z\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:3000/refusal/verify")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"refusalRecordId\": \"eddc5dd1-a791-4470-9534-11b3fc573ab8\",\n \"businessTransactionId\": \"353c73fb-5e87-4dbe-8bfc-c15c8f18d871\",\n \"decision\": {\n \"decisionId\": \"3919f4b6-cbc8-44ec-a6a1-8887ee85f314\",\n \"intentId\": \"4ba6b14a-c593-4f5c-ab58-dcef38a29364\",\n \"policy\": {\n \"name\": \"vendor-payment\",\n \"version\": \"2.0.0\",\n \"schemaVersion\": \"1.0.0\"\n },\n \"signals\": {\n \"vendorVerified\": false,\n \"invoiceVerified\": true,\n \"paymentApproved\": true,\n \"sufficientFunds\": true,\n \"paymentAmount\": 1000,\n \"riskScore\": 5,\n \"vendorId\": \"vendor://payments\"\n },\n \"outcome\": \"REJECTED\",\n \"reason\": \"Vendor payment rejected because the vendor has not been verified.\",\n \"evaluatedAt\": \"2026-09-15T03:27:45.666Z\"\n },\n \"evaluatedIntent\": {\n \"target\": \"vendor://payments\",\n \"parameters\": {\n \"amount\": 1000,\n \"currency\": \"USD\"\n }\n },\n \"createdAt\": \"2026-09-15T03:27:45.666Z\",\n \"refusalRecordHash\": \"47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca\",\n \"signature\": {\n \"algorithm\": \"ed25519\",\n \"keyId\": \"default\",\n \"value\": \"tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==\",\n \"signedAt\": \"2026-09-15T03:27:45.668Z\"\n }\n}"
response = http.request(request)
puts response.read_body{
"valid": true
}{
"error": "Request body must be a Refusal Record (refusalRecordId, businessTransactionId, decision, refusalRecordHash, signature required)."
}Body
Durable, signed, independently verifiable evidence that a policy decision rejected a transaction (RFC-0021). Scope is deliberately narrow: covers PolicyEngine.evaluate REJECTs and SignalIntentBinder binding-violation REJECTs only, not caller-authentication failures or webhook signature failures, which are a separate, unsigned audit-sink capability. At most one Refusal Record exists per businessTransactionId.
Unique Refusal Record identifier.
Business Transaction this refusal is about.
Immutable result of evaluating an Intent against a Policy. Decision does not create authority, grant authorization, or modify Intent; it only records the outcome of deterministic Policy evaluation.
Show child attributes
Show child attributes
{
"decisionId": "9d69dc0b-333a-4be3-b09f-358fece806f3",
"intentId": "ae5865f6-181b-409a-90ec-1b4b8b8414ba",
"policy": {
"name": "vendor-payment",
"version": "2.0.0",
"schemaVersion": "1.0.0"
},
"signals": {
"vendorVerified": true,
"invoiceVerified": true,
"paymentApproved": true,
"sufficientFunds": true,
"paymentAmount": 4500,
"riskScore": 10
},
"outcome": "APPROVED",
"reason": "Vendor payment authorized. Vendor verification, invoice verification, payment approval, funding, and risk assessment requirements were satisfied.",
"evaluatedAt": "2026-07-07T16:38:59.326Z"
}
The Intent snapshot the signals were evaluated against: target and parameters only, present for every refusal, not only binding violations.
Show child attributes
Show child attributes
Canonical hash of this Refusal Record, same convention as ExecutionTrustRecord.trustRecordHash.
Cryptographic signature over the canonical Refusal Record, signed with the same key as ExecutionTrustRecord, one root of trust for both approvals and refusals.
Show child attributes
Show child attributes
UTC timestamp when this Refusal Record was created.
Present only when the rejection came from SignalIntentBinder. Absent (not an empty array) for an ordinary PolicyEngine.evaluate REJECT that never reached binding-violation logic at all.
Show child attributes
Show child attributes
Authenticated caller who submitted the rejected request. Absent when caller authentication is disabled.
Response
Verification completed. A 200 does not by itself mean the signature verified, see the valid field.
Response shared by POST /refusal/verify and POST /audit/verify: a bare signature-validity result, no wrapper, no partial-failure detail. Both routes verify a signature over bytes with no database lookup, so there is nothing more specific to report than valid or not.
Whether the signature verifies against Parmana's public key for the stated algorithm and key ID.
curl --request POST \
--url http://localhost:3000/refusal/verify \
--header 'Content-Type: application/json' \
--data '
{
"refusalRecordId": "eddc5dd1-a791-4470-9534-11b3fc573ab8",
"businessTransactionId": "353c73fb-5e87-4dbe-8bfc-c15c8f18d871",
"decision": {
"decisionId": "3919f4b6-cbc8-44ec-a6a1-8887ee85f314",
"intentId": "4ba6b14a-c593-4f5c-ab58-dcef38a29364",
"policy": {
"name": "vendor-payment",
"version": "2.0.0",
"schemaVersion": "1.0.0"
},
"signals": {
"vendorVerified": false,
"invoiceVerified": true,
"paymentApproved": true,
"sufficientFunds": true,
"paymentAmount": 1000,
"riskScore": 5,
"vendorId": "vendor://payments"
},
"outcome": "REJECTED",
"reason": "Vendor payment rejected because the vendor has not been verified.",
"evaluatedAt": "2026-09-15T03:27:45.666Z"
},
"evaluatedIntent": {
"target": "vendor://payments",
"parameters": {
"amount": 1000,
"currency": "USD"
}
},
"createdAt": "2026-09-15T03:27:45.666Z",
"refusalRecordHash": "47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca",
"signature": {
"algorithm": "ed25519",
"keyId": "default",
"value": "tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==",
"signedAt": "2026-09-15T03:27:45.668Z"
}
}
'import requests
url = "http://localhost:3000/refusal/verify"
payload = {
"refusalRecordId": "eddc5dd1-a791-4470-9534-11b3fc573ab8",
"businessTransactionId": "353c73fb-5e87-4dbe-8bfc-c15c8f18d871",
"decision": {
"decisionId": "3919f4b6-cbc8-44ec-a6a1-8887ee85f314",
"intentId": "4ba6b14a-c593-4f5c-ab58-dcef38a29364",
"policy": {
"name": "vendor-payment",
"version": "2.0.0",
"schemaVersion": "1.0.0"
},
"signals": {
"vendorVerified": False,
"invoiceVerified": True,
"paymentApproved": True,
"sufficientFunds": True,
"paymentAmount": 1000,
"riskScore": 5,
"vendorId": "vendor://payments"
},
"outcome": "REJECTED",
"reason": "Vendor payment rejected because the vendor has not been verified.",
"evaluatedAt": "2026-09-15T03:27:45.666Z"
},
"evaluatedIntent": {
"target": "vendor://payments",
"parameters": {
"amount": 1000,
"currency": "USD"
}
},
"createdAt": "2026-09-15T03:27:45.666Z",
"refusalRecordHash": "47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca",
"signature": {
"algorithm": "ed25519",
"keyId": "default",
"value": "tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==",
"signedAt": "2026-09-15T03:27:45.668Z"
}
}
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({
refusalRecordId: 'eddc5dd1-a791-4470-9534-11b3fc573ab8',
businessTransactionId: '353c73fb-5e87-4dbe-8bfc-c15c8f18d871',
decision: {
decisionId: '3919f4b6-cbc8-44ec-a6a1-8887ee85f314',
intentId: '4ba6b14a-c593-4f5c-ab58-dcef38a29364',
policy: {name: 'vendor-payment', version: '2.0.0', schemaVersion: '1.0.0'},
signals: {
vendorVerified: false,
invoiceVerified: true,
paymentApproved: true,
sufficientFunds: true,
paymentAmount: 1000,
riskScore: 5,
vendorId: 'vendor://payments'
},
outcome: 'REJECTED',
reason: 'Vendor payment rejected because the vendor has not been verified.',
evaluatedAt: '2026-09-15T03:27:45.666Z'
},
evaluatedIntent: {target: 'vendor://payments', parameters: {amount: 1000, currency: 'USD'}},
createdAt: '2026-09-15T03:27:45.666Z',
refusalRecordHash: '47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca',
signature: {
algorithm: 'ed25519',
keyId: 'default',
value: 'tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==',
signedAt: '2026-09-15T03:27:45.668Z'
}
})
};
fetch('http://localhost:3000/refusal/verify', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "3000",
CURLOPT_URL => "http://localhost:3000/refusal/verify",
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([
'refusalRecordId' => 'eddc5dd1-a791-4470-9534-11b3fc573ab8',
'businessTransactionId' => '353c73fb-5e87-4dbe-8bfc-c15c8f18d871',
'decision' => [
'decisionId' => '3919f4b6-cbc8-44ec-a6a1-8887ee85f314',
'intentId' => '4ba6b14a-c593-4f5c-ab58-dcef38a29364',
'policy' => [
'name' => 'vendor-payment',
'version' => '2.0.0',
'schemaVersion' => '1.0.0'
],
'signals' => [
'vendorVerified' => false,
'invoiceVerified' => true,
'paymentApproved' => true,
'sufficientFunds' => true,
'paymentAmount' => 1000,
'riskScore' => 5,
'vendorId' => 'vendor://payments'
],
'outcome' => 'REJECTED',
'reason' => 'Vendor payment rejected because the vendor has not been verified.',
'evaluatedAt' => '2026-09-15T03:27:45.666Z'
],
'evaluatedIntent' => [
'target' => 'vendor://payments',
'parameters' => [
'amount' => 1000,
'currency' => 'USD'
]
],
'createdAt' => '2026-09-15T03:27:45.666Z',
'refusalRecordHash' => '47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca',
'signature' => [
'algorithm' => 'ed25519',
'keyId' => 'default',
'value' => 'tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==',
'signedAt' => '2026-09-15T03:27:45.668Z'
]
]),
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 := "http://localhost:3000/refusal/verify"
payload := strings.NewReader("{\n \"refusalRecordId\": \"eddc5dd1-a791-4470-9534-11b3fc573ab8\",\n \"businessTransactionId\": \"353c73fb-5e87-4dbe-8bfc-c15c8f18d871\",\n \"decision\": {\n \"decisionId\": \"3919f4b6-cbc8-44ec-a6a1-8887ee85f314\",\n \"intentId\": \"4ba6b14a-c593-4f5c-ab58-dcef38a29364\",\n \"policy\": {\n \"name\": \"vendor-payment\",\n \"version\": \"2.0.0\",\n \"schemaVersion\": \"1.0.0\"\n },\n \"signals\": {\n \"vendorVerified\": false,\n \"invoiceVerified\": true,\n \"paymentApproved\": true,\n \"sufficientFunds\": true,\n \"paymentAmount\": 1000,\n \"riskScore\": 5,\n \"vendorId\": \"vendor://payments\"\n },\n \"outcome\": \"REJECTED\",\n \"reason\": \"Vendor payment rejected because the vendor has not been verified.\",\n \"evaluatedAt\": \"2026-09-15T03:27:45.666Z\"\n },\n \"evaluatedIntent\": {\n \"target\": \"vendor://payments\",\n \"parameters\": {\n \"amount\": 1000,\n \"currency\": \"USD\"\n }\n },\n \"createdAt\": \"2026-09-15T03:27:45.666Z\",\n \"refusalRecordHash\": \"47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca\",\n \"signature\": {\n \"algorithm\": \"ed25519\",\n \"keyId\": \"default\",\n \"value\": \"tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==\",\n \"signedAt\": \"2026-09-15T03:27:45.668Z\"\n }\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("http://localhost:3000/refusal/verify")
.header("Content-Type", "application/json")
.body("{\n \"refusalRecordId\": \"eddc5dd1-a791-4470-9534-11b3fc573ab8\",\n \"businessTransactionId\": \"353c73fb-5e87-4dbe-8bfc-c15c8f18d871\",\n \"decision\": {\n \"decisionId\": \"3919f4b6-cbc8-44ec-a6a1-8887ee85f314\",\n \"intentId\": \"4ba6b14a-c593-4f5c-ab58-dcef38a29364\",\n \"policy\": {\n \"name\": \"vendor-payment\",\n \"version\": \"2.0.0\",\n \"schemaVersion\": \"1.0.0\"\n },\n \"signals\": {\n \"vendorVerified\": false,\n \"invoiceVerified\": true,\n \"paymentApproved\": true,\n \"sufficientFunds\": true,\n \"paymentAmount\": 1000,\n \"riskScore\": 5,\n \"vendorId\": \"vendor://payments\"\n },\n \"outcome\": \"REJECTED\",\n \"reason\": \"Vendor payment rejected because the vendor has not been verified.\",\n \"evaluatedAt\": \"2026-09-15T03:27:45.666Z\"\n },\n \"evaluatedIntent\": {\n \"target\": \"vendor://payments\",\n \"parameters\": {\n \"amount\": 1000,\n \"currency\": \"USD\"\n }\n },\n \"createdAt\": \"2026-09-15T03:27:45.666Z\",\n \"refusalRecordHash\": \"47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca\",\n \"signature\": {\n \"algorithm\": \"ed25519\",\n \"keyId\": \"default\",\n \"value\": \"tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==\",\n \"signedAt\": \"2026-09-15T03:27:45.668Z\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:3000/refusal/verify")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"refusalRecordId\": \"eddc5dd1-a791-4470-9534-11b3fc573ab8\",\n \"businessTransactionId\": \"353c73fb-5e87-4dbe-8bfc-c15c8f18d871\",\n \"decision\": {\n \"decisionId\": \"3919f4b6-cbc8-44ec-a6a1-8887ee85f314\",\n \"intentId\": \"4ba6b14a-c593-4f5c-ab58-dcef38a29364\",\n \"policy\": {\n \"name\": \"vendor-payment\",\n \"version\": \"2.0.0\",\n \"schemaVersion\": \"1.0.0\"\n },\n \"signals\": {\n \"vendorVerified\": false,\n \"invoiceVerified\": true,\n \"paymentApproved\": true,\n \"sufficientFunds\": true,\n \"paymentAmount\": 1000,\n \"riskScore\": 5,\n \"vendorId\": \"vendor://payments\"\n },\n \"outcome\": \"REJECTED\",\n \"reason\": \"Vendor payment rejected because the vendor has not been verified.\",\n \"evaluatedAt\": \"2026-09-15T03:27:45.666Z\"\n },\n \"evaluatedIntent\": {\n \"target\": \"vendor://payments\",\n \"parameters\": {\n \"amount\": 1000,\n \"currency\": \"USD\"\n }\n },\n \"createdAt\": \"2026-09-15T03:27:45.666Z\",\n \"refusalRecordHash\": \"47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca\",\n \"signature\": {\n \"algorithm\": \"ed25519\",\n \"keyId\": \"default\",\n \"value\": \"tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==\",\n \"signedAt\": \"2026-09-15T03:27:45.668Z\"\n }\n}"
response = http.request(request)
puts response.read_body{
"valid": true
}{
"error": "Request body must be a Refusal Record (refusalRecordId, businessTransactionId, decision, refusalRecordHash, signature required)."
}