Payment history
Copy page
Retrieve payment history and manual balance adjustments for the active workspace.
GET /api/v1/user/payments · Permission: payments.read
Request
Section titled “Request”curl https://restlink23telecom.com/api/v1/user/payments \ -H "X-API-Key: $API_KEY"const res = await fetch('https://restlink23telecom.com/api/v1/user/payments', { method: 'GET', headers: { 'X-API-Key': process.env.API_KEY },});
if (!res.ok) { const err = await res.json(); throw new Error(`${err.error_code}: ${err.description}`);}const data = await res.json();console.log(data);import osimport requests
res = requests.get( "https://restlink23telecom.com/api/v1/user/payments", headers={"X-API-Key": os.environ["API_KEY"]},)res.raise_for_status()print(res.json())<?php$ch = curl_init('https://restlink23telecom.com/api/v1/user/payments');curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('API_KEY')],]);
$response = curl_exec($ch);$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);curl_close($ch);
if ($status !== 200) { throw new Exception("HTTP $status: $response");}$data = json_decode($response, true);print_r($data);require "net/http"require "json"
uri = URI("https://restlink23telecom.com/api/v1/user/payments")req = Net::HTTP::Get.new(uri)req["X-API-Key"] = ENV.fetch("API_KEY")
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }raise "HTTP #{res.code}: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
puts JSON.parse(res.body)import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://restlink23telecom.com/api/v1/user/payments")) .header("X-API-Key", System.getenv("API_KEY")) .GET() .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.body());package main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("GET", "https://restlink23telecom.com/api/v1/user/payments", nil) if err != nil { panic(err) } req.Header.Set("X-API-Key", os.Getenv("API_KEY"))
res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close()
data, _ := io.ReadAll(res.Body) fmt.Println(string(data))}using System.Text;
using var client = new HttpClient();client.DefaultRequestHeaders.Add("X-API-Key", Environment.GetEnvironmentVariable("API_KEY"));
var response = await client.GetAsync("https://restlink23telecom.com/api/v1/user/payments");
response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());Permissions
Section titled “Permissions”This endpoint requires payments.read. When a key lacks it, the response is 403 FORBIDDEN with required_permission set to payments.read; enable it in Portal → API Keys → Edit permissions. A key can be updated only by a user who holds that permission; otherwise ask the account owner to update or replace the key. An integration SMS key also receives 403 FORBIDDEN, without required_permission, because it can call only the integration send endpoint. A team member whose role hides Billing or lacks billing.read (in the portal, or through a key they created) receives 403 SECTION_ACCESS_DENIED with "section": "billing". Workspace errors for portal sessions are listed in Errors.
Response
Section titled “Response”{ "payments": [ { "id": "sms_gateway_S12345", "amount": 500, "currency": "EUR", "date": "2026-02-10T14:30:00Z", "type": "deposit", "method": "bank", "status": "settled", "ref_display": "Bank transfer", "description": "Bank transfer", "source": "sms_gateway" }, { "id": "crypto_h_42", "amount": 100, "currency": "EUR", "date": "2026-02-09T12:00:00Z", "type": "deposit", "method": "crypto", "status": "declined", "ref_display": "Crypto top-up", "reason": "Deposit could not be credited automatically. Please contact support.", "description": "Crypto top-up", "source": "crypto" }, { "id": "portal_P678", "amount": -20, "currency": "EUR", "date": "2026-02-08T09:00:00Z", "type": "adjustment", "method": "portal", "status": "settled", "ref_display": "Manual debit", "description": "Manual debit", "source": "portal" } ], "totals": { "deposits": 500, "withdrawals": 0, "adjustments": -20, "count": 2, "currency": "EUR" }}| Field | Meaning |
|---|---|
payments |
Newest first; [] when empty. |
totals |
Totals for settled rows in the account currency. |
sources_degraded |
Present only when a source failed; rows from listed sources may be incomplete. |
Fields
Section titled “Fields”| Field | Type | Meaning |
|---|---|---|
id |
string | Opaque payment ID. |
amount |
number | Signed: deposits positive, usage negative, adjustments either sign. |
currency |
string | Currency code. |
date |
string (RFC3339 date-time) | Payment date. |
type |
string | deposit, usage, or adjustment. |
method |
string | card, crypto, bank, or portal. |
status |
string | settled, in_progress, or declined. |
ref_display |
string | Same text as description; never a raw provider reference. |
reason |
string (optional) | Only on declined rows, when a reason is known. |
description |
string | Client-safe payment label. |
source |
string | sms_gateway, portal, stripe, or crypto. |
IDs are opaque. Prefixes are sms_gateway_S, portal_P, stripe_, crypto_, and crypto_h_.
Totals
Section titled “Totals”Totals include settled rows in the account currency only. count is the number of rows summed; withdrawals is a positive magnitude. An unknown currency gives "" and zero sums.
There is no pagination.
Setup in progress
Section titled “Setup in progress”During setup, HTTP 200 contains "error": "Account is in setup process" and "status": false.
Degraded state
Section titled “Degraded state”X-Sms-Gateway-Status is partial when rows exist and unavailable otherwise. See degraded balance for the reason header.
Money fields and labels are null for team-member portal sessions without balance.read; API keys are never redacted.
Temporary errors (503)
Section titled “Temporary errors (503)”Authentication and access checks run before balance, pricing and payments handlers. Their response body is:
{"status":false,"error_code":"API_KEY_VALIDATION_UNAVAILABLE","description":"An internal error occurred. Reference: req-3f9c2b7d1e0a4c5b6d7e8f90"}Quote the X-Request-ID header to support. Retry after a short pause; when Retry-After is present it is 1.
error_code |
Who can receive it | Retry-After |
Cause |
|---|---|---|---|
API_KEY_VALIDATION_UNAVAILABLE |
API keys | 1 |
The key could not be checked. |
AUTH_PROTECTION_UNAVAILABLE |
Unrecognised API keys | 1 |
Failed-attempt protection is unavailable. |
REPLAY_PROTECTION_UNAVAILABLE |
Signed API-key POST requests (here only POST /user/pricing); never GET |
1 |
Replay protection is unavailable. |
RATE_LIMIT_UNAVAILABLE |
API keys and portal sessions | — | The per-account rate limiter is unavailable. |
SECTION_ACCESS_UNAVAILABLE |
Team members (portal session or a key they created) | — | Section access could not be checked. |
WORKSPACE_ACCESS_UNAVAILABLE |
Portal sessions only; never API keys | 1 |
Workspace access could not be checked. |
Like balance and pricing, this endpoint can also return 429 RATE_LIMIT_EXCEEDED or 429 TOO_MANY_ATTEMPTS; see Balance errors.
