> For the complete documentation index, see [llms.txt](https://docs.coda.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.coda.co/codapay/refund-a-payment.md).

# Refund a Payment

This guide provides a comprehensive overview of Codapay's Refund API. It describes how merchants can programmatically issue refunds, retrieve refund statuses, and handle refund notifications.

{% hint style="info" %}
Refund API requires special approval, and is only available to payments that are made via Codapay APIs. Please contact your Account Manager or our integration support team for approval.&#x20;
{% endhint %}

### Overview of Refund Scenarios

Codapay supports Refunds for Completed Payments. If the payment is incomplete or cancelled when refund is requested, it will return an error response.

### 1. Refund Integration Flow

#### Refund for Completed Payments

<figure><img src="/files/uO1BxJU5p1DFpClloqxe" alt=""><figcaption></figcaption></figure>

#### Refund for Cancelled Payments

<figure><img src="/files/LjgUiTnUCQhdaCC4tIx8" alt=""><figcaption></figcaption></figure>

### 2. Create Refund

#### Endpoint

```url
POST {domain}/airtime/api/restful/v2.0/Payment/createRefund.json
```

#### Sample Body

```json
{
  "refundRequest": {
    "apiKey": "<your_api_key>",
    "txnId": 1234567890,
    "country": "360",
    "projectId": 100,
    "customerEmail": "optional@example.com"
  }
}
```

#### Request Parameters

<table><thead><tr><th width="254.65625">Parameter</th><th width="134.22265625">Type</th><th width="118.0703125">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>refundRequest</td><td>Object</td><td>Yes</td><td>Valid JSON object</td></tr><tr><td>refundRequest.apiKey</td><td>String</td><td>Yes</td><td>API key provided by Coda</td></tr><tr><td>refundRequest.txnId</td><td>Numeric</td><td>Yes</td><td>The transaction ID to refund</td></tr><tr><td>refundRequest.country</td><td>String</td><td>No</td><td>ISO 3166 country code</td></tr><tr><td>refundRequest.projectId</td><td>Numeric</td><td>Yes</td><td>Unique project ID</td></tr><tr><td>refundRequest.customerEmail</td><td>String</td><td>No</td><td>Customer's email address</td></tr></tbody></table>

#### Sample Response

```json
{
  "refundResult": {
    "id": "rfl_sg195468b7c6c0000",
    "createdAt": "2023-03-08T15:30:00.000000000Z",
    "statusCode": "accepted",
    "type": "full",
    "txnId": 1234567890,
    "amountValue": 40000,
    "amountCurrency": "IDR"
  }
}
```

#### Response Fields

| Parameter                   | Type    | Description                                                                                                                                                                                                                                                      |
| --------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| refundResult                | Object  | JSON object                                                                                                                                                                                                                                                      |
| refundResult.id             | String  | Refund ID                                                                                                                                                                                                                                                        |
| refundResult.createdAt      | String  | <p>Timestamp (ISO 8601 format) </p><p></p><p>Possible formats:</p><p>YYYY-MM-DDThh:mm:ss.ssssssZ (up to microseconds)</p><p>YYYY-MM-DDThh:mm:ss.sssssssssZ (up to nanoseconds)</p>                                                                               |
| refundResult.statusCode     | String  | Status: accepted, succeeded, or failed                                                                                                                                                                                                                           |
| refundResult.finalizedAt    | String  | <p>Optional timestamp when refund is finalized </p><p></p><p>Possible formats:</p><p>YYYY-MM-DDThh:mm:ss.ssssssZ (up to microseconds)</p><p>YYYY-MM-DDThh:mm:ss.sssssssssZ (up to nanoseconds) </p><p>\*If null, this field will not be included in response</p> |
| refundResult.type           | String  | Type of refund, always "full"                                                                                                                                                                                                                                    |
| refundResult.txnId          | Numeric | Refunded transaction ID                                                                                                                                                                                                                                          |
| refundResult.amountValue    | Numeric | Amount refunded                                                                                                                                                                                                                                                  |
| refundResult.amountCurrency | String  | Currency of the refund                                                                                                                                                                                                                                           |

#### Sample Error Response

```json
{
  "refundResult": {
    "resultCode": 551
    "resultDesc": "Duplicate Refund Request"
  }
}
```

#### Error Response Fields

| Parameter               | Type    | Description              |
| ----------------------- | ------- | ------------------------ |
| refundResult            | Object  | JSON object              |
| refundResult.resultCode | Numeric | Error code               |
| refundResult.resultDesc | String  | Description of the error |

#### Error Codes

<table><thead><tr><th width="111.28125">Code</th><th>Description</th></tr></thead><tbody><tr><td>103</td><td>Invalid API Key, Merchant Not Found, or Invalid Email</td></tr><tr><td>206</td><td>Transaction Not Found, Invalid Transaction</td></tr><tr><td>551</td><td>Duplicate Refund Request</td></tr><tr><td>102</td><td>Internal Server Error</td></tr></tbody></table>

### 3. Retrieve Refund Status

#### Endpoint

```
POST {domain}/airtime/api/restful/v2.0/Payment/retrieveRefund.json
```

#### Sample Body

```json
{
  "retrieveRefundRequest": {
    "apiKey": "<your_api_key>",
    "country": "360",
    "projectId": 100,
    "refundId": "rfl_sg1955a7330200033"
  }
}
```

#### Request Parameters

<table><thead><tr><th width="254.65625">Parameter</th><th width="134.22265625">Type</th><th width="118.0703125">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>refundRequest</td><td>Object</td><td>Yes</td><td>Valid JSON object</td></tr><tr><td>refundRequest.apiKey</td><td>String</td><td>Yes</td><td>API key provided by Coda</td></tr><tr><td>refundRequest.country</td><td>String</td><td>No</td><td>ISO 3166 country code</td></tr><tr><td>refundRequest.projectId</td><td>Numeric</td><td>Yes</td><td>Unique project ID</td></tr><tr><td>refundRequest.refundId</td><td>String</td><td>Yes</td><td>The ID of the refund request to retrieve</td></tr></tbody></table>

#### Response

Same as the `refundResult` object in the `createRefund` response.

### 4. Refund Notification Callback

Codapay sends a webhook to the configured notification URL with the refund status.

#### Request from Codapay

{% code overflow="wrap" %}

```
GET {merchantCallbackUrl}?EventType=refund&Id=<refund_id>&CreatedAt=<ts>&StatusCode=accepted&FinalizedAt=<ts>&Type=full&TxnId=<txn_id>&AmountValue=<amount>&AmountCurrency=<currency>&OrderId=<orderId>&ResultCode=0&Checksum=<checksum>
```

{% endcode %}

#### Expected Response from webhook

```
ResultCode=0
```

#### Key Fields

| Field          | Type    | Description                                                                                                                                                                                                  |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| EventType      | String  | The type of event being sent. In this case it will be "refund"                                                                                                                                               |
| Id             | String  | Refund ID                                                                                                                                                                                                    |
| CreatedAt      | String  | <p>Timestamp of when the refund was created (ISO 8601 format).</p><p>Possible formats:</p><p>YYYY-MM-DDThh:mm:ss.ssssssZ (up to microseconds)</p><p>YYYY-MM-DDThh:mm:ss.sssssssssZ (up to nanoseconds)</p>   |
| StatusCode     | String  | Status: accepted, succeeded, or failed                                                                                                                                                                       |
| FinalizedAt    | String  | <p>Timestamp of when the refund was finalized (ISO 8601 format).</p><p>Possible formats:</p><p>YYYY-MM-DDThh:mm:ss.ssssssZ (up to microseconds)</p><p>YYYY-MM-DDThh:mm:ss.sssssssssZ (up to nanoseconds)</p> |
| Type           | String  | Type of refund, always "full"                                                                                                                                                                                |
| TxnId          | String  | Transaction ID of this refund object                                                                                                                                                                         |
| AmountValue    | Float   | Refunded amount                                                                                                                                                                                              |
| AmountCurrency | String  | Currency of the refund                                                                                                                                                                                       |
| OrderId        | String  | Unique order identifier from merchant                                                                                                                                                                        |
| ResultCode     | Integer | <p>Indicates payment success (0 for success).</p><p>0: Success</p><p>431: Pending</p><p>216: Pending</p><p>481: Pending</p><p>Others: Failure</p>                                                            |
| Checksum       | String  | Checksum for validation                                                                                                                                                                                      |

#### Checksum Generation

```
MD5(eventType + apiKey + txnId + orderId + resultCode + statusCode)
```

### 5. Testing in Sandbox

#### Refunds

1. Complete a payment in [sandbox](https://coda-payments.gitbook.io/coda-private-technical-documentation/codapay/integration-guides/testing-guide/sandbox-testing-guide)
2. Use the transaction ID to request a refund
3. Verify refund status using the retrieveRefund endpoint
4. Notify Codapay support to simulate final status if needed

#### Example Requests

**Create Refund**

```sh
curl --location 'https://sandbox.codapayments.com/airtime/api/restful/v2.0/Payment/createRefund.json' \
--header 'Content-Type: application/json' \
--data-raw '{
  "refundRequest": {
    "country": "360",
    "apiKey": "<test_key>",
    "txnId": "740976157910166864",
    "projectId": 43
  }
}'
```

**Retrieve Refund**

```sh
curl --location 'https://sandbox.codapayments.com/airtime/api/restful/v2.0/Payment/retrieveRefund.json' \
--header 'Content-Type: application/json' \
--data '{
  "retrieveRefundRequest": {
    "country": "360",
    "apiKey": "<test_key>",
    "projectId": 43,
    "refundId": "rfl_sg1955a7330200033"
  }
}'
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.coda.co/codapay/refund-a-payment.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
