Mark payment as paid
curl --request POST \
--url https://api-eu.flexportal.io/v1/payments/{paymentId}/mark-paid \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenant-ID: <tenant-id>' \
--data '
{
"paymentReference": "<string>",
"notes": "<string>"
}
'import requests
url = "https://api-eu.flexportal.io/v1/payments/{paymentId}/mark-paid"
payload = {
"paymentReference": "<string>",
"notes": "<string>"
}
headers = {
"Tenant-ID": "<tenant-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Tenant-ID': '<tenant-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({paymentReference: '<string>', notes: '<string>'})
};
fetch('https://api-eu.flexportal.io/v1/payments/{paymentId}/mark-paid', 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-eu.flexportal.io/v1/payments/{paymentId}/mark-paid",
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([
'paymentReference' => '<string>',
'notes' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Tenant-ID: <tenant-id>"
],
]);
$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-eu.flexportal.io/v1/payments/{paymentId}/mark-paid"
payload := strings.NewReader("{\n \"paymentReference\": \"<string>\",\n \"notes\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Tenant-ID", "<tenant-id>")
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-eu.flexportal.io/v1/payments/{paymentId}/mark-paid")
.header("Tenant-ID", "<tenant-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"paymentReference\": \"<string>\",\n \"notes\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-eu.flexportal.io/v1/payments/{paymentId}/mark-paid")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Tenant-ID"] = '<tenant-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"paymentReference\": \"<string>\",\n \"notes\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "<string>",
"payment": {
"paymentId": "<string>",
"tenantId": "<string>",
"customerId": "<string>",
"subtotal": 1,
"total": 1,
"currency": "<string>",
"paymentType": "individual",
"billingPeriod": "<string>",
"status": "pending",
"idempotencyKey": "<string>",
"dueDate": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"taxAmount": 0,
"taxRate": 0,
"amount": 1,
"rentalId": "<string>",
"billingGroupId": "<string>",
"provider": "stripe",
"transactionId": "<string>",
"providerResponse": {},
"manuallyMarked": false,
"paymentReference": "<string>",
"markedBy": "<string>",
"captureAttempts": 0,
"lastCaptureError": {
"code": "<string>",
"message": "<string>",
"declineCode": "<string>"
},
"lineItems": [
{
"rentalId": "<string>",
"description": "<string>",
"amount": 1,
"taxAmount": 0
}
],
"lateFeeApplied": false,
"lateFeeAmount": 1,
"originalAmount": 1,
"notes": "<string>",
"paidAt": "<string>",
"lastCaptureAttempt": "<string>",
"nextRetryAt": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}Payments
Mark Payment Paid
Manually marks a payment as paid. Use for offline payments (check, wire transfer, cash).
POST
/
v1
/
payments
/
{paymentId}
/
mark-paid
Mark payment as paid
curl --request POST \
--url https://api-eu.flexportal.io/v1/payments/{paymentId}/mark-paid \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenant-ID: <tenant-id>' \
--data '
{
"paymentReference": "<string>",
"notes": "<string>"
}
'import requests
url = "https://api-eu.flexportal.io/v1/payments/{paymentId}/mark-paid"
payload = {
"paymentReference": "<string>",
"notes": "<string>"
}
headers = {
"Tenant-ID": "<tenant-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Tenant-ID': '<tenant-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({paymentReference: '<string>', notes: '<string>'})
};
fetch('https://api-eu.flexportal.io/v1/payments/{paymentId}/mark-paid', 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-eu.flexportal.io/v1/payments/{paymentId}/mark-paid",
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([
'paymentReference' => '<string>',
'notes' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Tenant-ID: <tenant-id>"
],
]);
$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-eu.flexportal.io/v1/payments/{paymentId}/mark-paid"
payload := strings.NewReader("{\n \"paymentReference\": \"<string>\",\n \"notes\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Tenant-ID", "<tenant-id>")
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-eu.flexportal.io/v1/payments/{paymentId}/mark-paid")
.header("Tenant-ID", "<tenant-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"paymentReference\": \"<string>\",\n \"notes\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-eu.flexportal.io/v1/payments/{paymentId}/mark-paid")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Tenant-ID"] = '<tenant-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"paymentReference\": \"<string>\",\n \"notes\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "<string>",
"payment": {
"paymentId": "<string>",
"tenantId": "<string>",
"customerId": "<string>",
"subtotal": 1,
"total": 1,
"currency": "<string>",
"paymentType": "individual",
"billingPeriod": "<string>",
"status": "pending",
"idempotencyKey": "<string>",
"dueDate": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"taxAmount": 0,
"taxRate": 0,
"amount": 1,
"rentalId": "<string>",
"billingGroupId": "<string>",
"provider": "stripe",
"transactionId": "<string>",
"providerResponse": {},
"manuallyMarked": false,
"paymentReference": "<string>",
"markedBy": "<string>",
"captureAttempts": 0,
"lastCaptureError": {
"code": "<string>",
"message": "<string>",
"declineCode": "<string>"
},
"lineItems": [
{
"rentalId": "<string>",
"description": "<string>",
"amount": 1,
"taxAmount": 0
}
],
"lateFeeApplied": false,
"lateFeeAmount": 1,
"originalAmount": 1,
"notes": "<string>",
"paidAt": "<string>",
"lastCaptureAttempt": "<string>",
"nextRetryAt": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}Overview
Manually mark a payment as paid. Use this when payment was collected outside of automated billing (e.g., bank transfer, check, cash) or to reconcile payments manually.This endpoint is for manual reconciliation. Automated payments through integrated payment processors are marked paid automatically.
Common Use Cases
- Bank Transfers: Customer paid via wire transfer
- Checks: Payment received by check
- Cash: In-person cash payment
- External Systems: Payment collected through another system
- Reconciliation: Fix discrepancies between systems
Request Fields
| Field | Required | Description |
|---|---|---|
paidAt | No | When payment was received (default: now) |
notes | No | Notes about the payment |
reference | No | External reference (bank ref, check number) |
Example Request
{
"paidAt": "2025-01-15T10:30:00Z",
"reference": "WIRE-2025-001234",
"notes": "Received via bank transfer"
}
What Happens
When you mark a payment as paid:- Payment status changes to
paid - paidAt timestamp recorded
- Subscription cost recovery metrics updated
- Customer lifetime value updated
Example: Process Bank Transfer
async function recordBankTransfer(paymentId, bankReference, transferDate) {
return await markPaymentPaid(paymentId, {
paidAt: transferDate,
reference: bankReference,
notes: 'Manual reconciliation - bank transfer'
});
}
// Usage
await recordBankTransfer('pay_abc123', 'TRF-2025-001234', '2025-01-15T10:30:00Z');
Example: Bulk Reconciliation
async function reconcilePayments(reconciliationData) {
const results = { success: 0, errors: [] };
for (const item of reconciliationData) {
try {
await markPaymentPaid(item.paymentId, {
paidAt: item.paidDate,
reference: item.bankReference
});
results.success++;
} catch (error) {
results.errors.push({
paymentId: item.paymentId,
error: error.message
});
}
}
return results;
}
Error Handling
| Error Code | Cause | Solution |
|---|---|---|
NOT_FOUND | Payment doesn’t exist | Verify payment ID |
ALREADY_PAID | Payment already marked as paid | No action needed |
PAYMENT_CANCELLED | Cannot mark cancelled payment as paid | Payment is final |
Related Endpoints
- Get Payment - Check current status
- List Payments - Find payments to reconcile
- Cancel Payment - Cancel instead of paying
Authorizations
API key obtained from FlexPortal dashboard
Headers
Your tenant identifier
Path Parameters
The payment ID
Was this page helpful?