curl --request POST \
--url https://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"amountCents": 2500,
"paidAt": "2026-08-30",
"externalReferenceId": "txn_8f3a2c"
}
'import requests
url = "https://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment"
payload = {
"amountCents": 2500,
"paidAt": "2026-08-30",
"externalReferenceId": "txn_8f3a2c"
}
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({amountCents: 2500, paidAt: '2026-08-30', externalReferenceId: 'txn_8f3a2c'})
};
fetch('https://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment', 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://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment",
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([
'amountCents' => 2500,
'paidAt' => '2026-08-30',
'externalReferenceId' => 'txn_8f3a2c'
]),
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://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment"
payload := strings.NewReader("{\n \"amountCents\": 2500,\n \"paidAt\": \"2026-08-30\",\n \"externalReferenceId\": \"txn_8f3a2c\"\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://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amountCents\": 2500,\n \"paidAt\": \"2026-08-30\",\n \"externalReferenceId\": \"txn_8f3a2c\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment")
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 \"amountCents\": 2500,\n \"paidAt\": \"2026-08-30\",\n \"externalReferenceId\": \"txn_8f3a2c\"\n}"
response = http.request(request)
puts response.read_body{
"externalPayment": {
"id": "cmr9zx1bq000gsf02h1d5w4t8",
"amountCents": 2500,
"paidAt": "2026-08-30",
"voided": false,
"externalReferenceId": "txn_8f3a2c",
"source": "MERCHANT",
"nickelBankingTransferId": null
},
"paymentLink": {
"id": "clkqzo2y1000cx9tfohoiodq1",
"requestedAmountCents": 12055,
"name": "INV-123",
"status": "ACTIVE",
"payments": [
{
"id": "<string>",
"status": "SUCCEEDED",
"fees": [
{
"type": "CREDIT_CARD_FEE",
"amountInCents": 290
}
],
"amountInCents": 10000,
"chargedAmountInCents": 10290,
"platformFeeInCents": 290,
"paymentLinkId": "<string>",
"paymentMethod": {
"id": "<string>",
"type": "ACH",
"achDetails": {
"bankName": "JP Morgan Chase",
"routingNumber": "<string>",
"accountNumberLastFour": "<string>"
},
"cardDetails": {
"brand": "visa",
"last4": "<string>",
"holderName": "<string>",
"expMonth": "2",
"expYear": "2030"
},
"nickelBalanceDetails": {
"nickname": "Operating",
"accountNumberLastFour": "6789",
"spendableCents": 125000
},
"billingDetails": {
"name": "<string>",
"companyName": "<string>",
"street": "<string>",
"city": "<string>",
"state": "<string>",
"zip": "<string>",
"email": "<string>"
}
},
"disbursement": {
"id": "<string>",
"status": "PENDING",
"amountInCents": 10000,
"bankName": "JP Morgan Chase",
"accountNumberLastFour": "<string>",
"paymentIds": [
"clkqzo2y1000cx9tfohoiodq1"
],
"createdAt": "2023-12-25",
"paidAt": "2023-12-25"
},
"refunds": [
{
"id": "<string>",
"amountCents": 515,
"refundDate": "2023-11-07T05:31:56Z",
"voided": true
}
],
"createdAt": 123,
"estimatedDisbursementDate": "<string>"
}
],
"externalPayments": [
{
"id": "cmr9zx1bq000gsf02h1d5w4t8",
"amountCents": 2500,
"paidAt": "2026-08-30",
"voided": false,
"externalReferenceId": "txn_8f3a2c",
"source": "MERCHANT",
"nickelBankingTransferId": null
}
],
"debitMemos": [
{
"id": "cmrb2k7w1000hsf02q8d9x3vn",
"amountCents": 3500,
"description": "Returned check fee",
"voided": false,
"createdAt": "2023-11-07T05:31:56Z",
"externalReferenceId": "DM-1042"
}
],
"debitMemoAmountCents": 0,
"url": "https://nickel.nickelpayments.com/pay/Ahndhz",
"completedAmountCents": 123,
"dueDate": "2023-12-25",
"customerId": "<string>",
"feePassthroughPercent": 100,
"creditCardEnabled": true,
"achEnabled": true,
"amountEditable": false,
"memo": "PO 4471, net 30"
}
}{
"error": "<string>",
"code": "<string>"
}{
"error": "The logged in user is not allowed to perform that action."
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}Record an external payment on a payment link
Records money that satisfied part or all of the payment link outside Nickel — a mailed check, cash, a direct bank transfer. No money moves through Nickel. The link’s completedAmountCents and status are re-derived from its Nickel payments plus its live external payment records: a partial amount leaves the link ACTIVE with the amount counted, and reminders continue for the remainder. For invoices synced from QuickBooks, Nickel records a matching QuickBooks payment for the recorded amount. Undo with the void endpoint. To reduce what is owed without recording money received (a discount or write-off), lower the link’s requestedAmountCents instead.
Pass externalReferenceId — your own transaction id for the money — to make the call safe to retry: a repeat with the same reference on the same link returns the existing record instead of creating another, and two concurrent posts of the same reference resolve to one record.
Don’t record a check you deposited into Nickel Banking. That money is already in your balance: apply the deposit to the invoice instead with Apply a check deposit to a payment link, and the application appears in the link’s externalPayments with nickelBankingTransferId set. Recording the same check here as well would count it twice.
curl --request POST \
--url https://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"amountCents": 2500,
"paidAt": "2026-08-30",
"externalReferenceId": "txn_8f3a2c"
}
'import requests
url = "https://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment"
payload = {
"amountCents": 2500,
"paidAt": "2026-08-30",
"externalReferenceId": "txn_8f3a2c"
}
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({amountCents: 2500, paidAt: '2026-08-30', externalReferenceId: 'txn_8f3a2c'})
};
fetch('https://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment', 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://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment",
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([
'amountCents' => 2500,
'paidAt' => '2026-08-30',
'externalReferenceId' => 'txn_8f3a2c'
]),
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://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment"
payload := strings.NewReader("{\n \"amountCents\": 2500,\n \"paidAt\": \"2026-08-30\",\n \"externalReferenceId\": \"txn_8f3a2c\"\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://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amountCents\": 2500,\n \"paidAt\": \"2026-08-30\",\n \"externalReferenceId\": \"txn_8f3a2c\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://rest.staging.nickel.com/paymentLink/{paymentLinkId}/externalPayment")
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 \"amountCents\": 2500,\n \"paidAt\": \"2026-08-30\",\n \"externalReferenceId\": \"txn_8f3a2c\"\n}"
response = http.request(request)
puts response.read_body{
"externalPayment": {
"id": "cmr9zx1bq000gsf02h1d5w4t8",
"amountCents": 2500,
"paidAt": "2026-08-30",
"voided": false,
"externalReferenceId": "txn_8f3a2c",
"source": "MERCHANT",
"nickelBankingTransferId": null
},
"paymentLink": {
"id": "clkqzo2y1000cx9tfohoiodq1",
"requestedAmountCents": 12055,
"name": "INV-123",
"status": "ACTIVE",
"payments": [
{
"id": "<string>",
"status": "SUCCEEDED",
"fees": [
{
"type": "CREDIT_CARD_FEE",
"amountInCents": 290
}
],
"amountInCents": 10000,
"chargedAmountInCents": 10290,
"platformFeeInCents": 290,
"paymentLinkId": "<string>",
"paymentMethod": {
"id": "<string>",
"type": "ACH",
"achDetails": {
"bankName": "JP Morgan Chase",
"routingNumber": "<string>",
"accountNumberLastFour": "<string>"
},
"cardDetails": {
"brand": "visa",
"last4": "<string>",
"holderName": "<string>",
"expMonth": "2",
"expYear": "2030"
},
"nickelBalanceDetails": {
"nickname": "Operating",
"accountNumberLastFour": "6789",
"spendableCents": 125000
},
"billingDetails": {
"name": "<string>",
"companyName": "<string>",
"street": "<string>",
"city": "<string>",
"state": "<string>",
"zip": "<string>",
"email": "<string>"
}
},
"disbursement": {
"id": "<string>",
"status": "PENDING",
"amountInCents": 10000,
"bankName": "JP Morgan Chase",
"accountNumberLastFour": "<string>",
"paymentIds": [
"clkqzo2y1000cx9tfohoiodq1"
],
"createdAt": "2023-12-25",
"paidAt": "2023-12-25"
},
"refunds": [
{
"id": "<string>",
"amountCents": 515,
"refundDate": "2023-11-07T05:31:56Z",
"voided": true
}
],
"createdAt": 123,
"estimatedDisbursementDate": "<string>"
}
],
"externalPayments": [
{
"id": "cmr9zx1bq000gsf02h1d5w4t8",
"amountCents": 2500,
"paidAt": "2026-08-30",
"voided": false,
"externalReferenceId": "txn_8f3a2c",
"source": "MERCHANT",
"nickelBankingTransferId": null
}
],
"debitMemos": [
{
"id": "cmrb2k7w1000hsf02q8d9x3vn",
"amountCents": 3500,
"description": "Returned check fee",
"voided": false,
"createdAt": "2023-11-07T05:31:56Z",
"externalReferenceId": "DM-1042"
}
],
"debitMemoAmountCents": 0,
"url": "https://nickel.nickelpayments.com/pay/Ahndhz",
"completedAmountCents": 123,
"dueDate": "2023-12-25",
"customerId": "<string>",
"feePassthroughPercent": 100,
"creditCardEnabled": true,
"achEnabled": true,
"amountEditable": false,
"memo": "PO 4471, net 30"
}
}{
"error": "<string>",
"code": "<string>"
}{
"error": "The logged in user is not allowed to perform that action."
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
ID of the payment link the payment was made against
Body
Amount received, in cents. Defaults to the link's full remaining balance. Cannot exceed the remaining balance.
x >= 12500
The date the money moved (YYYY-MM-DD). Defaults to today. Cannot be in the future.
"2026-08-30"
Your own transaction id for this money, used to make the request idempotent. Posting the same externalReferenceId on the same payment link again returns the existing record with 200 instead of creating a second one, as long as any amountCents and paidAt you pass agree with it; if they differ, the request is refused with 409 and code REFERENCE_CONFLICT. Voiding a record releases its reference. Unique per payment link, so the same id may be used against different links.
1 - 255"txn_8f3a2c"
