Move money externally
curl --request POST \
--url https://api.getlemma.com/v0/ach-transfer \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"source_account_id": "<string>",
"destination_account_id": "<string>",
"amount": 123,
"description": "<string>"
}
'import requests
url = "https://api.getlemma.com/v0/ach-transfer"
payload = {
"source_account_id": "<string>",
"destination_account_id": "<string>",
"amount": 123,
"description": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
source_account_id: '<string>',
destination_account_id: '<string>',
amount: 123,
description: '<string>'
})
};
fetch('https://api.getlemma.com/v0/ach-transfer', 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.getlemma.com/v0/ach-transfer",
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([
'source_account_id' => '<string>',
'destination_account_id' => '<string>',
'amount' => 123,
'description' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-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.getlemma.com/v0/ach-transfer"
payload := strings.NewReader("{\n \"source_account_id\": \"<string>\",\n \"destination_account_id\": \"<string>\",\n \"amount\": 123,\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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.getlemma.com/v0/ach-transfer")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source_account_id\": \"<string>\",\n \"destination_account_id\": \"<string>\",\n \"amount\": 123,\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getlemma.com/v0/ach-transfer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_account_id\": \"<string>\",\n \"destination_account_id\": \"<string>\",\n \"amount\": 123,\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "ach_transfer_Lk7nQx4mVp9bRt3d",
"account_id": "account_Rv4nBt8xKw2pMh6s",
"external_account_id": "external_account_Bx5nTm8hKw3pVd7c",
"amount": 150000,
"status": "submitted",
"statement_descriptor": "Acme payroll",
"transaction_id": null,
"settled_at": null,
"submission": {
"submitted_at": "2026-03-15T14:30:00Z",
"expected_funds_settlement_at": "2026-03-17T14:30:00Z"
},
"return": null
}
Outbound ACH transfers
Move money externally
Send money to a saved external account.
POST
/
v0
/
ach-transfer
Move money externally
curl --request POST \
--url https://api.getlemma.com/v0/ach-transfer \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"source_account_id": "<string>",
"destination_account_id": "<string>",
"amount": 123,
"description": "<string>"
}
'import requests
url = "https://api.getlemma.com/v0/ach-transfer"
payload = {
"source_account_id": "<string>",
"destination_account_id": "<string>",
"amount": 123,
"description": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
source_account_id: '<string>',
destination_account_id: '<string>',
amount: 123,
description: '<string>'
})
};
fetch('https://api.getlemma.com/v0/ach-transfer', 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.getlemma.com/v0/ach-transfer",
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([
'source_account_id' => '<string>',
'destination_account_id' => '<string>',
'amount' => 123,
'description' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-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.getlemma.com/v0/ach-transfer"
payload := strings.NewReader("{\n \"source_account_id\": \"<string>\",\n \"destination_account_id\": \"<string>\",\n \"amount\": 123,\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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.getlemma.com/v0/ach-transfer")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source_account_id\": \"<string>\",\n \"destination_account_id\": \"<string>\",\n \"amount\": 123,\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getlemma.com/v0/ach-transfer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_account_id\": \"<string>\",\n \"destination_account_id\": \"<string>\",\n \"amount\": 123,\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "ach_transfer_Lk7nQx4mVp9bRt3d",
"account_id": "account_Rv4nBt8xKw2pMh6s",
"external_account_id": "external_account_Bx5nTm8hKw3pVd7c",
"amount": 150000,
"status": "submitted",
"statement_descriptor": "Acme payroll",
"transaction_id": null,
"settled_at": null,
"submission": {
"submitted_at": "2026-03-15T14:30:00Z",
"expected_funds_settlement_at": "2026-03-17T14:30:00Z"
},
"return": null
}
Creates a transfer from a Lemma account to a saved recipient — an external bank account registered in Lemma. External transfers are sent via ACH and typically settle within 1-2 business days.
Transfers over $100,000 are held for manual review by the Lemma team as a
security measure to protect your accounts in the event of a compromised API
key. Need higher limits? Contact us.
Headers
string
required
A key that lets you safely retry the request without sending the same ACH
transfer more than once. See Idempotency.
Request body
string
required
The ID of the Lemma account to send money from.
string
required
The ID of a saved recipient. You cannot
send money to an arbitrary bank account — it must be a pre-registered
recipient belonging to your entity.
integer
required
The amount to transfer in cents. Must be greater than zero.
string
A description for the transfer. Appears on the sender’s transaction history.
Response
Returns the created ACH transfer object.string
Unique identifier for the ACH transfer.
string
The Lemma account the transfer moves money from or to.
string | null
The external account on the other side of
the transfer.
integer
The transfer amount in cents. A positive amount indicates a credit transfer
pushing funds to the receiving account. A negative amount indicates a debit
transfer pulling funds from the receiving account (an ACH pull).
string
Current status of the ACH transfer.
Show possible values
Show possible values
-
pending— in flight. -
submitted— sent to the ACH network. When the Federal Reserve settles the transfer, the status stayssubmittedandsettled_atis populated. -
canceled— we canceled the transfer after holding it for manual review. -
rejected— the ACH network rejected the transfer. -
returned— the transfer was returned.
string
The statement descriptor shown to the counterparty.
string | null
The settled transaction, once the transfer posts.
object | null
object | null
{
"id": "ach_transfer_Lk7nQx4mVp9bRt3d",
"account_id": "account_Rv4nBt8xKw2pMh6s",
"external_account_id": "external_account_Bx5nTm8hKw3pVd7c",
"amount": 150000,
"status": "submitted",
"statement_descriptor": "Acme payroll",
"transaction_id": null,
"settled_at": null,
"submission": {
"submitted_at": "2026-03-15T14:30:00Z",
"expected_funds_settlement_at": "2026-03-17T14:30:00Z"
},
"return": null
}