Endpoints transfer saldo spend cap antar akun iklan. Dipindahkan secara atomik oleh TransferBalanceService (cek saldo riil → withdraw sumber → topup tujuan). Semua endpoint middleware: auth:api, myapi .
POST /api/transfer-balance — Eksekusi transfer baru
POST http://127.0.0.1:8081/api/transfer-balanceCopy URL
curl PowerShell JavaScript Node.js Python Go PHP Copy
curl --request POST \
--url http://127.0.0.1:8081/api/transfer-balance $ response = Invoke-WebRequest - Uri ' http://127.0.0.1:8081/api/transfer-balance ' - Method POST const url = ' http://127.0.0.1:8081/api/transfer-balance ' ;
const options = { method : ' POST ' };
try {
const response = await fetch ( url , options );
const data = await response . json ();
console . log ( data );
} catch ( error ) {
console . error ( error );
} const fetch = require ( ' node-fetch ' );
const url = ' http://127.0.0.1:8081/api/transfer-balance ' ;
const options = { method : ' POST ' };
try {
const response = await fetch ( url , options );
const data = await response . json ();
console . log ( data );
} catch ( error ) {
console . error ( error );
} import requests
url = " http://127.0.0.1:8081/api/transfer-balance "
response = requests . post ( url )
print ( response . json ()) package main
import (
" fmt "
" net/http "
" io "
)
func main () {
url := " http://127.0.0.1:8081/api/transfer-balance "
req , _ := http . NewRequest ( " POST " , url , nil )
res , _ := http . DefaultClient . Do ( req )
defer res . Body . Close ()
body , _ := io . ReadAll ( res . Body )
fmt . Println ( res )
fmt . Println ( string ( body ))
} <? php
$ curl = curl_init ();
curl_setopt_array ($ curl , [
CURLOPT_PORT => " 8081 " ,
CURLOPT_URL => " http://127.0.0.1:8081/api/transfer-balance " ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_ENCODING => "" ,
CURLOPT_MAXREDIRS => 10 ,
CURLOPT_TIMEOUT => 30 ,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1 ,
CURLOPT_CUSTOMREQUEST => " POST " ,
]);
$ response = curl_exec ($ curl );
$ err = curl_error ($ curl );
curl_close ($ curl );
if ($ err ) {
echo " cURL Error #: " . $ err ;
} else {
echo $ response ;
}
Buat & eksekusi transfer saldo (TransferBalanceController::store).
Request body
Field Wajib Tipe Keterangan order_id✅ UUID/UUID Reference ke order di web app source_account_ids✅ array List akun sumber (ads_account_id) amounts✅ array Nominal per sumber (urutan sama) destination_ads_account_id✅ string Akun tujuan
Contoh request
json Copy &# 123 ;
" order_id " : " 550e8400-e29b-41d4-a716-446655440000 " ,
" source_account_ids " : [ " act_A " , " act_B " ] ,
" amounts " : [ 50000 , 50000 ] ,
" destination_ads_account_id " : " act_TUJUAN "
&# 125 ;
Response sukses
json Copy &# 123 ;
" status " : true ,
" data " : &# 123 ;
" transfer_balance_id " : " UUID " ,
" status " : " pending "
&# 125 ;
&# 125 ;
Error
Status Kondisi 400 Validasi body gagal 409 Saldo sumber tidak cukup 404 Akun tidak ditemukan
GET /api/transfer-balance — Riwayat transfer
GET http://127.0.0.1:8081/api/transfer-balanceCopy URL
curl PowerShell JavaScript Node.js Python Go PHP Copy
curl --request GET \
--url http://127.0.0.1:8081/api/transfer-balance $ response = Invoke-WebRequest - Uri ' http://127.0.0.1:8081/api/transfer-balance ' - Method GET const url = ' http://127.0.0.1:8081/api/transfer-balance ' ;
const options = { method : ' GET ' };
try {
const response = await fetch ( url , options );
const data = await response . json ();
console . log ( data );
} catch ( error ) {
console . error ( error );
} const fetch = require ( ' node-fetch ' );
const url = ' http://127.0.0.1:8081/api/transfer-balance ' ;
const options = { method : ' GET ' };
try {
const response = await fetch ( url , options );
const data = await response . json ();
console . log ( data );
} catch ( error ) {
console . error ( error );
} import requests
url = " http://127.0.0.1:8081/api/transfer-balance "
response = requests . get ( url )
print ( response . json ()) package main
import (
" fmt "
" net/http "
" io "
)
func main () {
url := " http://127.0.0.1:8081/api/transfer-balance "
req , _ := http . NewRequest ( " GET " , url , nil )
res , _ := http . DefaultClient . Do ( req )
defer res . Body . Close ()
body , _ := io . ReadAll ( res . Body )
fmt . Println ( res )
fmt . Println ( string ( body ))
} <? php
$ curl = curl_init ();
curl_setopt_array ($ curl , [
CURLOPT_PORT => " 8081 " ,
CURLOPT_URL => " http://127.0.0.1:8081/api/transfer-balance " ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_ENCODING => "" ,
CURLOPT_MAXREDIRS => 10 ,
CURLOPT_TIMEOUT => 30 ,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1 ,
CURLOPT_CUSTOMREQUEST => " GET " ,
]);
$ response = curl_exec ($ curl );
$ err = curl_error ($ curl );
curl_close ($ curl );
if ($ err ) {
echo " cURL Error #: " . $ err ;
} else {
echo $ response ;
}
List riwayat transaksi transfer balance (TransferBalanceController::index).
Response
json Copy &# 123 ;
" status " : true ,
" data " : [
&# 123 ;
" id " : " UUID " ,
" destination_ads_account_id " : " act_TUJUAN " ,
" total_transferred " : 100000 ,
" status " : " completed " ,
" created_at " : " 2026-08-21T10:00:00+07:00 "
&# 125 ;
]
&# 125 ;
GET /api/transfer-balance/{id} — Detail transfer
GET http://127.0.0.1:8081/api/transfer-balance/:idCopy URL
curl PowerShell JavaScript Node.js Python Go PHP Copy
curl --request GET \
--url http://127.0.0.1:8081/api/transfer-balance/:id $ response = Invoke-WebRequest - Uri ' http://127.0.0.1:8081/api/transfer-balance/:id ' - Method GET const url = ' http://127.0.0.1:8081/api/transfer-balance/:id ' ;
const options = { method : ' GET ' };
try {
const response = await fetch ( url , options );
const data = await response . json ();
console . log ( data );
} catch ( error ) {
console . error ( error );
} const fetch = require ( ' node-fetch ' );
const url = ' http://127.0.0.1:8081/api/transfer-balance/:id ' ;
const options = { method : ' GET ' };
try {
const response = await fetch ( url , options );
const data = await response . json ();
console . log ( data );
} catch ( error ) {
console . error ( error );
} import requests
url = " http://127.0.0.1:8081/api/transfer-balance/:id "
response = requests . get ( url )
print ( response . json ()) package main
import (
" fmt "
" net/http "
" io "
)
func main () {
url := " http://127.0.0.1:8081/api/transfer-balance/:id "
req , _ := http . NewRequest ( " GET " , url , nil )
res , _ := http . DefaultClient . Do ( req )
defer res . Body . Close ()
body , _ := io . ReadAll ( res . Body )
fmt . Println ( res )
fmt . Println ( string ( body ))
} <? php
$ curl = curl_init ();
curl_setopt_array ($ curl , [
CURLOPT_PORT => " 8081 " ,
CURLOPT_URL => " http://127.0.0.1:8081/api/transfer-balance/:id " ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_ENCODING => "" ,
CURLOPT_MAXREDIRS => 10 ,
CURLOPT_TIMEOUT => 30 ,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1 ,
CURLOPT_CUSTOMREQUEST => " GET " ,
]);
$ response = curl_exec ($ curl );
$ err = curl_error ($ curl );
curl_close ($ curl );
if ($ err ) {
echo " cURL Error #: " . $ err ;
} else {
echo $ response ;
}
Detail satu transaksi transfer + item sumber (TransferBalanceController::show).
Param Wajib Tipe id✅ UUID/UUID
Response
json Copy &# 123 ;
" status " : true ,
" data " : &# 123 ;
" id " : " UUID " ,
" status " : " processing " ,
" destination_ads_account_id " : " act_TUJUAN " ,
" details " : [
&# 123 ; " source_ads_account_id " : " act_A " , " amount " : 50000 , " status " : " completed " &# 125 ; ,
&# 123 ; " source_ads_account_id " : " act_B " , " amount " : 50000 , " status " : " pending " &# 125 ;
]
&# 125 ;
&# 125 ;
POST /api/transfer-balance/{id}/process — Proses transfer
POST http://127.0.0.1:8081/api/transfer-balance/:id/processCopy URL
curl PowerShell JavaScript Node.js Python Go PHP Copy
curl --request POST \
--url http://127.0.0.1:8081/api/transfer-balance/:id/process $ response = Invoke-WebRequest - Uri ' http://127.0.0.1:8081/api/transfer-balance/:id/process ' - Method POST const url = ' http://127.0.0.1:8081/api/transfer-balance/:id/process ' ;
const options = { method : ' POST ' };
try {
const response = await fetch ( url , options );
const data = await response . json ();
console . log ( data );
} catch ( error ) {
console . error ( error );
} const fetch = require ( ' node-fetch ' );
const url = ' http://127.0.0.1:8081/api/transfer-balance/:id/process ' ;
const options = { method : ' POST ' };
try {
const response = await fetch ( url , options );
const data = await response . json ();
console . log ( data );
} catch ( error ) {
console . error ( error );
} import requests
url = " http://127.0.0.1:8081/api/transfer-balance/:id/process "
response = requests . post ( url )
print ( response . json ()) package main
import (
" fmt "
" net/http "
" io "
)
func main () {
url := " http://127.0.0.1:8081/api/transfer-balance/:id/process "
req , _ := http . NewRequest ( " POST " , url , nil )
res , _ := http . DefaultClient . Do ( req )
defer res . Body . Close ()
body , _ := io . ReadAll ( res . Body )
fmt . Println ( res )
fmt . Println ( string ( body ))
} <? php
$ curl = curl_init ();
curl_setopt_array ($ curl , [
CURLOPT_PORT => " 8081 " ,
CURLOPT_URL => " http://127.0.0.1:8081/api/transfer-balance/:id/process " ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_ENCODING => "" ,
CURLOPT_MAXREDIRS => 10 ,
CURLOPT_TIMEOUT => 30 ,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1 ,
CURLOPT_CUSTOMREQUEST => " POST " ,
]);
$ response = curl_exec ($ curl );
$ err = curl_error ($ curl );
curl_close ($ curl );
if ($ err ) {
echo " cURL Error #: " . $ err ;
} else {
echo $ response ;
}
Proses (eksekusi) transfer yang tersimpan. Berguna bila transfer dibuat sebagai draft lalu dieksekusi terpisah, atau retry untuk transfer failed.
Field Wajib Tipe id✅ UUID/UUID
Aksi
TransferBalanceService — validasi saldo riil sumber via Meta
Withdraw dari tiap sumber
Topup ke tujuan
Update status → completed / failed
Response sukses
json Copy &# 123 ;
" status " : true ,
" data " : &# 123 ;
" status " : " completed " ,
" total_transferred " : 100000
&# 125 ;
&# 125 ;
Status lifecycle transfer
text Copy [pending] ──process──► [processing] ──sukses──► [completed]
│
└──gagal──► [failed]
Status Arti pendingDibuat, belum dieksekusi processingSedang dieksekusi completedSelesai (total_transferred terisi) failedGagal (error_message terisi, rollback/perlu review)
Validasi saldo riil
Sebelum withdraw, TransferBalanceService memanggil GET /api/account/balance untuk akun sumber — memastikan saldo Meta sebenarnya mencukupi, bukan hanya saldo cache lokal.
Transfer multi-source Satu transfer bisa memindahkan dari multiple akun sumber ke satu tujuan. Masing-masing source diproses sebagai item di details. Bila salah satu gagal, keseluruhan transfer ditandai failed (items yang sukses tetap tercatat di api_response untuk audit).
Queue job
TransferBalanceJob (di API engine) menjalankan eksekusi secara async bila di-queue-kan. Pastikan queue worker aktif (php artisan local:start / queue:work).
Error umum
Pesan Kondisi Insufficient balanceSaldo riil sumber < nominal Destination account not foundAkun tujuan tidak dikenal Graph returned an error: (#17) User request limit reachedMeta rate limit
Ringkasan endpoint
Method Endpoint Fungsi POST /api/transfer-balanceEksekusi transfer baru GET /api/transfer-balanceRiwayat transfer GET /api/transfer-balance/{id}Detail transfer POST /api/transfer-balance/{id}/processProses transfer
Langkah berikutnya