# Payment refunds

This method initiates a **refund** of a successful payment (`link` channel). Pass the `order_id` of the original payment and a separate `user_data` for the refund operation. After the request is accepted, the API returns `refund_order_id` and status `REFUND_PENDING`; the final result arrives at the project `notify_url`.

Request format and signatures — [API request format](/en/pages/init-request).

## How it works

1. **Original payment** — a refund is available for `order_id` of a payment in success status (`SUCCESS`, code `3`). The ID comes from the [form](/en/pages/link/init-form) or [GATE](/en/pages/link/host2host) creation response.
2. **Initiation** — signed request to `init_refund` with a unique **refund** `user_data` (different from the payment `user_data`).
3. **Response** — `refund_order_id`, `status` `9` (`REFUND_PENDING`), and `status_description`.
4. **Final status** — POST JSON callback to `notify_url`; if needed, poll status by `refund_order_id` via [Payment status](/en/pages/link/status).


See [Transaction statuses](/en/pages/transaction-statuses) for `status` and `status_description` for refunds (`REFUND`, `REFUND_PENDING`).

## Technical details

|  |  |
|  --- | --- |
| **Endpoint** | `https://api.1payment.com/init_refund` |
| **Methods** | `GET`, `POST` |
| **Response format** | JSON |
| **Callback type** | `payment_type` — see [Payment types](/en/pages/payment-types) (`refund` in refund notifications) |


## Request parameters

### Required

| Parameter | Type | Description |
|  --- | --- | --- |
| `partner_id` | Integer | Your unique ID in the 1Payment system. |
| `project_id` | Integer | Your project identifier. |
| `order_id` | String | `order_id` of the **original successful** payment (`link` channel). |
| `user_data` | String | Unique **refund** ID on your side (different from payment `user_data`). Up to 255 characters; UUID recommended. |
| `sign` | String | Request signature (see the "Signature" section). |


### Optional

| Parameter | Type | Description |
|  --- | --- | --- |
| `amount` | Number | **Partial** refund amount. Confirm partial refund availability with your 1Payment manager. |


## Signature generation (`sign`)

Signature: MD5, lowercase (hex). General rules — [API request format](/en/pages/init-request#request-signature-sign).

**Formula:**


```text
MD5(init_refund + <параметры_без_sign_в_алфавитном_порядке_через_&> + <API_KEY>)
```

**Example string before hashing:**


```text
init_refundorder_id=8p3brmb19gfg0sg8gcwhws8kgc748s87&partner_id=1234&project_id=5678&user_data=abcd1234secret_key
```

For a partial refund, the passed `amount` is included in the signature.

### Signature verification in the documentation

## Request examples

Node.js

```javascript
const crypto = require('crypto');
const axios = require('axios');

async function initLinkRefund(apiKey, params) {
  const sortedKeys = Object.keys(params).sort();
  const queryString = sortedKeys.map((key) => `${key}=${params[key]}`).join('&');

  const baseString = `init_refund${queryString}${apiKey}`;
  params.sign = crypto.createHash('md5').update(baseString).digest('hex');

  const response = await axios.get('https://api.1payment.com/init_refund', { params });
  return response.data;
}

const apiKey = process.env.ONEPAYMENT_API_KEY;
const data = {
  partner_id: 1234,
  project_id: 5678,
  order_id: '8p3brmb19gfg0sg8gcwhws8kgc748s87',
  user_data: 'abcd1234',
};

initLinkRefund(apiKey, data).then(console.log);
```

Python

```python
import hashlib
import os
import requests

def init_link_refund(api_key: str, params: dict) -> dict:
    sorted_keys = sorted(params.keys())
    query_string = "&".join(f"{k}={params[k]}" for k in sorted_keys)

    base_string = f"init_refund{query_string}{api_key}"
    params["sign"] = hashlib.md5(base_string.encode("utf-8")).hexdigest()

    response = requests.get("https://api.1payment.com/init_refund", params=params)
    response.raise_for_status()
    return response.json()

api_key = os.environ["ONEPAYMENT_API_KEY"]
data = {
    "partner_id": 1234,
    "project_id": 5678,
    "order_id": "8p3brmb19gfg0sg8gcwhws8kgc748s87",
    "user_data": "abcd1234",
}

print(init_link_refund(api_key, data))
```

cURL

```bash
# sign = md5("init_refund" + order_id=...&partner_id=1234&project_id=5678&user_data=abcd1234 + API_KEY)
curl -sS "https://api.1payment.com/init_refund?partner_id=1234&project_id=5678&order_id=8p3brmb19gfg0sg8gcwhws8kgc748s87&user_data=abcd1234&sign=PASTE_MD5_HEX"
```

## API response

Successful response (`200`):


```json
{
  "refund_order_id": "crf_1p3brmb19gfg0sg8gcwhws8kgc748s87",
  "status": 9,
  "status_description": "REFUND_PENDING",
  "status_code": 0
}
```

| Field | Description |
|  --- | --- |
| `refund_order_id` | Refund ID in 1Payment; use for status polling and accounting. |
| `status` | Numeric code (`9` — refund in progress). |
| `status_description` | `REFUND_PENDING`, etc. |
| `status_code` | Decline code on refund error (see [decline codes](/en/pages/decline-error-codes)). |


Request error (`400`):


```json
{
  "error_code": 2
}
```

## Status notifications (callbacks)

After the refund status changes, the server sends **POST** JSON to the project `notify_url`.

| Parameter | Type | Req. | Description |
|  --- | --- | --- | --- |
| `payment_type` | String | Yes | Operation type (see [Payment types](/en/pages/payment-types)). |
| `order_id` | String | Yes | **Refund** identifier in 1Payment. |
| `project_id` | Integer | Yes | Your project ID. |
| `status` | Integer | Yes | Refund state (`5` — `REFUND`, `9` — `REFUND_PENDING`, etc.). |
| `status_description` | String | Yes | `REFUND`, `REFUND_PENDING`, `FAILURE`, etc. |
| `init_time` | String | Yes | Refund creation time. |
| `status_time` | String | Yes | Status received time. |
| `merchant_price` | Number | Yes | Original payment amount for the payer. |
| `init_price` | Number | No | Amount at initiation. |
| `user_price` | Number | Yes | Refund debit amount. |
| `user_data` | String | Yes | Refund ID passed in `init_refund`. |
| `original_order_id` | String | No | Original payment `order_id`. |
| `status_code` | String | No | Error code on decline. |
| `sign` | String | Yes | Callback signature. |


**Important:** your server must return **HTTP 200 OK**. Otherwise the system retries the callback **once per minute for 10 minutes**.

**Callback signature verification:** MD5 of all parameters in alphabetical order joined by `&` + `API_KEY` (**without** the `init_refund` prefix). See [API request format](/en/pages/init-request#callbacks-notifications).

## Related sections

- [Form payment creation](/en/pages/link/init-form)
- [Host-to-host payment creation (GATE)](/en/pages/link/host2host)
- [Payment status](/en/pages/link/status)
- [Transaction statuses](/en/pages/transaction-statuses)
- [Payment types](/en/pages/payment-types)
- [Error codes (API)](/en/pages/error-codes-api)
- [Decline error codes](/en/pages/decline-error-codes)