Record Payment
curl --request POST \
--url https://getbill.io/external-api/v1/debts/{id}/payments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"amount": 123,
"external_payment_id": "<string>",
"paid_at": "<string>",
"provider": "<string>",
"installment_id": "<string>"
}
'import requests
url = "https://getbill.io/external-api/v1/debts/{id}/payments"
payload = {
"amount": 123,
"external_payment_id": "<string>",
"paid_at": "<string>",
"provider": "<string>",
"installment_id": "<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({
amount: 123,
external_payment_id: '<string>',
paid_at: '<string>',
provider: '<string>',
installment_id: '<string>'
})
};
fetch('https://getbill.io/external-api/v1/debts/{id}/payments', 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://getbill.io/external-api/v1/debts/{id}/payments",
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([
'amount' => 123,
'external_payment_id' => '<string>',
'paid_at' => '<string>',
'provider' => '<string>',
'installment_id' => '<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://getbill.io/external-api/v1/debts/{id}/payments"
payload := strings.NewReader("{\n \"amount\": 123,\n \"external_payment_id\": \"<string>\",\n \"paid_at\": \"<string>\",\n \"provider\": \"<string>\",\n \"installment_id\": \"<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://getbill.io/external-api/v1/debts/{id}/payments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 123,\n \"external_payment_id\": \"<string>\",\n \"paid_at\": \"<string>\",\n \"provider\": \"<string>\",\n \"installment_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://getbill.io/external-api/v1/debts/{id}/payments")
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 \"amount\": 123,\n \"external_payment_id\": \"<string>\",\n \"paid_at\": \"<string>\",\n \"provider\": \"<string>\",\n \"installment_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data.debt_id": "<string>",
"data.id": "<string>",
"data.installment_id": "<string>",
"data.idempotent": true
}Debts API
Record Payment
Record an external payment or mark an installment as paid
POST
/
external-api
/
v1
/
debts
/
{id}
/
payments
Record Payment
curl --request POST \
--url https://getbill.io/external-api/v1/debts/{id}/payments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"amount": 123,
"external_payment_id": "<string>",
"paid_at": "<string>",
"provider": "<string>",
"installment_id": "<string>"
}
'import requests
url = "https://getbill.io/external-api/v1/debts/{id}/payments"
payload = {
"amount": 123,
"external_payment_id": "<string>",
"paid_at": "<string>",
"provider": "<string>",
"installment_id": "<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({
amount: 123,
external_payment_id: '<string>',
paid_at: '<string>',
provider: '<string>',
installment_id: '<string>'
})
};
fetch('https://getbill.io/external-api/v1/debts/{id}/payments', 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://getbill.io/external-api/v1/debts/{id}/payments",
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([
'amount' => 123,
'external_payment_id' => '<string>',
'paid_at' => '<string>',
'provider' => '<string>',
'installment_id' => '<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://getbill.io/external-api/v1/debts/{id}/payments"
payload := strings.NewReader("{\n \"amount\": 123,\n \"external_payment_id\": \"<string>\",\n \"paid_at\": \"<string>\",\n \"provider\": \"<string>\",\n \"installment_id\": \"<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://getbill.io/external-api/v1/debts/{id}/payments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 123,\n \"external_payment_id\": \"<string>\",\n \"paid_at\": \"<string>\",\n \"provider\": \"<string>\",\n \"installment_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://getbill.io/external-api/v1/debts/{id}/payments")
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 \"amount\": 123,\n \"external_payment_id\": \"<string>\",\n \"paid_at\": \"<string>\",\n \"provider\": \"<string>\",\n \"installment_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data.debt_id": "<string>",
"data.id": "<string>",
"data.installment_id": "<string>",
"data.idempotent": true
}Overview
Records a payment made outside GetBill. Use it for a dated pay-down on a debt, or includeinstallment_id to mark a specific payment-plan installment as paid.
This endpoint is provider-agnostic: the payment can come from any external payment link provider, bank transfer, card processor, or partner system. GetBill only requires your stable external_payment_id.
external_payment_id is required and used for idempotency on the debt. Re-sending the same ID with the same amount and same installment_id returns the existing payment instead of creating a duplicate. Reusing the same ID with a different amount or installment returns 409. Reusing the ID of a cancelled payment also returns 409; send a new external_payment_id for a new payment.
New payments cannot exceed the relevant remaining amount. Send the same external_payment_id again to safely replay a successful call.
Use Cancel Payment to fully cancel a payment that was sent by mistake.
Common workflows
Mark an installment as paid
Send theinstallment_id returned by Get Payment Plan. The payment amount must exactly match the installment amount; partial payments cannot be attached to an installment.
When the last outstanding installment settles the debt, GetBill automatically marks the debt as paid and closes the payment plan.
For a grouped plan, you may send the request through any debt ID in the group. GetBill records the installment on the shared plan debt and distributes its amount across group balances in deterministic FIFO order. The plan closes only when the complete group balance is paid.
Record a partial payment without a payment plan
Omitinstallment_id and send the amount received. GetBill deducts it from the debt’s remaining balance without creating a payment plan.
On a grouped debt, a payment without installment_id remains scoped to the debt ID in the URL; it is not distributed across the group.
Use a new external_payment_id for each distinct payment. Reuse the same ID only when retrying the same request.
Complete a payment plan
Record each installment payment with its correspondinginstallment_id. The final payment closes the plan automatically; no separate payment-plan deletion request is required.
Authentication
Requires a valid OAuth 2.0 access token with thedebts:write scope.
Request
string
required
Encrypted debt ID.
number
required
Payment amount. When
installment_id is provided, it must match the installment amount.string
required
Partner payment identifier used for idempotency.
string
Payment date/time in ISO 8601 format. Defaults to now.
string
Optional free-form partner/provider label, stored in payment metadata. Omit it when the provider is unknown.
string
Encrypted installment ID returned by the payment-plan endpoints.
Response
string
Encrypted debt that owns the payment. For a grouped installment, this is the shared
plan_debt_id and can differ from the debt ID used in the request URL.string
Opaque UUID of the recorded payment transaction.
string
Encrypted installment ID when the payment was attached to a specific installment, otherwise
null.boolean
true when the response is for an already-recorded external_payment_id.Example
curl -X POST "/external-api/v1/debts/debt_id/payments" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": 100,
"paid_at": "2026-08-05T12:00:00+00:00",
"provider": "partner",
"external_payment_id": "partner-payment-123",
"installment_id": "installment_id"
}'