curl --request PATCH \
--url https://api.globalstack.io/v1/beneficiaries/{beneficiaryId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"label": "<string>",
"metadata": {},
"merchant_reference": "<string>",
"network": "<string>",
"rail": "payshap",
"provider_id": "<string>",
"account_number": "<string>",
"account_name": "<string>",
"address": "<string>"
}
'import requests
url = "https://api.globalstack.io/v1/beneficiaries/{beneficiaryId}"
payload = {
"name": "<string>",
"label": "<string>",
"metadata": {},
"merchant_reference": "<string>",
"network": "<string>",
"rail": "payshap",
"provider_id": "<string>",
"account_number": "<string>",
"account_name": "<string>",
"address": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
label: '<string>',
metadata: {},
merchant_reference: '<string>',
network: '<string>',
rail: 'payshap',
provider_id: '<string>',
account_number: '<string>',
account_name: '<string>',
address: '<string>'
})
};
fetch('https://api.globalstack.io/v1/beneficiaries/{beneficiaryId}', 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.globalstack.io/v1/beneficiaries/{beneficiaryId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'label' => '<string>',
'metadata' => [
],
'merchant_reference' => '<string>',
'network' => '<string>',
'rail' => 'payshap',
'provider_id' => '<string>',
'account_number' => '<string>',
'account_name' => '<string>',
'address' => '<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.globalstack.io/v1/beneficiaries/{beneficiaryId}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"label\": \"<string>\",\n \"metadata\": {},\n \"merchant_reference\": \"<string>\",\n \"network\": \"<string>\",\n \"rail\": \"payshap\",\n \"provider_id\": \"<string>\",\n \"account_number\": \"<string>\",\n \"account_name\": \"<string>\",\n \"address\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.globalstack.io/v1/beneficiaries/{beneficiaryId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"label\": \"<string>\",\n \"metadata\": {},\n \"merchant_reference\": \"<string>\",\n \"network\": \"<string>\",\n \"rail\": \"payshap\",\n \"provider_id\": \"<string>\",\n \"account_number\": \"<string>\",\n \"account_name\": \"<string>\",\n \"address\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.globalstack.io/v1/beneficiaries/{beneficiaryId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"label\": \"<string>\",\n \"metadata\": {},\n \"merchant_reference\": \"<string>\",\n \"network\": \"<string>\",\n \"rail\": \"payshap\",\n \"provider_id\": \"<string>\",\n \"account_number\": \"<string>\",\n \"account_name\": \"<string>\",\n \"address\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": true,
"message": "Beneficiary updated successfully",
"code": "ok",
"data": {
"id": "ben_01KPBAP7WTDKQKW5B3R31VPNX4",
"customer_id": "cust_01HXYZABC1234567890ABCDEFG",
"name": "Alice Bank Beneficiary",
"type": "fiat",
"currency": "NGN",
"details": {
"country_code": "NG",
"network": "bank",
"account_number": "0039415616",
"provider": {
"id": "prov_01KPBAP7WTDKQKW5B3R31VPNX4",
"name": "Access Bank",
"code": "000014"
},
"rail": "payshap",
"account_name": "ALICE JOHNSON"
},
"metadata": {},
"status": "pending",
"created_at": "2026-04-16T16:14:08.000Z",
"updated_at": "2026-04-16T16:14:08.000Z",
"label": "Alice's salary account",
"merchant_reference": "ref_01HXYZ4K5ABCDEFGHJKLMNPQRS"
},
"meta": {
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}Update a beneficiary
Partially updates an existing beneficiary. Returns the beneficiary in
the same shape as POST /v1/beneficiaries.
The path id is the GlobalStack external identifier (ben_…).
Mutable fields
name,label,metadata,merchant_reference- Fiat:
network,rail,account_number,account_name,provider_id - Crypto:
network,address
Immutable fields
type, customer_id, currency, country_code. Including any of
these in the request body fails validation with 400 bad_request.
To re-attach a beneficiary to a different customer or change its
currency/country/type, create a new beneficiary.
Semantics
metadatais replaced whole-cloth when present. No deep merge — the new map fully replaces the stored map.merchant_referenceis replace-only. Passingnullto clear it is rejected as400 bad_request.networkchange (fiat) requiresprovider_idto also be sent. The existing provider snapshot indetails.provideris not guaranteed to be valid for the new network, so GlobalStack re-calls FX EnginegetAccountProviderand refreshes the snapshot. Not required when the resulting delivery resolves its own provider (rail = "payshap"), which stores no provider at all.railis three-state: omitting it keeps the stored rail,nullclears it back to the corridor’s default, and a value sets it. A rail is never dropped as a side effect of another change.railchange requiresaccount_numberto also be sent, in either direction. The rail decides what that field means — a PayShap proxy (a mobile number or a ShapName) or a bank account number — so the stored value is not an address on the new rail. Clearing a PayShap rail additionally requiresprovider_id, since a PayShap beneficiary stores neither.provider_idchange (fiat, on its own or alongside a network change) triggers an FX Engine call to refreshdetails.provider. On a rail that resolves its own provider it is ignored, and a patch carrying onlyprovider_idis treated as no change.- All other validations from
POST /v1/beneficiariesapply to the merged state: currency must be offramp-supported indetails.country_code; the resultingnetworkmust be supported by the currency in that country; the resultingrailmust be valid for that network, currency and country; mobile-money beneficiaries require anaccount_name; crypto network must be supported by the currency.
Status preconditions
pending→ updated.active→ updated.archived→409 invalid_status.
Errors
400 bad_request— request body fails field-level validation, includes an immutable field, or sendsmerchant_reference: null.400 invalid_input— a cross-field rule is broken (e.g. fiatnetworkchange withoutprovider_id) or the merged state fails a currency/network check.404 not_found— id does not exist or belongs to a different integration.409 invalid_status— beneficiary is archived.409 duplicate_resource—merchant_referencecollides with another beneficiary in this integration.500 external_service_unavailable— FX Engine call failed.
Example — change account number
PATCH /v1/beneficiaries/ben_01KPBAP7WTDKQKW5B3R31VPNX4
{
"account_number": "0099887766"
}
Example — switch fiat network from bank to mobile_money
PATCH /v1/beneficiaries/ben_01KPBAP7WTDKQKW5B3R31VPNX4
{
"network": "mobile_money",
"provider_id": "prov_01KPBBNEWPR0V1DERZZZZZZZ4M",
"account_number": "+2348012345678",
"account_name": "Alice Johnson"
}
curl --request PATCH \
--url https://api.globalstack.io/v1/beneficiaries/{beneficiaryId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"label": "<string>",
"metadata": {},
"merchant_reference": "<string>",
"network": "<string>",
"rail": "payshap",
"provider_id": "<string>",
"account_number": "<string>",
"account_name": "<string>",
"address": "<string>"
}
'import requests
url = "https://api.globalstack.io/v1/beneficiaries/{beneficiaryId}"
payload = {
"name": "<string>",
"label": "<string>",
"metadata": {},
"merchant_reference": "<string>",
"network": "<string>",
"rail": "payshap",
"provider_id": "<string>",
"account_number": "<string>",
"account_name": "<string>",
"address": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
label: '<string>',
metadata: {},
merchant_reference: '<string>',
network: '<string>',
rail: 'payshap',
provider_id: '<string>',
account_number: '<string>',
account_name: '<string>',
address: '<string>'
})
};
fetch('https://api.globalstack.io/v1/beneficiaries/{beneficiaryId}', 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.globalstack.io/v1/beneficiaries/{beneficiaryId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'label' => '<string>',
'metadata' => [
],
'merchant_reference' => '<string>',
'network' => '<string>',
'rail' => 'payshap',
'provider_id' => '<string>',
'account_number' => '<string>',
'account_name' => '<string>',
'address' => '<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.globalstack.io/v1/beneficiaries/{beneficiaryId}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"label\": \"<string>\",\n \"metadata\": {},\n \"merchant_reference\": \"<string>\",\n \"network\": \"<string>\",\n \"rail\": \"payshap\",\n \"provider_id\": \"<string>\",\n \"account_number\": \"<string>\",\n \"account_name\": \"<string>\",\n \"address\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.globalstack.io/v1/beneficiaries/{beneficiaryId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"label\": \"<string>\",\n \"metadata\": {},\n \"merchant_reference\": \"<string>\",\n \"network\": \"<string>\",\n \"rail\": \"payshap\",\n \"provider_id\": \"<string>\",\n \"account_number\": \"<string>\",\n \"account_name\": \"<string>\",\n \"address\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.globalstack.io/v1/beneficiaries/{beneficiaryId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"label\": \"<string>\",\n \"metadata\": {},\n \"merchant_reference\": \"<string>\",\n \"network\": \"<string>\",\n \"rail\": \"payshap\",\n \"provider_id\": \"<string>\",\n \"account_number\": \"<string>\",\n \"account_name\": \"<string>\",\n \"address\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": true,
"message": "Beneficiary updated successfully",
"code": "ok",
"data": {
"id": "ben_01KPBAP7WTDKQKW5B3R31VPNX4",
"customer_id": "cust_01HXYZABC1234567890ABCDEFG",
"name": "Alice Bank Beneficiary",
"type": "fiat",
"currency": "NGN",
"details": {
"country_code": "NG",
"network": "bank",
"account_number": "0039415616",
"provider": {
"id": "prov_01KPBAP7WTDKQKW5B3R31VPNX4",
"name": "Access Bank",
"code": "000014"
},
"rail": "payshap",
"account_name": "ALICE JOHNSON"
},
"metadata": {},
"status": "pending",
"created_at": "2026-04-16T16:14:08.000Z",
"updated_at": "2026-04-16T16:14:08.000Z",
"label": "Alice's salary account",
"merchant_reference": "ref_01HXYZ4K5ABCDEFGHJKLMNPQRS"
},
"meta": {
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}{
"status": false,
"message": "Resource not found",
"code": "not_found",
"data": null,
"meta": {
"next_steps": {
"action": "Verify the resource identifier and retry.",
"docs_url": "https://docs.globalstack.io/errors#not_found"
},
"request_id": "req_01HXYZ4K5ABCDEFGHJKLMNPQRS",
"timestamp": "2026-05-14T15:43:55.732Z",
"version": "1"
}
}Authorizations
API key issued during merchant onboarding.
Path Parameters
[^\/#\?]+?Body
UpdateBeneficiaryDto
1 - 2551 - 1281281Set to 'payshap' to pay this bank beneficiary over PayShap, or null to clear the rail and return to the corridor's default. Omit to keep the stored rail. Changing the rail always requires account_number, because the rail decides what that field means — a PayShap proxy or a bank account number. Clearing a PayShap rail also requires provider_id, since a PayShap beneficiary stores neither.
payshap "payshap"
^prov_[0-9A-HJKMNP-TV-Z]{26}$1 - 642551 - 128Response
Beneficiary updated successfully