curl --request POST \
--url https://api.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"customer_id": "<string>",
"idempotency_key": "<string>"
}
'import requests
url = "https://api.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release"
payload = {
"customer_id": "<string>",
"idempotency_key": "<string>"
}
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({customer_id: '<string>', idempotency_key: '<string>'})
};
fetch('https://api.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release', 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.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release",
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([
'customer_id' => '<string>',
'idempotency_key' => '<string>'
]),
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.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release"
payload := strings.NewReader("{\n \"customer_id\": \"<string>\",\n \"idempotency_key\": \"<string>\"\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.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customer_id\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release")
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 \"customer_id\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"release": {
"release_id": "<string>",
"transport": "direct",
"output_hash": "<string>",
"replayed": true
},
"message": "<string>"
}{
"error": "<string>",
"detail": "<string>"
}{
"error": "<string>",
"detail": "<string>"
}{
"release": {
"release_id": "<string>",
"transport": "direct",
"output_hash": "<string>",
"replayed": true
},
"message": "<string>"
}Release one exact immutable source-bound payment batch
Requires explicit payment_batch.release plus authority to review every source. The server revalidates the source revision and effective global transport before atomically recording the first irreversible marker.
curl --request POST \
--url https://api.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"customer_id": "<string>",
"idempotency_key": "<string>"
}
'import requests
url = "https://api.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release"
payload = {
"customer_id": "<string>",
"idempotency_key": "<string>"
}
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({customer_id: '<string>', idempotency_key: '<string>'})
};
fetch('https://api.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release', 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.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release",
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([
'customer_id' => '<string>',
'idempotency_key' => '<string>'
]),
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.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release"
payload := strings.NewReader("{\n \"customer_id\": \"<string>\",\n \"idempotency_key\": \"<string>\"\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.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customer_id\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.app.lastaccountingcompany.com/portal/payment-batches/{batch_id}/release")
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 \"customer_id\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"release": {
"release_id": "<string>",
"transport": "direct",
"output_hash": "<string>",
"replayed": true
},
"message": "<string>"
}{
"error": "<string>",
"detail": "<string>"
}{
"error": "<string>",
"detail": "<string>"
}{
"release": {
"release_id": "<string>",
"transport": "direct",
"output_hash": "<string>",
"replayed": true
},
"message": "<string>"
}Authorizations
Firebase ID token from an interactive portal session. Required for interactive operations (payroll, company settings, API-key management) and invoice decisions allowed by the member's review permissions.
Path Parameters
Body
Carries no bank login identifier. The PSU identifier Open Payments requires on every ISO call is derived server-side from the signed-in member's immutable auth subject (an opaque hash, unique per person and company, never a bank credential), recorded with the submission, and reused for every later status read of that submission. A sign-in without a derivable identity is refused after source revalidation and before any marker or bank call.
Response
Exact durable release receipt for direct bank delivery. A retry with the same idempotency key replays the receipt with replayed: true; when the delivery already crossed its request boundary for that release, the recorded submission stands, no bank call is made, and message says so.