> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.crisscross.money/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.crisscross.money/_mcp/server.

# Search Payments by Merchant Reference

GET https://api.crisscross.money/v1/payment/search

Search for payments using a merchant reference. Returns matching transactions across
the specified merchant IDs. See the [Payment Status & Recovery guide](/collect/payment-recovery)
for using this endpoint to recover payment state after a timeout.

Semantics:
- Matching on `merchantReference` is **exact and case-sensitive** — no partial or prefix matching.
- Transactions in **any state** (pending, in-flight, terminal) are returned, and a transaction
  is searchable immediately after initiation — there is no consistency delay.
- **Only transactions are searched.** A checkout session against which no payment was ever
  initiated does not appear; only collections are returned (never payouts).
- `merchantReference` is unique per merchant for new sessions (duplicates are rejected
  with `409 DUPLICATE_REFERENCE` at session creation), but sessions created before
  uniqueness was enforced may share a reference — so the result is an array.
- At most 100 matching transactions are returned.
- The parent session is available on each result under `identifiers.sessionId`.


Reference: https://docs.crisscross.money/api-reference/collect/payments/manage-transactions/search-payments

## Request

### Query parameters

- `merchantIds` (string, required) — Comma-separated list of merchant IDs (UUIDs) to search within.
- `merchantReference` (string, required) — The merchant reference to search for.

## Response

### 200

Matching transactions returned successfully. The array is empty when no transaction carries the reference — including when a session was created but no payment was ever initiated against it.

- `list of TransactionFullStateResponse`

## Errors

### 401 Unauthorized Error

Unauthorized - Invalid or missing authentication.

- `message` (string, required) — Human-readable description of what went wrong.
- `error` (string, required) — Error category. Most endpoints return the HTTP reason phrase (e.g. "Bad Request", "Unauthorized", "Conflict", "Unprocessable Entity", "Internal Server Error"). Some return a machine-readable snake_case code instead — notably the FX and rate-lock rejections on checkout session creation and payment initiation, where several distinct codes share a single HTTP status. Where a code is present it is the finer discriminator and is safe to branch on.
- `statusCode` (integer, required) — HTTP status code, mirroring the response header. The response header is the source of truth.

### 422 Unprocessable Entity Error

Validation error - Invalid request parameters.

- `message` (string, required) — Human-readable description of what went wrong.
- `error` (string, required) — Error category. Most endpoints return the HTTP reason phrase (e.g. "Bad Request", "Unauthorized", "Conflict", "Unprocessable Entity", "Internal Server Error"). Some return a machine-readable snake_case code instead — notably the FX and rate-lock rejections on checkout session creation and payment initiation, where several distinct codes share a single HTTP status. Where a code is present it is the finer discriminator and is safe to branch on.
- `statusCode` (integer, required) — HTTP status code, mirroring the response header. The response header is the source of truth.

## Types

### TransactionFullStateResponse

Complete transaction state response with full details and history.

- `currentState` (string, required) — Current transaction state
- `previousStates` (list of string, required) — Array of previous transaction states
- `processor` (string, required) — Payment processor used for the transaction
- `merchantName` (string, required) — Merchant name
- `transactionId` (string, required) — Unique transaction identifier
- `amount` (double, required) — Transaction amount as a decimal in **major** units (e.g. `10` = 10.00 KES) — unlike session creation, which takes minor units.
- `transactionType` (string, required) — Transaction type
- `paymentMethodId` (string, required) — Payment method identifier
- `currency` (string, required) — Transaction currency
- `merchantReference` (string, required) — Merchant reference
- `transactionStates` (list of map from string to any, required) — Detailed transaction state history
- `paymentAttributes` (map from string to string, optional) — Payment-specific attributes and metadata
- `identifiers` (map from string to string, optional) — Additional transaction identifiers. For collections this includes `sessionId` — the checkout session the transaction belongs to — and `payerId`, the persistent [payer identifier](/payer-id).
- `paymentInstrument` (map from string to any, optional) — Payment instrument details when applicable.
- `processorReference` (string, optional) — Payment processor reference
- `financialTransactionReference` (string, optional) — Financial transaction reference from the processor
- `currentAttemptId` (string, optional) — Current attempt identifier
- `batchPayoutId` (string, optional) — Batch payout identifier, if the transaction is part of a batch payout
- `refundTransactionIds` (list of string, optional) — Transaction identifiers of all refunds processed against this transaction. Each entry can be passed to `GET /payment/{transactionId}` to retrieve full refund state. UUID v7.

## Examples

**Response**

```json
[
  {
    "currentState": "AUTH_REQUIRED",
    "previousStates": [
      "RECEIVED",
      "PENDING",
      "ROUTED",
      "AUTH_REQUIRED"
    ],
    "processor": "Example Processor",
    "merchantName": "Example Merchant",
    "transactionId": "01a02352-ac7b-799f-9bd0-79ba982c24f8",
    "amount": 10,
    "transactionType": "PAYMENT",
    "paymentMethodId": "mobilemoney",
    "currency": "KES",
    "merchantReference": "ORDER-2026-001",
    "transactionStates": [
      {
        "receivedState": {
          "state": "RECEIVED",
          "transitionedAt": "2026-08-21T07:56:55.812Z",
          "message": "Transaction queried successfully"
        }
      },
      {
        "authRequiredState": {
          "state": "AUTH_REQUIRED",
          "transitionedAt": "2026-08-21T07:56:57.688Z",
          "authMethodType": "pendingApproval"
        }
      }
    ],
    "paymentAttributes": {},
    "identifiers": {
      "sessionId": "01a02352-53b8-7000-82b3-380f374c7219",
      "payerId": "01994e10-78b0-7aa8-bf9a-80a9d571706c"
    },
    "currentAttemptId": "01a02352-b0a8-7bb0-8dbe-ff668232334c"
  }
]
```

**SDK Code**

```python Manage Transactions_searchPayments_example
import requests

url = "https://api.crisscross.money/v1/payment/search"

querystring = {"merchantIds":"merchantIds","merchantReference":"merchantReference"}

response = requests.get(url, params=querystring)

print(response.json())
```

```javascript Manage Transactions_searchPayments_example
const url = 'https://api.crisscross.money/v1/payment/search?merchantIds=merchantIds&merchantReference=merchantReference';
const options = {method: 'GET'};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Manage Transactions_searchPayments_example
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.crisscross.money/v1/payment/search?merchantIds=merchantIds&merchantReference=merchantReference"

	req, _ := http.NewRequest("GET", url, nil)

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Manage Transactions_searchPayments_example
require 'uri'
require 'net/http'

url = URI("https://api.crisscross.money/v1/payment/search?merchantIds=merchantIds&merchantReference=merchantReference")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
```

```java Manage Transactions_searchPayments_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.crisscross.money/v1/payment/search?merchantIds=merchantIds&merchantReference=merchantReference")
  .asString();
```

```php Manage Transactions_searchPayments_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.crisscross.money/v1/payment/search?merchantIds=merchantIds&merchantReference=merchantReference');

echo $response->getBody();
```

```csharp Manage Transactions_searchPayments_example
using RestSharp;

var client = new RestClient("https://api.crisscross.money/v1/payment/search?merchantIds=merchantIds&merchantReference=merchantReference");
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
```

```swift Manage Transactions_searchPayments_example
import Foundation

let request = NSMutableURLRequest(url: NSURL(string: "https://api.crisscross.money/v1/payment/search?merchantIds=merchantIds&merchantReference=merchantReference")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```