# Erstattungen auflisten

> Listen Sie Rechnungserstattungen mit Cursor-Paginierung auf und filtern Sie nach Rechnungs-ID, Status oder Erstellungszeitraum.

`GET /v1/refunds`

:::endpoint
GET /v1/refunds
:::

**API-Schlüssel:** `Payment`

Gibt Rechnungserstattungen für Projekte im Geltungsbereich des authentifizierten Payment-Schlüssels zurück, sortiert nach `created_at DESC` und anschließend `withdrawal_id DESC`. Reguläre Händlerauszahlungen über `POST /v1/withdrawals` sind in dieser Liste niemals enthalten.

## Abfrageparameter

| Parameter | Typ | Standard | Beschreibung |
|-----------|-----|----------|--------------|
| `limit` | integer | `20` | Seitengröße von 1 bis 100 |
| `cursor` | string | — | Opaker `next_cursor` aus der vorherigen Antwort |
| `invoice_id` | string | — | Filter nach Rechnungskennung mit Präfix (`inv_...`) |
| `status` | string | — | Exakter Status in snake_case (`created`, `signed`, `pending_review`, `cancelling`, `completed`, `failed`, `cancelled`). Parameter mehrfach angeben, um mehrere Status abzufragen |
| `created_from` | RFC 3339 | — | Inklusive Untergrenze für `created_at` mit Zeitzone (z. B. `2026-08-23T00:00:00Z`) |
| `created_to` | RFC 3339 | — | Exklusive Obergrenze für `created_at` mit Zeitzone. Muss nach `created_from` liegen |

Unbekannte Abfrageparameter, doppelte Statuswerte und ungültige Zeitstempel werden mit `400` abgewiesen.

## Codebeispiele

Jeder Tab verwendet das offizielle SDK der jeweiligen Sprache mit einem Payment-Schlüssel (`pk_`).

```curl
API_KEY_ID="pk_live_xxxxxxxxxxxx"
API_SECRET="sk_live_xxxxxxxxxxxx"
QUERY="?invoice_id=inv_7K2M9P4Q8R1X5Z3A0bC2dE&limit=20"

TS=$(date +%s)
# No body: the hash slot is the EMPTY STRING, not sha256("").
SIGNATURE=$(printf '%s\n%s\n%s\n%s\n%s' "$TS" GET /v1/refunds "$QUERY" '' \
  | openssl dgst -sha256 -hmac "$API_SECRET" -binary | base64)

curl -sS "https://api.paymos.io/v1/refunds$QUERY" \
  -H "Authorization: HMAC-SHA256 $API_KEY_ID:$SIGNATURE" \
  -H "X-Request-Timestamp: $TS"
```

```javascript
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.refunds.list({
  invoiceId: 'inv_7K2M9P4Q8R1X5Z3A0bC2dE',
  limit: 20,
});

for await (const refund of paymos.refunds.iterate({ status: ['completed'] }, 10)) {
  console.log(refund.withdrawalId);
}
```

```python
import os

from paymos import Paymos

paymos = Paymos(
    api_key=os.environ["PAYMOS_API_KEY"],
    api_secret=os.environ["PAYMOS_API_SECRET"],
)

page = paymos.refunds.list(invoice_id="inv_7K2M9P4Q8R1X5Z3A0bC2dE", limit=20)

for refund in paymos.refunds.iterate(10, status=["completed"]):
    print(refund["withdrawal_id"])
```

```php
<?php
use Paymos\Client;
use Paymos\ClientConfig;

$paymos = new Client(new ClientConfig(
    getenv('PAYMOS_API_KEY'),
    getenv('PAYMOS_API_SECRET')
));

$page = $paymos->refunds()->listPage(array(
    'invoice_id' => 'inv_7K2M9P4Q8R1X5Z3A0bC2dE',
    'limit' => 20,
));

foreach ($paymos->refunds()->iterate(array('status' => array('completed')), 10) as $refund) {
    echo $refund['withdrawal_id'] . PHP_EOL;
}
```

```go
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.Refunds.List(context.Background(), paymos.RefundListParams{
		InvoiceID: "inv_7K2M9P4Q8R1X5Z3A0bC2dE",
		Limit:     20,
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(len(page.Items), page.NextCursor)

	iter := paymos.NewRefundIterator(client.Refunds, paymos.RefundListParams{
		Status: []paymos.WithdrawalStatus{paymos.WithdrawalCompleted},
	}, 10)
	for {
		refund, ok, err := iter.Next(context.Background())
		if err != nil {
			panic(err)
		}
		if !ok {
			break
		}
		fmt.Println(refund.WithdrawalID)
	}
}
```

