Approve a signing request with a machine stamp
Submits a machine (api-key) P-256 stamp approving the payout. Conduit verifies the signature locally, resolves it to an active machine signer, checks it authorizes this exact request, and relays it to the signing provider. Idempotent: whether the request is still collecting signatures or already resolved, a (re)submission returns the request’s current state — safe to retry after a timeout. Send an Idempotency-Key header (required on this money-moving route).
curl --request POST \
--url https://api.sandbox.conduit.financial/v2/signing-requests/{id}/approve \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'x-api-key: <api-key>' \
--data '
{
"signedBody": "<string>",
"stamp": "<string>"
}
'import requests
url = "https://api.sandbox.conduit.financial/v2/signing-requests/{id}/approve"
payload = {
"signedBody": "<string>",
"stamp": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
'x-api-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({signedBody: '<string>', stamp: '<string>'})
};
fetch('https://api.sandbox.conduit.financial/v2/signing-requests/{id}/approve', 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.sandbox.conduit.financial/v2/signing-requests/{id}/approve",
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([
'signedBody' => '<string>',
'stamp' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"x-api-key: <api-key>"
],
]);
$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.sandbox.conduit.financial/v2/signing-requests/{id}/approve"
payload := strings.NewReader("{\n \"signedBody\": \"<string>\",\n \"stamp\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("x-api-key", "<api-key>")
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.sandbox.conduit.financial/v2/signing-requests/{id}/approve")
.header("Idempotency-Key", "<idempotency-key>")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"signedBody\": \"<string>\",\n \"stamp\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.conduit.financial/v2/signing-requests/{id}/approve")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"signedBody\": \"<string>\",\n \"stamp\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"transactionId": "<string>",
"customerId": "<string>",
"requiredApprovals": 0,
"approvedCount": 0,
"expiresAt": "2026-01-15T09:30:00.000Z",
"createdAt": "2026-01-15T09:30:00.000Z",
"approvalMaterial": {
"version": "1",
"activityId": "<string>",
"fingerprint": "<string>",
"subOrganizationId": "<string>",
"outbound": {
"toAddress": "<string>",
"assetAmount": {
"amount": "<string>"
}
}
}
}{
"type": "INVALID_OID_FORMAT",
"title": "Invalid Object ID Format",
"status": 400,
"detail": "A path or query parameter expected a valid object identifier but received a value that does not match the expected format.",
"resolution": "Verify that all IDs in the request URL and query parameters are correctly formatted. IDs are typically prefixed strings like 'cus_...', 'app_...', or 'doc_...'.",
"docs": "https://conduit-v2.mintlify.app/errors#invalid-oid-format",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "API_KEY_MISSING",
"title": "API Key Missing",
"status": 401,
"detail": "The request did not include an API key. All API requests must be authenticated.",
"resolution": "Include your API key in the 'x-api-key' header with every request.",
"docs": "https://conduit-v2.mintlify.app/errors#api-key-missing",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "API_KEY_READ_ONLY",
"title": "API Key Is Read-Only",
"status": 403,
"detail": "This API key has read-only access and cannot perform write operations. Read-only keys may make read requests (GET, HEAD, OPTIONS) only.",
"resolution": "Use a read-write API key for this request, or have an organization admin mint one from the dashboard.",
"docs": "https://conduit-v2.mintlify.app/errors#api-key-read-only",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "SIGNING_REQUEST_NOT_FOUND",
"title": "Signing request not found",
"status": 404,
"detail": "No signing request with this id exists for your account. The same response is returned for an id that belongs to another account, so a 404 never confirms that an id exists elsewhere.",
"resolution": "List your actionable signing requests with GET /v2/signing-requests and use an id from that list. The transaction.awaiting_signature webhook also delivers the id directly as signingRequestId (programmatic mode).",
"docs": "https://conduit-v2.mintlify.app/errors#signing-request-not-found",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "IDEMPOTENCY_KEY_CONFLICT",
"title": "Idempotency Key Conflict",
"status": 409,
"detail": "The idempotency key was previously used with a different request body. Idempotency keys are bound to the exact request shape — replays must match the original.",
"resolution": "Use a fresh idempotency key for the new request, or replay the original request unchanged.",
"docs": "https://conduit-v2.mintlify.app/errors#idempotency-key-conflict",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "UNSUPPORTED_MEDIA_TYPE",
"title": "Unsupported Media Type",
"status": 415,
"detail": "The request carries a body with a Content-Type this endpoint cannot parse. JSON endpoints accept 'application/json'; a body with no Content-Type header at all is assumed to be JSON. File-upload endpoints accept only 'multipart/form-data' — JSON or undeclared bodies are rejected there.",
"resolution": "Send the request body with the 'Content-Type: application/json' header. For file uploads, use 'Content-Type: multipart/form-data' — upload endpoints accept no other body type.",
"docs": "https://conduit-v2.mintlify.app/errors#unsupported-media-type",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "SIGNING_STAMP_INVALID",
"title": "Signing stamp is invalid",
"status": 422,
"detail": "The submitted stamp could not be verified: it is not a well-formed P-256 stamp, its signature does not match the signed body, or the signed body does not authorize this exact signing request (its activity fingerprint, sub-organization, or request type does not match).",
"resolution": "Re-fetch the signing request's approval material with GET /v2/signing-requests/{id}, rebuild the approve/reject activity body exactly as returned, and stamp it with your machine signer's P-256 api key.",
"docs": "https://conduit-v2.mintlify.app/errors#signing-stamp-invalid",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "RATE_LIMITED",
"title": "Rate Limited",
"status": 429,
"detail": "Too many requests. This error is returned by three independent checks: the per-organization bucket applied to every authenticated API request; the per-IP bucket applied to unauthenticated traffic before an API key is validated; and the per-IP bucket applied when repeated invalid API keys are submitted from the same address. Honor the Retry-After header (also exposed as retryAfterSeconds in the body) before retrying. Current limits and remaining budget are visible in X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset on rate-limited route responses.",
"resolution": "Sleep until Retry-After seconds have elapsed, then retry. For sustained workloads exceeding the per-organization defaults, request a rate-limit increase through your support contact.",
"docs": "https://conduit-v2.mintlify.app/errors#rate-limited",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z",
"retryAfterSeconds": 3
}{
"type": "INTERNAL_ERROR",
"title": "Internal Error",
"status": 500,
"detail": "An unexpected error occurred while processing your request.",
"resolution": "Retry the request after a brief delay. If the error persists, contact support and include the correlationId from the error response for investigation.",
"docs": "https://conduit-v2.mintlify.app/errors#internal-error",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "SIGNING_PROVIDER_UNAVAILABLE",
"title": "Signing Provider Unavailable",
"status": 502,
"detail": "The signing provider returned a transient upstream error (network failure, timeout, rate limit, or 5xx) rather than a definitive verdict on the stamped request. The signer is authenticated and the request itself is fine — the provider just couldn't be reached right now.",
"resolution": "Retry the request after a brief delay. Do not re-authenticate — the session is still valid.",
"docs": "https://conduit-v2.mintlify.app/errors#signing-provider-unavailable",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}Authorizations
Headers
Caller-generated unique key that lets the server safely replay this request. The cached response is returned for 5 minutes on any retry with the same key from the same API principal. Required on every state-changing money-moving or resource-creating POST.
1 - 128^[A-Za-z0-9_.:-]{1,128}$Path Parameters
Body
Response
Signing request id (equals the pending verification id).
^vrf_[0-9A-Za-z]{22}$^txn_[0-9A-Za-z]{22}$^cus_[0-9A-Za-z]{22}$awaiting_signature, quorum_met, declined, expired -9007199254740991 <= x <= 9007199254740991-9007199254740991 <= x <= 9007199254740991ISO 8601 timestamp
"2026-01-15T09:30:00.000Z"
ISO 8601 timestamp
"2026-01-15T09:30:00.000Z"
Show child attributes
Show child attributes
curl --request POST \
--url https://api.sandbox.conduit.financial/v2/signing-requests/{id}/approve \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'x-api-key: <api-key>' \
--data '
{
"signedBody": "<string>",
"stamp": "<string>"
}
'import requests
url = "https://api.sandbox.conduit.financial/v2/signing-requests/{id}/approve"
payload = {
"signedBody": "<string>",
"stamp": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
'x-api-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({signedBody: '<string>', stamp: '<string>'})
};
fetch('https://api.sandbox.conduit.financial/v2/signing-requests/{id}/approve', 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.sandbox.conduit.financial/v2/signing-requests/{id}/approve",
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([
'signedBody' => '<string>',
'stamp' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"x-api-key: <api-key>"
],
]);
$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.sandbox.conduit.financial/v2/signing-requests/{id}/approve"
payload := strings.NewReader("{\n \"signedBody\": \"<string>\",\n \"stamp\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("x-api-key", "<api-key>")
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.sandbox.conduit.financial/v2/signing-requests/{id}/approve")
.header("Idempotency-Key", "<idempotency-key>")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"signedBody\": \"<string>\",\n \"stamp\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.conduit.financial/v2/signing-requests/{id}/approve")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"signedBody\": \"<string>\",\n \"stamp\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"transactionId": "<string>",
"customerId": "<string>",
"requiredApprovals": 0,
"approvedCount": 0,
"expiresAt": "2026-01-15T09:30:00.000Z",
"createdAt": "2026-01-15T09:30:00.000Z",
"approvalMaterial": {
"version": "1",
"activityId": "<string>",
"fingerprint": "<string>",
"subOrganizationId": "<string>",
"outbound": {
"toAddress": "<string>",
"assetAmount": {
"amount": "<string>"
}
}
}
}{
"type": "INVALID_OID_FORMAT",
"title": "Invalid Object ID Format",
"status": 400,
"detail": "A path or query parameter expected a valid object identifier but received a value that does not match the expected format.",
"resolution": "Verify that all IDs in the request URL and query parameters are correctly formatted. IDs are typically prefixed strings like 'cus_...', 'app_...', or 'doc_...'.",
"docs": "https://conduit-v2.mintlify.app/errors#invalid-oid-format",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "API_KEY_MISSING",
"title": "API Key Missing",
"status": 401,
"detail": "The request did not include an API key. All API requests must be authenticated.",
"resolution": "Include your API key in the 'x-api-key' header with every request.",
"docs": "https://conduit-v2.mintlify.app/errors#api-key-missing",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "API_KEY_READ_ONLY",
"title": "API Key Is Read-Only",
"status": 403,
"detail": "This API key has read-only access and cannot perform write operations. Read-only keys may make read requests (GET, HEAD, OPTIONS) only.",
"resolution": "Use a read-write API key for this request, or have an organization admin mint one from the dashboard.",
"docs": "https://conduit-v2.mintlify.app/errors#api-key-read-only",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "SIGNING_REQUEST_NOT_FOUND",
"title": "Signing request not found",
"status": 404,
"detail": "No signing request with this id exists for your account. The same response is returned for an id that belongs to another account, so a 404 never confirms that an id exists elsewhere.",
"resolution": "List your actionable signing requests with GET /v2/signing-requests and use an id from that list. The transaction.awaiting_signature webhook also delivers the id directly as signingRequestId (programmatic mode).",
"docs": "https://conduit-v2.mintlify.app/errors#signing-request-not-found",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "IDEMPOTENCY_KEY_CONFLICT",
"title": "Idempotency Key Conflict",
"status": 409,
"detail": "The idempotency key was previously used with a different request body. Idempotency keys are bound to the exact request shape — replays must match the original.",
"resolution": "Use a fresh idempotency key for the new request, or replay the original request unchanged.",
"docs": "https://conduit-v2.mintlify.app/errors#idempotency-key-conflict",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "UNSUPPORTED_MEDIA_TYPE",
"title": "Unsupported Media Type",
"status": 415,
"detail": "The request carries a body with a Content-Type this endpoint cannot parse. JSON endpoints accept 'application/json'; a body with no Content-Type header at all is assumed to be JSON. File-upload endpoints accept only 'multipart/form-data' — JSON or undeclared bodies are rejected there.",
"resolution": "Send the request body with the 'Content-Type: application/json' header. For file uploads, use 'Content-Type: multipart/form-data' — upload endpoints accept no other body type.",
"docs": "https://conduit-v2.mintlify.app/errors#unsupported-media-type",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "SIGNING_STAMP_INVALID",
"title": "Signing stamp is invalid",
"status": 422,
"detail": "The submitted stamp could not be verified: it is not a well-formed P-256 stamp, its signature does not match the signed body, or the signed body does not authorize this exact signing request (its activity fingerprint, sub-organization, or request type does not match).",
"resolution": "Re-fetch the signing request's approval material with GET /v2/signing-requests/{id}, rebuild the approve/reject activity body exactly as returned, and stamp it with your machine signer's P-256 api key.",
"docs": "https://conduit-v2.mintlify.app/errors#signing-stamp-invalid",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "RATE_LIMITED",
"title": "Rate Limited",
"status": 429,
"detail": "Too many requests. This error is returned by three independent checks: the per-organization bucket applied to every authenticated API request; the per-IP bucket applied to unauthenticated traffic before an API key is validated; and the per-IP bucket applied when repeated invalid API keys are submitted from the same address. Honor the Retry-After header (also exposed as retryAfterSeconds in the body) before retrying. Current limits and remaining budget are visible in X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset on rate-limited route responses.",
"resolution": "Sleep until Retry-After seconds have elapsed, then retry. For sustained workloads exceeding the per-organization defaults, request a rate-limit increase through your support contact.",
"docs": "https://conduit-v2.mintlify.app/errors#rate-limited",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z",
"retryAfterSeconds": 3
}{
"type": "INTERNAL_ERROR",
"title": "Internal Error",
"status": 500,
"detail": "An unexpected error occurred while processing your request.",
"resolution": "Retry the request after a brief delay. If the error persists, contact support and include the correlationId from the error response for investigation.",
"docs": "https://conduit-v2.mintlify.app/errors#internal-error",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}{
"type": "SIGNING_PROVIDER_UNAVAILABLE",
"title": "Signing Provider Unavailable",
"status": 502,
"detail": "The signing provider returned a transient upstream error (network failure, timeout, rate limit, or 5xx) rather than a definitive verdict on the stamped request. The signer is authenticated and the request itself is fine — the provider just couldn't be reached right now.",
"resolution": "Retry the request after a brief delay. Do not re-authenticate — the session is still valid.",
"docs": "https://conduit-v2.mintlify.app/errors#signing-provider-unavailable",
"instance": "/v2/...",
"correlationId": "req_a1b2c3d4",
"timestamp": "2026-01-15T09:30:00.000Z"
}