# İade Oluştur

> Ödenmiş veya fazla ödenmiş bir faturayı tam tutarda ya da fazla ödeme farkı kadar ilk onaylanan gönderici adresine iade edin.

`POST /v1/refunds`

:::endpoint
POST /v1/refunds
:::

**API anahtarı:** `Payment`

Son onaylanan yatırma işleminden itibaren 14 gün içinde `paid` veya `paid_over` durumundaki bir fatura için zincir üstü iade oluşturur. Hem hedef adres hem de iade tutarı sunucu tarafından otomatik hesaplanır: fonlar ilk onaylanan fatura yatırmasının gönderici adresine (`first_sender`) döner ve üye işyeri bakiyesinden `amount + fee` düşülür.

## İstek gövdesi

| Parametre | Tür | Zorunlu | Açıklama |
|-----------|-----|---------|----------|
| `invoice_id` | string | Evet | Anahtarın kapsamındaki bir projeye ait önekli fatura kimliği (`inv_...`) |
| `mode` | string | Evet | `"full"` (kalan iade edilebilir fatura bakiyesini döndürür) veya `"overpayment"` (yalnızca talep edilen fatura tutarını aşan fazlalığı döndürür) |
| `external_order_id` | string | Evet | Üye işyeri ve ortam başına benzersiz idempotency referansınız (en fazla 200 karakter) |

## Örnek istek

```json
{
  "invoice_id": "inv_7K2M9P4Q8R1X5Z3A0bC2dE",
  "mode": "full",
  "external_order_id": "refund-1042-full"
}
```

## Kod örnekleri

Her sekme bir Payment anahtarı (`pk_`) ile resmi SDK kullanır. İmzalama, serileştirme, güvenli yeniden denemeler ve tipli hatalar SDK tarafından yönetilir.

```curl
API_KEY_ID="pk_live_xxxxxxxxxxxx"
API_SECRET="sk_live_xxxxxxxxxxxx"
BODY='{"invoice_id":"inv_7K2M9P4Q8R1X5Z3A0bC2dE","mode":"full","external_order_id":"refund-1042-full"}'

TS=$(date +%s)
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | sed 's/^.* //')
SIGNATURE=$(printf '%s\n%s\n%s\n%s\n%s' "$TS" POST /v1/refunds '' "$BODY_HASH" \
  | openssl dgst -sha256 -hmac "$API_SECRET" -binary | base64)

curl -sS https://api.paymos.io/v1/refunds \
  -H "Authorization: HMAC-SHA256 $API_KEY_ID:$SIGNATURE" \
  -H "X-Request-Timestamp: $TS" \
  -H "Content-Type: application/json" \
  -d "$BODY"
```

```javascript
import { Paymos, externalOrderId } from '@paymos/sdk';

const paymos = new Paymos({
  apiKey: process.env.PAYMOS_API_KEY,
  apiSecret: process.env.PAYMOS_API_SECRET,
});
const refund = await paymos.refunds.create({
  invoiceId: 'inv_7K2M9P4Q8R1X5Z3A0bC2dE',
  mode: 'full',
  externalOrderId: externalOrderId('refund'),
});

console.log(refund.withdrawalId, refund.status);
```

```python
import os

from paymos import Paymos

paymos = Paymos(
    api_key=os.environ["PAYMOS_API_KEY"],
    api_secret=os.environ["PAYMOS_API_SECRET"],
)
refund = paymos.refunds.create(
    invoice_id="inv_7K2M9P4Q8R1X5Z3A0bC2dE",
    mode="full",
    external_order_id="refund-1042-full",
)

print(refund["withdrawal_id"], refund["status"])
```

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

$paymos = new Client(new ClientConfig(
    getenv('PAYMOS_API_KEY'),
    getenv('PAYMOS_API_SECRET')
));
$refund = $paymos->refunds()->create(array(
    'invoice_id' => 'inv_7K2M9P4Q8R1X5Z3A0bC2dE',
    'mode' => 'full',
    'external_order_id' => IdempotencyKey::externalOrderId('refund'),
));

