curl --request POST \
--url https://production-api.puppetvendors.com/payouts/make-payment \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'x-access-token: <api-key>' \
--data '
{
"vendors": [
{
"vendorId": "507f1f77bcf86cd799439012",
"lineItemIds": [
"507f1f77bcf86cd799439099",
"507f1f77bcf86cd79943909a"
],
"adjustmentIds": [
"507f1f77bcf86cd799439088"
]
},
{
"vendorId": "507f1f77bcf86cd799439013",
"lineItemIds": [
"507f1f77bcf86cd7994390b1"
]
}
],
"method": "stripe",
"notifyVendor": true,
"payoutDate": "2026-03-02",
"comment": "March payouts"
}
'import requests
url = "https://production-api.puppetvendors.com/payouts/make-payment"
payload = {
"vendors": [
{
"vendorId": "507f1f77bcf86cd799439012",
"lineItemIds": ["507f1f77bcf86cd799439099", "507f1f77bcf86cd79943909a"],
"adjustmentIds": ["507f1f77bcf86cd799439088"]
},
{
"vendorId": "507f1f77bcf86cd799439013",
"lineItemIds": ["507f1f77bcf86cd7994390b1"]
}
],
"method": "stripe",
"notifyVendor": True,
"payoutDate": "2026-03-02",
"comment": "March payouts"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"x-access-token": "<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-access-token': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
vendors: [
{
vendorId: '507f1f77bcf86cd799439012',
lineItemIds: ['507f1f77bcf86cd799439099', '507f1f77bcf86cd79943909a'],
adjustmentIds: ['507f1f77bcf86cd799439088']
},
{
vendorId: '507f1f77bcf86cd799439013',
lineItemIds: ['507f1f77bcf86cd7994390b1']
}
],
method: 'stripe',
notifyVendor: true,
payoutDate: '2026-03-02',
comment: 'March payouts'
})
};
fetch('https://production-api.puppetvendors.com/payouts/make-payment', 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://production-api.puppetvendors.com/payouts/make-payment",
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([
'vendors' => [
[
'vendorId' => '507f1f77bcf86cd799439012',
'lineItemIds' => [
'507f1f77bcf86cd799439099',
'507f1f77bcf86cd79943909a'
],
'adjustmentIds' => [
'507f1f77bcf86cd799439088'
]
],
[
'vendorId' => '507f1f77bcf86cd799439013',
'lineItemIds' => [
'507f1f77bcf86cd7994390b1'
]
]
],
'method' => 'stripe',
'notifyVendor' => true,
'payoutDate' => '2026-03-02',
'comment' => 'March payouts'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"x-access-token: <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://production-api.puppetvendors.com/payouts/make-payment"
payload := strings.NewReader("{\n \"vendors\": [\n {\n \"vendorId\": \"507f1f77bcf86cd799439012\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd799439099\",\n \"507f1f77bcf86cd79943909a\"\n ],\n \"adjustmentIds\": [\n \"507f1f77bcf86cd799439088\"\n ]\n },\n {\n \"vendorId\": \"507f1f77bcf86cd799439013\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd7994390b1\"\n ]\n }\n ],\n \"method\": \"stripe\",\n \"notifyVendor\": true,\n \"payoutDate\": \"2026-03-02\",\n \"comment\": \"March payouts\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("x-access-token", "<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://production-api.puppetvendors.com/payouts/make-payment")
.header("Idempotency-Key", "<idempotency-key>")
.header("x-access-token", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"vendors\": [\n {\n \"vendorId\": \"507f1f77bcf86cd799439012\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd799439099\",\n \"507f1f77bcf86cd79943909a\"\n ],\n \"adjustmentIds\": [\n \"507f1f77bcf86cd799439088\"\n ]\n },\n {\n \"vendorId\": \"507f1f77bcf86cd799439013\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd7994390b1\"\n ]\n }\n ],\n \"method\": \"stripe\",\n \"notifyVendor\": true,\n \"payoutDate\": \"2026-03-02\",\n \"comment\": \"March payouts\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://production-api.puppetvendors.com/payouts/make-payment")
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-access-token"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"vendors\": [\n {\n \"vendorId\": \"507f1f77bcf86cd799439012\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd799439099\",\n \"507f1f77bcf86cd79943909a\"\n ],\n \"adjustmentIds\": [\n \"507f1f77bcf86cd799439088\"\n ]\n },\n {\n \"vendorId\": \"507f1f77bcf86cd799439013\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd7994390b1\"\n ]\n }\n ],\n \"method\": \"stripe\",\n \"notifyVendor\": true,\n \"payoutDate\": \"2026-03-02\",\n \"comment\": \"March payouts\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"requestId": "<string>",
"status": "completed",
"replay": true,
"transactionId": "<string>",
"totalPayout": 123
}
}{
"success": true,
"data": {
"requestId": "<string>",
"transactionId": "<string>",
"status": "processing",
"dryRun": false,
"vendors": [
{
"vendorId": "<string>",
"vendorName": "<string>",
"totalAmount": 123,
"totalLineItemsCount": 123,
"issue": "<string>"
}
],
"totalPayout": 123
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}Pay out a selection of line items for one or more vendors (asynchronous)
Merchant scope only, requires the admin:payouts:make_payment
permission: an EXACT match, deliberately separate from
admin:payouts so keys issued before this feature (legacy default
set admin:users, admin:vendors, admin:payouts) cannot move money.
Multi-vendor. vendors holds one group per vendor (up to 50),
each with that vendor’s line items and adjustments; the run pays one
batch per vendor, all with the one method of the request (as the
merchant portal’s Make Payment page does). The whole request is
refused, and nothing is paid, when any vendor is not in this shop,
is hidden, is not ready for the method, or has an item that cannot
be paid.
Once accepted, the run is NOT all-or-nothing. Each vendor’s
batch is paid on its own: one can be refused by the gateway (or lose
an adjustment to a payout made in the merchant portal meanwhile)
while the others are paid, and the poll still reads status: completed. Check every entry of batches on the poll, and retry or
mark-paid the ones that did not go through (canRetry; POST
/payouts/batches//retry and /mark-paid, per batch).
Accepts a payout run and returns 202 immediately: the engine validates the selection (the same computation the dry-run performs), reserves an idempotent Action row, pre-generates the transactionId, and returns the accept-time totals while the real run executes detached. Poll GET /payouts/make-payment/ for the batches. A replayed Idempotency-Key returns the SAME requestId, never a second run.
Retry with the same Idempotency-Key. The key is the only duplicate protection: two requests with different keys are two payouts, even for identical line items. If a request times out or the connection drops, resend it with its original key (you get the stored answer, or a 409 while it is still running), or poll GET /payouts/make-payment/. Never generate a new key for a retry, and do not submit the same line items from two workers at once.
method is the READ-side vocabulary (stripe / paypal /
globalPayouts / manual, same enum as GET /payouts/methods); the
bridge maps it to legacy’s resolver keys (stripeConnected,
paypalConnected, globalPayoutConnected, other) before the engine
runs.
curl --request POST \
--url https://production-api.puppetvendors.com/payouts/make-payment \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'x-access-token: <api-key>' \
--data '
{
"vendors": [
{
"vendorId": "507f1f77bcf86cd799439012",
"lineItemIds": [
"507f1f77bcf86cd799439099",
"507f1f77bcf86cd79943909a"
],
"adjustmentIds": [
"507f1f77bcf86cd799439088"
]
},
{
"vendorId": "507f1f77bcf86cd799439013",
"lineItemIds": [
"507f1f77bcf86cd7994390b1"
]
}
],
"method": "stripe",
"notifyVendor": true,
"payoutDate": "2026-03-02",
"comment": "March payouts"
}
'import requests
url = "https://production-api.puppetvendors.com/payouts/make-payment"
payload = {
"vendors": [
{
"vendorId": "507f1f77bcf86cd799439012",
"lineItemIds": ["507f1f77bcf86cd799439099", "507f1f77bcf86cd79943909a"],
"adjustmentIds": ["507f1f77bcf86cd799439088"]
},
{
"vendorId": "507f1f77bcf86cd799439013",
"lineItemIds": ["507f1f77bcf86cd7994390b1"]
}
],
"method": "stripe",
"notifyVendor": True,
"payoutDate": "2026-03-02",
"comment": "March payouts"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"x-access-token": "<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-access-token': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
vendors: [
{
vendorId: '507f1f77bcf86cd799439012',
lineItemIds: ['507f1f77bcf86cd799439099', '507f1f77bcf86cd79943909a'],
adjustmentIds: ['507f1f77bcf86cd799439088']
},
{
vendorId: '507f1f77bcf86cd799439013',
lineItemIds: ['507f1f77bcf86cd7994390b1']
}
],
method: 'stripe',
notifyVendor: true,
payoutDate: '2026-03-02',
comment: 'March payouts'
})
};
fetch('https://production-api.puppetvendors.com/payouts/make-payment', 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://production-api.puppetvendors.com/payouts/make-payment",
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([
'vendors' => [
[
'vendorId' => '507f1f77bcf86cd799439012',
'lineItemIds' => [
'507f1f77bcf86cd799439099',
'507f1f77bcf86cd79943909a'
],
'adjustmentIds' => [
'507f1f77bcf86cd799439088'
]
],
[
'vendorId' => '507f1f77bcf86cd799439013',
'lineItemIds' => [
'507f1f77bcf86cd7994390b1'
]
]
],
'method' => 'stripe',
'notifyVendor' => true,
'payoutDate' => '2026-03-02',
'comment' => 'March payouts'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"x-access-token: <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://production-api.puppetvendors.com/payouts/make-payment"
payload := strings.NewReader("{\n \"vendors\": [\n {\n \"vendorId\": \"507f1f77bcf86cd799439012\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd799439099\",\n \"507f1f77bcf86cd79943909a\"\n ],\n \"adjustmentIds\": [\n \"507f1f77bcf86cd799439088\"\n ]\n },\n {\n \"vendorId\": \"507f1f77bcf86cd799439013\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd7994390b1\"\n ]\n }\n ],\n \"method\": \"stripe\",\n \"notifyVendor\": true,\n \"payoutDate\": \"2026-03-02\",\n \"comment\": \"March payouts\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("x-access-token", "<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://production-api.puppetvendors.com/payouts/make-payment")
.header("Idempotency-Key", "<idempotency-key>")
.header("x-access-token", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"vendors\": [\n {\n \"vendorId\": \"507f1f77bcf86cd799439012\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd799439099\",\n \"507f1f77bcf86cd79943909a\"\n ],\n \"adjustmentIds\": [\n \"507f1f77bcf86cd799439088\"\n ]\n },\n {\n \"vendorId\": \"507f1f77bcf86cd799439013\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd7994390b1\"\n ]\n }\n ],\n \"method\": \"stripe\",\n \"notifyVendor\": true,\n \"payoutDate\": \"2026-03-02\",\n \"comment\": \"March payouts\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://production-api.puppetvendors.com/payouts/make-payment")
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-access-token"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"vendors\": [\n {\n \"vendorId\": \"507f1f77bcf86cd799439012\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd799439099\",\n \"507f1f77bcf86cd79943909a\"\n ],\n \"adjustmentIds\": [\n \"507f1f77bcf86cd799439088\"\n ]\n },\n {\n \"vendorId\": \"507f1f77bcf86cd799439013\",\n \"lineItemIds\": [\n \"507f1f77bcf86cd7994390b1\"\n ]\n }\n ],\n \"method\": \"stripe\",\n \"notifyVendor\": true,\n \"payoutDate\": \"2026-03-02\",\n \"comment\": \"March payouts\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"requestId": "<string>",
"status": "completed",
"replay": true,
"transactionId": "<string>",
"totalPayout": 123
}
}{
"success": true,
"data": {
"requestId": "<string>",
"transactionId": "<string>",
"status": "processing",
"dryRun": false,
"vendors": [
{
"vendorId": "<string>",
"vendorName": "<string>",
"totalAmount": 123,
"totalLineItemsCount": 123,
"issue": "<string>"
}
],
"totalPayout": 123
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}{
"success": false,
"error": {
"message": "Resource not found",
"code": "NOT_FOUND",
"errorId": "err_1783365360839_j281w7b",
"details": {}
}
}Authorizations
JWT minted from a merchant API key (mk_live_…) by POST /authenticate. Send the token value directly, with no "Bearer" prefix. Tokens last 14 days and can be renewed at POST /refresh-token; revoking the key refuses the next request made with any token minted from it.
Headers
Caller-chosen dedupe key, unique per payout you intend to make. Retrying the same request with the same key returns the same requestId and never starts a second run; the engine deduplicates on it. The key is bound to its request body: the same key with a different body is refused with 422 IDEMPOTENCY_KEY_REUSED. A NEW key is a NEW payout: always retry a timed-out or failed-to-connect request with its original key, never a fresh one, or the same items can be paid twice.
8 - 128Body
The vendors to pay, one group each, paid as one batch per vendor. A vendorId may appear only once, and a line item or adjustment id under only one vendor (ids compare case-insensitively). Every vendor must belong to this shop and be ready for the method, or the whole request is refused and nothing is paid.
1 - 50 elementsShow child attributes
Show child attributes
READ-side method name, one for every vendor of the run; mapped to legacy resolver keys at the bridge. manual records a payment made outside the app and needs manualMethod
stripe, paypal, globalPayouts, manual How a manual payout was made, the same options as the merchant portal. Recorded as the run's payout method and shown in the vendor email. Required when method is manual, refused with any other method
bankTransfer, paypal, cash, other "bankTransfer"
Whether the run emails the vendor
Recorded as the payout date. Either an RFC 3339 date-time or a calendar date without a time (YYYY-MM-DD), recorded as that day in the merchant portal's MM/DD/YYYY. When omitted, defaults to today in the shop's timezone (as MM/DD/YYYY), as the merchant portal pre-fills it
"2026-03-02"
Free-text note recorded with the run
2000Was this page helpful?