curl --request POST \
--url https://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"action": "complete",
"challengeIdentifier": "{{challengeIdentifier}}",
"firstFactor": {
"kind": "Fido2",
"credentialAssertion": {
"credId": "{{passkeyCredentialId}}",
"clientData": "{{passkeyClientData}}",
"signature": "{{passkeySignature}}",
"authenticatorData": "{{passkeyAuthenticatorData}}"
}
}
}
'import requests
url = "https://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm"
payload = {
"action": "complete",
"challengeIdentifier": "{{challengeIdentifier}}",
"firstFactor": {
"kind": "Fido2",
"credentialAssertion": {
"credId": "{{passkeyCredentialId}}",
"clientData": "{{passkeyClientData}}",
"signature": "{{passkeySignature}}",
"authenticatorData": "{{passkeyAuthenticatorData}}"
}
}
}
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({
action: 'complete',
challengeIdentifier: '{{challengeIdentifier}}',
firstFactor: {
kind: 'Fido2',
credentialAssertion: {
credId: '{{passkeyCredentialId}}',
clientData: '{{passkeyClientData}}',
signature: '{{passkeySignature}}',
authenticatorData: '{{passkeyAuthenticatorData}}'
}
}
})
};
fetch('https://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm', 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://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm",
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([
'action' => 'complete',
'challengeIdentifier' => '{{challengeIdentifier}}',
'firstFactor' => [
'kind' => 'Fido2',
'credentialAssertion' => [
'credId' => '{{passkeyCredentialId}}',
'clientData' => '{{passkeyClientData}}',
'signature' => '{{passkeySignature}}',
'authenticatorData' => '{{passkeyAuthenticatorData}}'
]
]
]),
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://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm"
payload := strings.NewReader("{\n \"action\": \"complete\",\n \"challengeIdentifier\": \"{{challengeIdentifier}}\",\n \"firstFactor\": {\n \"kind\": \"Fido2\",\n \"credentialAssertion\": {\n \"credId\": \"{{passkeyCredentialId}}\",\n \"clientData\": \"{{passkeyClientData}}\",\n \"signature\": \"{{passkeySignature}}\",\n \"authenticatorData\": \"{{passkeyAuthenticatorData}}\"\n }\n }\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://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"action\": \"complete\",\n \"challengeIdentifier\": \"{{challengeIdentifier}}\",\n \"firstFactor\": {\n \"kind\": \"Fido2\",\n \"credentialAssertion\": {\n \"credId\": \"{{passkeyCredentialId}}\",\n \"clientData\": \"{{passkeyClientData}}\",\n \"signature\": \"{{passkeySignature}}\",\n \"authenticatorData\": \"{{passkeyAuthenticatorData}}\"\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm")
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 \"action\": \"complete\",\n \"challengeIdentifier\": \"{{challengeIdentifier}}\",\n \"firstFactor\": {\n \"kind\": \"Fido2\",\n \"credentialAssertion\": {\n \"credId\": \"{{passkeyCredentialId}}\",\n \"clientData\": \"{{passkeyClientData}}\",\n \"signature\": \"{{passkeySignature}}\",\n \"authenticatorData\": \"{{passkeyAuthenticatorData}}\"\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"status": "approval_required",
"funding": {
"transferId": "<string>",
"accountId": "<string>",
"agentAccountId": "<string>",
"direction": "owner_to_agent",
"asset": "<string>",
"amount": "<string>",
"amountAtoms": "<string>",
"status": "prepared",
"refusalReason": "owner_signature_invalid",
"journalRecordOrdinal": 123,
"journalRecordDigest": "<string>",
"intentDigest": "<string>",
"expiresAtEpochMs": 123,
"createdAtEpochMs": 123
},
"challenge": {
"challenge": "<string>",
"challengeIdentifier": "<string>",
"allowCredentials": {
"key": [
{
"type": "public-key",
"id": "<string>"
}
],
"webauthn": [
{
"type": "public-key",
"id": "<string>"
}
]
},
"userVerification": "required"
}
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}Read, approve or complete funding an agent
Drives one funding intent. status answers the funding. initiate answers status approval_required with a fresh passkey challenge for a passkey session, or status owner_signature_required with no challenge for an API key. complete spends the owner’s passkey answer: the owner’s signature over the intent must verify against the owner’s Party key, and then the venue moves the money and answers status credited once the move is journaled. An approved funding never expires: while the venue holds it and its record is still being confirmed it answers status submitted, and initiate sends it again with no new passkey; the venue moves one funding at most once. An answer for another intent, an expired challenge or a replayed answer moves nothing and answers approval_required with a fresh challenge. A refused funding answers 409 with its agentRefusal: owner_signature_invalid, transfer_eligibility_insufficient (more than the account may move now, pending withdrawals included), transfer_blocked or account_unavailable; read the funding again with status. An expired intent answers 409 with agentRefusal agent_funding_expired. A 503 with agentRefusal venue_halted (the venue is halted), account_transfer_unavailable, engine_view_unavailable or account_transfer_not_enabled moved nothing; an approved funding stays submitted and initiate sends it again. Every action but status also meets the venue’s gates first: a retired legacy account answers 409 account_legacy_excluded, a paused intake or an unavailable signing provider answers 503 and moves nothing. An API key with the funding scope may send status and initiate only; complete with an API key answers HTTP 403 passkey_required.
Method and path: POST /v1/accounts//agent-accounts//fundings//confirm
Authentication: DFNS trader bearer required.
Request schema: AgentFundingConfirmRequest.
Response schema: AgentFundingConfirmResponse.
Error envelope: ExternalRestError (external-rest-error/v1).
curl --request POST \
--url https://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"action": "complete",
"challengeIdentifier": "{{challengeIdentifier}}",
"firstFactor": {
"kind": "Fido2",
"credentialAssertion": {
"credId": "{{passkeyCredentialId}}",
"clientData": "{{passkeyClientData}}",
"signature": "{{passkeySignature}}",
"authenticatorData": "{{passkeyAuthenticatorData}}"
}
}
}
'import requests
url = "https://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm"
payload = {
"action": "complete",
"challengeIdentifier": "{{challengeIdentifier}}",
"firstFactor": {
"kind": "Fido2",
"credentialAssertion": {
"credId": "{{passkeyCredentialId}}",
"clientData": "{{passkeyClientData}}",
"signature": "{{passkeySignature}}",
"authenticatorData": "{{passkeyAuthenticatorData}}"
}
}
}
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({
action: 'complete',
challengeIdentifier: '{{challengeIdentifier}}',
firstFactor: {
kind: 'Fido2',
credentialAssertion: {
credId: '{{passkeyCredentialId}}',
clientData: '{{passkeyClientData}}',
signature: '{{passkeySignature}}',
authenticatorData: '{{passkeyAuthenticatorData}}'
}
}
})
};
fetch('https://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm', 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://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm",
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([
'action' => 'complete',
'challengeIdentifier' => '{{challengeIdentifier}}',
'firstFactor' => [
'kind' => 'Fido2',
'credentialAssertion' => [
'credId' => '{{passkeyCredentialId}}',
'clientData' => '{{passkeyClientData}}',
'signature' => '{{passkeySignature}}',
'authenticatorData' => '{{passkeyAuthenticatorData}}'
]
]
]),
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://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm"
payload := strings.NewReader("{\n \"action\": \"complete\",\n \"challengeIdentifier\": \"{{challengeIdentifier}}\",\n \"firstFactor\": {\n \"kind\": \"Fido2\",\n \"credentialAssertion\": {\n \"credId\": \"{{passkeyCredentialId}}\",\n \"clientData\": \"{{passkeyClientData}}\",\n \"signature\": \"{{passkeySignature}}\",\n \"authenticatorData\": \"{{passkeyAuthenticatorData}}\"\n }\n }\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://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"action\": \"complete\",\n \"challengeIdentifier\": \"{{challengeIdentifier}}\",\n \"firstFactor\": {\n \"kind\": \"Fido2\",\n \"credentialAssertion\": {\n \"credId\": \"{{passkeyCredentialId}}\",\n \"clientData\": \"{{passkeyClientData}}\",\n \"signature\": \"{{passkeySignature}}\",\n \"authenticatorData\": \"{{passkeyAuthenticatorData}}\"\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://testnet.edel-api.xyz/v1/accounts/{accountId}/agent-accounts/{agentAccountId}/fundings/{transferId}/confirm")
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 \"action\": \"complete\",\n \"challengeIdentifier\": \"{{challengeIdentifier}}\",\n \"firstFactor\": {\n \"kind\": \"Fido2\",\n \"credentialAssertion\": {\n \"credId\": \"{{passkeyCredentialId}}\",\n \"clientData\": \"{{passkeyClientData}}\",\n \"signature\": \"{{passkeySignature}}\",\n \"authenticatorData\": \"{{passkeyAuthenticatorData}}\"\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"status": "approval_required",
"funding": {
"transferId": "<string>",
"accountId": "<string>",
"agentAccountId": "<string>",
"direction": "owner_to_agent",
"asset": "<string>",
"amount": "<string>",
"amountAtoms": "<string>",
"status": "prepared",
"refusalReason": "owner_signature_invalid",
"journalRecordOrdinal": 123,
"journalRecordDigest": "<string>",
"intentDigest": "<string>",
"expiresAtEpochMs": 123,
"createdAtEpochMs": 123
},
"challenge": {
"challenge": "<string>",
"challengeIdentifier": "<string>",
"allowCredentials": {
"key": [
{
"type": "public-key",
"id": "<string>"
}
],
"webauthn": [
{
"type": "public-key",
"id": "<string>"
}
]
},
"userVerification": "required"
}
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}{
"version": "external-rest-error/v1",
"requestId": "<string>",
"code": "invalid_request",
"safeMessage": "<string>",
"retryable": true,
"recoveryActions": [
"none"
],
"occurredAtEpochMs": 1,
"realtimeTicketFailure": "invalid",
"apiKeyRejection": "malformed",
"agentRefusal": "agents_not_admitted_in_environment",
"rejectionGuard": "amount_atoms_invalid",
"withdrawalFailure": "requested",
"dependency": "dfns"
}Authorizations
The authorization field takes the session bearer returned by sign-in, or an API key where the route allows keys. Paste the token itself into the authorization field.
Path Parameters
1^aga_[0-9a-f]{32}$^agent-transfer:[a-f0-9]{64}$Body
- Option 1
- Option 2
- Option 3
"status"