Auf dieser Seite
Feed abfragen
Bestätigte Kanaleinzahlungen in Veröffentlichungsreihenfolge abfragen, mit stets vorrückendem Cursor: keine abgeschlossene Zahlung geht verloren.
API-Schlüssel: Payment
Ein Feed für die Anbindung, keine Verlaufsseite. Er gibt ausschließlich bestätigte Einzahlungen zurück, älteste zuerst, in einer globalen Veröffentlichungsreihenfolge, und er liefert immer einen Cursor mit. Fragen Sie ihn regelmäßig ab, dann sehen Sie jede abgeschlossene Zahlung genau einmal, in einer Reihenfolge, die sich unter Ihnen nie ändert.
Webhooks sind der schnelle Weg, dieser Feed der verlässliche. Betreiben Sie beide: Webhooks liefern Sekunden, der Feed garantiert, dass Sie am Ende alles sehen — auch dann, wenn Ihr Endpunkt ausgefallen war.
Query-Parameter
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
limit |
Ganzzahl | 20 |
Seitengröße von 1 bis 100. |
cursor |
Zeichenkette | — | Undurchsichtiger Cursor aus dem next_cursor der vorherigen Seite. |
project_id |
Zeichenkette | — | Auf ein Projekt einschränken (prj_…). |
payment_channel_id |
Zeichenkette | — | Auf einen Kanal einschränken (pc_…). |
confirmed_from |
Unix-Sekunden | — | Nur Einzahlungen, die zu diesem Zeitpunkt oder später bestätigt wurden. Begrenzt allein die erste Abfrage — siehe unten. |
Einen Parameter status gibt es bewusst nicht. Wer confirming abfragen könnte, würde Geld als abgeschlossen behandeln, das eine Reorganisation noch wegnehmen kann.
Beispiel
GET /v1/payment-channel-deposits?limit=100&cursor=CfDJ8JvN… HTTP/1.1
Host: api.paymos.io
Authorization: HMAC-SHA256 pk_live_…:…
X-Request-Timestamp: 1767225660
Codebeispiele
Jeder Reiter nutzt das offizielle SDK der jeweiligen Sprache. Signatur, Serialisierung, sichere Wiederholungen und typisierte Fehler übernimmt das SDK.
API_KEY_ID="pk_live_xxxxxxxxxxxx"
API_SECRET="sk_live_xxxxxxxxxxxx"
QUERY="?limit=100"
TS=$(date +%s)
# No body: the hash slot is the EMPTY STRING, not sha256("") — its fixed
# e3b0c442… digest signs a different payload and the request is rejected. The
# query keeps its leading "?" exactly as transmitted.
SIGNATURE=$(printf '%s\n%s\n%s\n%s\n%s' "$TS" GET /v1/payment-channel-deposits "$QUERY" '' \
| openssl dgst -sha256 -hmac "$API_SECRET" -binary | base64)
curl -sS "https://api.paymos.io/v1/payment-channel-deposits$QUERY" \
-H "Authorization: HMAC-SHA256 $API_KEY_ID:$SIGNATURE" \
-H "X-Request-Timestamp: $TS"
import { Paymos } from '@paymos/sdk';
const paymos = new Paymos({
apiKey: process.env.PAYMOS_API_KEY,
apiSecret: process.env.PAYMOS_API_SECRET,
});
const page = await paymos.paymentChannelDeposits.read({ limit: 100 });
for (const deposit of page.items) {
console.log(deposit.id, deposit.net, deposit.currency);
}
console.log('resume from', page.nextCursor);
import os
from paymos import Paymos
paymos = Paymos(
api_key=os.environ["PAYMOS_API_KEY"],
api_secret=os.environ["PAYMOS_API_SECRET"],
)
page = paymos.payment_channel_deposits.read(limit=100)
for deposit in page["items"]:
print(deposit["id"], deposit["net"], deposit["currency"])
print("resume from", page["next_cursor"])
<?php
use Paymos\Client;
use Paymos\ClientConfig;
$paymos = new Client(new ClientConfig(
getenv('PAYMOS_API_KEY'),
getenv('PAYMOS_API_SECRET')
));
$page = $paymos->paymentChannelDeposits()->readPage(array('limit' => 100));
foreach ($page['items'] as $deposit) {
echo $deposit['id'] . ' ' . $deposit['net'] . ' ' . $deposit['currency'] . PHP_EOL;
}
echo 'resume from ' . $page['next_cursor'] . PHP_EOL;
package main
import (
"context"
"fmt"
"os"
paymos "github.com/Paymos-labs/go-sdk/v2"
)
func main() {
client, err := paymos.NewClient(os.Getenv("PAYMOS_API_KEY"), os.Getenv("PAYMOS_API_SECRET"))
if err != nil {
panic(err)
}
page, err := client.PaymentChannelDeposits.Read(context.Background(), paymos.PaymentChannelDepositFeedParams{
Limit: 100,
})
if err != nil {
panic(err)
}
for _, deposit := range page.Items {
fmt.Println(deposit.ID, deposit.Net, deposit.Currency)
}
fmt.Println("resume from", page.NextCursor)
}
using Paymos;
using var paymos = new PaymosClient(
Environment.GetEnvironmentVariable("PAYMOS_API_KEY")!,
Environment.GetEnvironmentVariable("PAYMOS_API_SECRET")!);
var page = await paymos.PaymentChannelDeposits.ReadAsync(
new PaymentChannelDepositFeedOptions(Limit: 100));
foreach (var deposit in page.Items)
{
Console.WriteLine($"{deposit.Id} {deposit.Net} {deposit.Currency}");
}
Console.WriteLine($"resume from {page.NextCursor}");
import io.paymos.PaymentChannelDeposit;
import io.paymos.PaymentChannelDepositFeedOptions;
import io.paymos.PaymentChannelDepositFeedPage;
import io.paymos.PaymosClient;
PaymosClient paymos = new PaymosClient(
System.getenv("PAYMOS_API_KEY"),
System.getenv("PAYMOS_API_SECRET"));
PaymentChannelDepositFeedPage page = paymos.paymentChannelDeposits.read(
PaymentChannelDepositFeedOptions.builder().limit(100).build());
for (PaymentChannelDeposit deposit : page.items()) {
System.out.println(deposit.id() + " " + deposit.net() + " " + deposit.currency());
}
System.out.println("resume from " + page.nextCursor());
require 'paymos'
paymos = Paymos::Client.new(
api_key: ENV.fetch('PAYMOS_API_KEY'),
api_secret: ENV.fetch('PAYMOS_API_SECRET')
)
page = paymos.payment_channel_deposits.read(limit: 100)
page.items.each do |deposit|
puts "#{deposit.id} #{deposit.net} #{deposit.currency}"
end
puts "resume from #{page.next_cursor}"
use paymos::{PaymentChannelDepositFeedParams, PaymosClient};
let paymos = PaymosClient::new(
std::env::var("PAYMOS_API_KEY")?,
std::env::var("PAYMOS_API_SECRET")?,
)?;
let page = paymos
.payment_channel_deposits()
.read(&PaymentChannelDepositFeedParams {
limit: Some(100),
..Default::default()
})
.await?;
for deposit in &page.items {
println!("{} {} {}", deposit.id, deposit.net, deposit.currency);
}
println!("resume from {}", page.next_cursor);
Antwort (200 OK)
{
"items": [
{
"id": "pcd_8ScRvL4jNq2XkB7mTfZdWu",
"payment_channel_id": "pc_2QhKZv6mRt9WdA3nYpLbXf",
"project_id": "prj_xFukZuAJZR06pLVBh3uwzv",
"payment_channel_external_id": "customer-42",
"status": "confirmed",
"is_final": true,
"is_test": false,
"currency": "USDT",
"network": "TRC20",
"chain_id": 728126428,
"contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"gross": "100",
"fee": "1",
"net": "99",
"applied_fee_percent": 1.0,
"customer_fee_percent": 0,
"tx_hash": "9f4c1b7e30ad52c8ef6a1d84b0c39f27a5e6d138f4b90c72ae51d63b8407fc25",
"transfer_id": "9f4c1b7e30ad52c8ef6a1d84b0c39f27a5e6d138f4b90c72ae51d63b8407fc25:41a614f803b6fd780986a42c78ec9c7f77e6ded13c:41c9f6a2b7d0138e54ca3b91f6072ed48a5c1e93b7:0",
"source_address": "TW9s4RkAqBnLpVdX2ChYzUeGm7QfKt3NbZ",
"destination_address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
"block_height": 68421905,
"first_included_block_timestamp": 1767225900,
"explorer_url": "https://tronscan.org/#/transaction/9f4c1b7e30ad52c8ef6a1d84b0c39f27a5e6d138f4b90c72ae51d63b8407fc25",
"created_at": 1767225870,
"updated_at": 1767225930,
"confirmed_at": 1767225930
},
{
"id": "pcd_5NmXqW7bHt3ZjR9kCvPyAe",
"payment_channel_id": "pc_2QhKZv6mRt9WdA3nYpLbXf",
"project_id": "prj_xFukZuAJZR06pLVBh3uwzv",
"payment_channel_external_id": "customer-42",
"status": "confirmed",
"is_final": true,
"is_test": false,
"currency": "USDC",
"network": "ERC20",
"chain_id": 1,
"contract_address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"gross": "42.5",
"fee": "0.425",
"net": "42.075",
"applied_fee_percent": 1.0,
"customer_fee_percent": 0,
"tx_hash": "0x1d7b64e2c05af398b2e714cd9a06f3518cb7e2409df6a1c8305b47ed12f9ca63",
"transfer_id": "0x1d7b64e2c05af398b2e714cd9a06f3518cb7e2409df6a1c8305b47ed12f9ca63:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48:0x9f2a6c1b4e8d7350ab11c9e5f0d2743b86ce41d9:0",
"source_address": "0x4b8e1f60d3a97c25be04f7183a5cd9027ef6b14a",
"destination_address": "0x9f2a6c1b4e8d7350ab11c9e5f0d2743b86ce41d9",
"block_height": 22984117,
"first_included_block_timestamp": 1767226020,
"explorer_url": "https://etherscan.io/tx/0x1d7b64e2c05af398b2e714cd9a06f3518cb7e2409df6a1c8305b47ed12f9ca63",
"created_at": 1767226020,
"updated_at": 1767226260,
"confirmed_at": 1767226260
}
],
"next_cursor": "CfDJ8JvN…"
}
So fragen Sie richtig ab
- 01Beginnen Sie ohne Cursor. Verarbeiten Sie die gesamte Seite.
- 02Speichern Sie
next_cursor, nachdem die Seite vollständig verarbeitet ist, nicht davor. - 03Senden Sie ihn bei der nächsten Abfrage zurück. Und so weiter.
Der Vertrag hinter diesen drei Schritten:
- —
next_cursorist nienull. Er steht in jeder Antwort, auch auf einer leeren Seite. Die Positionen sind global und nicht je Händler vergeben, deshalb muss auch ein Filter, der nichts trifft, über die übersprungenen Positionen hinausrücken — und deshalb durchsucht eine ruhende Anbindung nicht endlos denselben Bereich. - —Halten Sie bei einer leeren oder kurzen Seite an, nicht bei einem
null-Cursor. Rechnungen auflisten endet, sobaldnext_cursoraufnullsteht; dieser Feed endet nie so, und eine Schleife mit dieser Bedingung wird nie verlassen. Weniger Einträge alslimitheißt: Für Sie liegt gerade nichts mehr an. Speichern Sie den Cursor, verlassen Sie die Schleife und fragen Sie nach Ihrem Zeitplan erneut ab. - —
confirmed_frombegrenzt allein die erste Abfrage. Ab der zweiten entscheidet der gespeicherte Cursor, wo Sie fortsetzen. Senden Sie denselben Wert unverändert neben dem Cursor mit: Er gehört zu dem, woran der Cursor gebunden ist, und wird er weggelassen oder nach vorn geschoben, ist der Cursor ungültig. - —Die Reihenfolge ist monoton. Eine Einzahlung wird einmal an einer festen Position veröffentlicht, und eine spätere Bestätigung kann nie vor einer früheren auftauchen, die Sie bereits gelesen haben.
- —Das Vorrücken ist Ihre Entscheidung. Legen Sie einen älteren Cursor erneut vor, sehen Sie Einzahlungen unter Umständen ein zweites Mal. Das ist unbedenklich, solange Sie über
iddeduplizieren — diepcd_-Kennung bleibt über Webhook-Zustellung, Feed und jede Wiederholung hinweg dieselbe. - —Cursor laufen nach 24 Stunden ab — planen Sie den Abruf also mindestens einmal täglich ein. Ein Cursor ist die Stelle, an der Sie weiterlesen, kein Lesezeichen für nächste Woche: Wer länger schweigt, bekommt
400 pagination_cursor_invalidund beginnt neu, begrenzt durchconfirmed_from. - —Ein Cursor ist außerdem gebunden an Ihre Zugangsdaten, deren Umgebung, deren Projektumfang und die gesendeten Filter. Ändern Sie einen Filter oder erweitern Sie den Projektzugriff des Schlüssels, wird der alte Cursor ebenso abgewiesen. Beginnen Sie dann bei der ersten Seite: Die Deduplizierung über
pcd_macht eine vollständige Neusynchronisierung harmlos.
Wenn der Feed stehen bleibt
Lässt sich eine einzelne Einzahlung nicht darstellen, wird sie weder übersprungen noch bringt sie die Seite zu Fall. Der Feed liefert alles davor, hält next_cursor an dieser Position und nennt Ihnen, welche Einzahlung betroffen ist und warum:
{
"items": [],
"next_cursor": "CfDJ8JvN…",
"blocked": {
"deposit_id": "pcd_4KdQzT9rVn6WsB1mYhFxLg",
"reason": "booked_auth_missing"
}
}
blocked fehlt auf jeder normalen Seite. Steht es dort:
| Grund | Bedeutung |
|---|---|
booked_auth_missing |
Die Zahlung ist bestätigt, ihre Buchung ist aber noch nicht geschrieben. |
inconsistent |
Die Einzahlung, ihr Kanal und ihr Datensatz aus der Chain widersprechen einander. |
deposit_missing |
Der veröffentlichte Datensatz führt zu keiner Einzahlung mehr. |
channel_missing |
Der Kanal der Einzahlung ließ sich nicht laden. |
transfer_missing |
Der Einzahlung fehlt der verknüpfte Datensatz aus der Chain, aus dem sie ihre Belege zieht. |
not_confirmed |
Eine veröffentlichte Einzahlung steht nicht auf bestätigt; in diesen Feed kommt nur endgültiges Geld. |
Fragen Sie weiter ab. next_cursor bleibt bewusst unterhalb der blockierten Position, der Feed läuft also von selbst weiter, sobald der zugrunde liegende Datensatz repariert ist, und dazwischen geht nichts verloren. Jeder dieser Fälle ist eine Betriebsstörung auf Plattformseite — wenden Sie sich mit der deposit_id an den Support, wenn er bestehen bleibt.
Fehler
| Code | HTTP | Wann |
|---|---|---|
payment_channels_disabled |
503 | Zahlungskanäle sind für Ihr Konto in dieser Umgebung nicht freigeschaltet. |
payment_key_required |
403 | Die Anfrage wurde mit einem Payout-Schlüssel (rk_) signiert. |
pagination_cursor_invalid |
400 | Der Cursor ist fehlerhaft, abgelaufen oder an andere Filter oder einen anderen Geltungsbereich gebunden. |
field_invalid_format |
400 | project_id oder payment_channel_id ist keine gültige Kennung mit Präfix. |
field_out_of_range |
400 | limit liegt außerhalb von 1–100. |
query_parameter_unknown |
400 | Ein Parameter, der nicht in der Tabelle oben steht. |
Den vollständigen Katalog finden Sie unter Fehlercodes.