echo $refund['withdrawal_id'] . ' ' . $refund['status'];
```

```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)
	}
	refund, err := client.Refunds.Create(context.Background(), paymos.CreateRefundParams{
		InvoiceID:       "inv_7K2M9P4Q8R1X5Z3A0bC2dE",
		Mode:            paymos.RefundModeFull,
		ExternalOrderID: "refund-1042-full",
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(refund.WithdrawalID, refund.Status)
}
```

```csharp
using Paymos;

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

var refund = await paymos.Refunds.CreateAsync(new CreateRefundRequest(
    InvoiceId: "inv_7K2M9P4Q8R1X5Z3A0bC2dE",
    Mode: RefundMode.Full,
    ExternalOrderId: "refund-1042-full"));

Console.WriteLine($"{refund.WithdrawalId} {refund.Status}");
```

```java
import io.paymos.CreateRefundRequest;
import io.paymos.PaymosClient;
import io.paymos.Refund;
import io.paymos.RefundMode;

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

Refund refund = paymos.refunds.create(new CreateRefundRequest(
    "inv_7K2M9P4Q8R1X5Z3A0bC2dE",
    RefundMode.FULL,
    "refund-1042-full"));

System.out.println(refund.withdrawalId() + " " + refund.status());
```

```ruby
require 'paymos'

paymos = Paymos::Client.new(
  api_key: ENV.fetch('PAYMOS_API_KEY'),
  api_secret: ENV.fetch('PAYMOS_API_SECRET')
)
refund = paymos.refunds.create(
  invoice_id: 'inv_7K2M9P4Q8R1X5Z3A0bC2dE',
  mode: 'full',
  external_order_id: 'refund-1042-full'
)

puts "#{refund.withdrawal_id} #{refund.status}"
```

```rust
use paymos::{CreateRefundRequest, PaymosClient, RefundMode};

let paymos = PaymosClient::new(
    std::env::var("PAYMOS_API_KEY")?,
    std::env::var("PAYMOS_API_SECRET")?,
)?;
let refund = paymos
    .refunds()
    .create(&CreateRefundRequest {
        invoice_id: "inv_7K2M9P4Q8R1X5Z3A0bC2dE".to_owned(),
        mode: RefundMode::Full,
        external_order_id: "refund-1042-full".to_owned(),
    })
    .await?;

println!("{} {}", refund.withdrawal_id, refund.status);
```

## Yanıt (201 Created / idempotent eşleşmede 200)

```json
{
  "withdrawal_id": "wdr_6Qm2fK8xR4vN7cT1bY9dL5",
  "invoice_id": "inv_7K2M9P4Q8R1X5Z3A0bC2dE",
  "mode": "full",
  "external_order_id": "refund-1042-full",
  "status": "created",
  "is_final": false,
  "is_test": false,
  "amount": "100.00",
  "fee": "1.00",
  "currency": "USDT",
  "network": "TRC20",
  "destination_address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
  "first_sender": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
  "created_at": 1767225600,
  "type": "refund",
  "project_id": "prj_3F9xL2mN8pQ4rT6vW1yZ5b"
}
```

## Yanıt alanları

| Alan | Tür | Açıklama |
|------|-----|----------|
| `withdrawal_id` | string | Bu iadeyi temsil eden önekli çekim kimliği (`wdr_...`) |
| `invoice_id` | string | İade edilen önekli fatura kimliği (`inv_...`) |
| `mode` | string | İade modu: `"full"` veya `"overpayment"` |
| `external_order_id` | string | Oluşturma isteğinden geri döndürülen idempotency referansınız |
| `status` | string | Güncel durum (`created`, `signed`, `pending_review`, `cancelling`, `completed`, `failed` veya `cancelled`) |
| `is_final` | boolean | İade uç bir duruma (`completed`, `failed`, `cancelled`) ulaştığında `true` |
| `is_test` | boolean | Sandbox iadeleri için `true` |
| `amount` | string | Ödeyiciye geri gönderilen tam token tutarı |
| `fee` | string? | `amount` tutarına ek olarak üye işyeri bakiyesinden düşülen sabit ağ çıkış ücreti. Sıfır olduğunda yer almaz |
| `currency` | string | Kripto varlık sembolü (faturanın ödeme para birimiyle aynıdır) |
| `network` | string | Blockchain ağ kodu (faturanın ödeme ağıyla aynıdır) |
| `destination_address` | string | Çıkış hedef adresi (her zaman `first_sender` ile aynıdır) |
| `first_sender` | string | Faturadaki ilk onaylanan yatırmanın kanonik gönderici adresi |
| `tx_hash` | string? | `status` değeri `completed` olduğunda zincir üstü işlem karması |
| `explorer_url` | string? | `status` değeri `completed` olduğunda `tx_hash` için blok gezgini bağlantısı |
| `created_at` | integer | Saniye cinsinden Unix zaman damgası |
| `completed_at` | integer? | İadenin tamamlandığı saniye cinsinden Unix zaman damgası |
| `failed_at` | integer? | İadenin başarısız olduğu saniye cinsinden Unix zaman damgası |
| `cancelled_at` | integer? | İadenin iptal edildiği saniye cinsinden Unix zaman damgası |
| `type` | string | Her zaman `"refund"` |
| `project_id` | string | Faturanın sahibi olan önekli proje kimliği (`prj_...`) |

## İdempotency

Her iade denemesi için deterministik bir `external_order_id` gönderin. `POST /v1/refunds` çağrısını aynı `(invoice_id, mode, external_order_id)` ile yeniden denemek, ikinci bir çıkış oluşturmak yerine mevcut iadeyi `200 OK` ile döndürür. Aynı `external_order_id` değerini farklı bir `invoice_id` veya `mode` ile kullanmak `409 idempotency_conflict` ile reddedilir.

Bir fatura için aynı anda yalnızca bir aktif iade işlemde olabilir. Önce `"overpayment"` iadesi başlatabilir, bu işlem `completed` durumuna ulaştıktan sonra kalan anapara için `"full"` iadesi oluşturabilirsiniz.

## Hatalar

| Kod | HTTP | Ne zaman |
|-----|------|----------|
| `payment_key_required` | 403 | İstek bir Payment (`pk_`) anahtarı yerine Payout (`rk_`) anahtarıyla imzalandı |
| `refunds_not_enabled` | 503 | Fatura iadeleri bu ortamda etkin değil |
| `invoice_not_found` | 404 | `invoice_id` mevcut değil veya API anahtarının proje kapsamı dışında |
| `refund_not_eligible` | 409 | Fatura `paid` veya `paid_over` durumunda değil ya da yatırmaları iadeye uygun değil |
| `refund_no_overpayment` | 409 | `mode` değeri `"overpayment"` ancak faturada iade edilebilir fazla ödeme bakiyesi yok |
| `refund_sender_unknown` | 409 | İlk onaylanan yatırmanın gönderici adresi mevcut değil |
| `refund_window_expired` | 409 | Faturanın son onaylanan yatırmasından bu yana 14 günden fazla süre geçti |
| `refund_network_unsupported` | 409 | Faturanın ödeme ağında çıkış işlemleri desteklenmiyor |
| `refund_in_flight` | 409 | Bu fatura için başka bir iade hâlâ uç olmayan bir durumda devam ediyor |
| `invoice_already_refunded` | 409 | Fatura zaten tamamen iade edildi |
| `refund_source_inconsistent` | 409 | Fatura yatırma veya iade geçmişi tutarlılık doğrulamasını geçemedi |
| `insufficient_balance` | 409 | Üye işyeri bakiyesi `amount + fee` tutarını karşılamaya yetmiyor |

Tam katalog için bkz. [Hata Kodları](/tr/docs/errors/codes.md).