```csharp
using Paymos;

using var paymos = new PaymosClient(
    Environment.GetEnvironmentVariable("PAYMOS_API_KEY")!,
    Environment.GetEnvironmentVariable("PAYMOS_API_SECRET")!);

var page = await paymos.Refunds.ListAsync(new RefundListOptions(
    InvoiceId: "inv_7K2M9P4Q8R1X5Z3A0bC2dE",
    Limit: 20));

await foreach (var refund in paymos.Refunds.IterateAsync(
    new RefundListOptions(Status: [WithdrawalStatus.Completed]), maxPages: 10))
{
    Console.WriteLine(refund.WithdrawalId);
}
```

```java
import io.paymos.Page;
import io.paymos.PaymosClient;
import io.paymos.Refund;
import io.paymos.RefundListOptions;
import io.paymos.WithdrawalStatus;

import java.util.List;

PaymosClient paymos = new PaymosClient(
    System.getenv("PAYMOS_API_KEY"),
    System.getenv("PAYMOS_API_SECRET"));

Page<Refund> page = paymos.refunds.list(RefundListOptions.builder()
    .invoiceId("inv_7K2M9P4Q8R1X5Z3A0bC2dE")
    .limit(20)
    .build());

for (Refund refund : paymos.refunds.iterate(
        RefundListOptions.builder().status(List.of(WithdrawalStatus.COMPLETED)).build(), 10)) {
    System.out.println(refund.withdrawalId());
}
```

```ruby
require 'paymos'

paymos = Paymos::Client.new(
  api_key: ENV.fetch('PAYMOS_API_KEY'),
  api_secret: ENV.fetch('PAYMOS_API_SECRET')
)

page = paymos.refunds.list(invoice_id: 'inv_7K2M9P4Q8R1X5Z3A0bC2dE', limit: 20)

paymos.refunds.each(max_pages: 10, status: ['completed']) do |refund|
  puts refund.withdrawal_id
end
```

```rust
use paymos::{PaymosClient, RefundListParams, WithdrawalStatus};

let paymos = PaymosClient::new(
    std::env::var("PAYMOS_API_KEY")?,
    std::env::var("PAYMOS_API_SECRET")?,
)?;

let page = paymos
    .refunds()
    .list(&RefundListParams {
        invoice_id: Some("inv_7K2M9P4Q8R1X5Z3A0bC2dE".to_owned()),
        limit: Some(20),
        ..Default::default()
    })
    .await?;
println!("{} items, next_cursor={:?}", page.items.len(), page.next_cursor);

let mut pager = paymos.refunds().pager(
    RefundListParams { status: Some(vec![WithdrawalStatus::Completed]), ..Default::default() },
    Some(10),
)?;
while let Some(refund) = pager.next().await? {
    println!("{}", refund.withdrawal_id);
}
```

## Antwort (200 OK)

```json
{
  "items": [
    {
      "withdrawal_id": "wdr_6Qm2fK8xR4vN7cT1bY9dL5",
      "invoice_id": "inv_7K2M9P4Q8R1X5Z3A0bC2dE",
      "mode": "full",
      "external_order_id": "refund-1042-full",
      "status": "completed",
      "is_final": true,
      "is_test": false,
      "amount": "100.00",
      "fee": "1.00",
      "currency": "USDT",
      "network": "TRC20",
      "destination_address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
      "first_sender": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
      "tx_hash": "9f3b8c2a1d0e4f6789abc123def4567890abc123def4567890abc123def45678",
      "explorer_url": "https://tronscan.org/#/transaction/9f3b8c2a1d0e4f6789abc123def4567890abc123def4567890abc123def45678",
      "created_at": 1767225600,
      "completed_at": 1767225932,
      "type": "refund",
      "project_id": "prj_3F9xL2mN8pQ4rT6vW1yZ5b"
    }
  ],
  "next_cursor": null
}
```

Jedes Element in `items` enthält die vollständige Erstattungsressource, identisch zu [Erstattung abrufen](/de/docs/refunds/get.md).

## Paginierungsregeln

- Folgen Sie `next_cursor`, bis `null` zurückgegeben wird.
- Der Cursor ist an den Endpunkt `/v1/refunds` und die exakten Filterparameter (`invoice_id`, `status`, `created_from`, `created_to`) gebunden. Lassen Sie die Filter zwischen den Seiten unverändert; `limit` darf variieren.
- Cursors laufen 24 Stunden nach Ausstellung ab.
- Eine `invoice_id` außerhalb des Projektbereichs Ihres Schlüssels liefert eine leere Liste statt `404`.

## Fehler

Ein Payout-Schlüssel (`rk_`) wird mit `403 payment_key_required` abgewiesen. Ungültige Filterwerte liefern `400`, ein abgelaufener oder nicht passender Cursor liefert `400 pagination_cursor_invalid`. Siehe [Fehlercodes](/de/docs/errors/codes.md).
