---
updatedAt: 2026-06-24T15:11:37.000Z
---

Fetch the complete documentation index at: https://docs.movmint.io/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Capture

Capture a quote with POST /fx/quote/capture/{quote_id} to lock the rate and execute the transaction. Covers the response, transaction status, delivery timing, and examples in Go, TypeScript, Java, Rust, and Python.

## Overview

Capturing a quote confirms your acceptance of its terms and executes the FX transaction at the locked rate. Call `POST /fx/quote/capture/{quote_id}` with the `quote_id` returned from [the quote](./quote.md).

```
POST https://api.sandbox.movmint.io/fx/quote/capture/{quote_id}
Authorization: Bearer <access_token>
x-idempotency-key: <uuid>
```

| Header              | Required | Description                                                                    |
| ------------------- | -------- | ------------------------------------------------------------------------------ |
| `Authorization`     | yes      | `Bearer <access_token>`.                                                       |
| `x-idempotency-key` | yes      | A UUID you generate. Reuse it on retries so the capture executes at most once. |

The capture endpoint takes **no request body** — the `quote_id` path parameter is the only input.

## Before you capture

* **Quotes expire.** Capture before the `valid_until` timestamp from the quote response. A late capture returns `410 Gone`; request a fresh quote.
* **Quotes are single-use.** A successfully captured quote cannot be captured again (`409`).
* **Capture executes the transaction.** Once captured, the conversion executes and funds move according to the source and target configurations from the quote.

## Code examples

### cURL

```bash
curl -X POST https://api.sandbox.movmint.io/fx/quote/capture/123e4567-e89b-12d3-a456-426614174000 \
  -H "Authorization: Bearer <access_token>" \
  -H "x-idempotency-key: $(uuidgen)"
```

### Go

```go
package main

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

	"github.com/google/uuid"
)

const baseURL = "https://api.sandbox.movmint.io"

func capture(token, quoteID string) (string, error) {
	req, err := http.NewRequest(
		http.MethodPost,
		fmt.Sprintf("%s/fx/quote/capture/%s", baseURL, quoteID),
		nil,
	)
	if err != nil {
		return "", err
	}
	req.Header.Set("Authorization", "Bearer "+token)
	req.Header.Set("x-idempotency-key", uuid.NewString())

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("capture failed (%d): %s", resp.StatusCode, body)
	}
	return string(body), nil
}

func main() {
	out, err := capture("<access_token>", "123e4567-e89b-12d3-a456-426614174000")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(out)
}
```

### TypeScript

```typescript
import { randomUUID } from "crypto";

const BASE_URL = "https://api.sandbox.movmint.io";

async function capture(token: string, quoteId: string) {
  const res = await fetch(`${BASE_URL}/fx/quote/capture/${quoteId}`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "x-idempotency-key": randomUUID(),
    },
  });

  if (!res.ok) {
    throw new Error(`Capture failed (${res.status}): ${await res.text()}`);
  }
  return res.json();
}

console.log(await capture("<access_token>", "123e4567-e89b-12d3-a456-426614174000"));
```

### Java

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;

public class Capture {

    private static final String BASE_URL = "https://api.sandbox.movmint.io";

    public static void main(String[] args) throws Exception {
        String token = "<access_token>";
        String quoteId = "123e4567-e89b-12d3-a456-426614174000";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + "/fx/quote/capture/" + quoteId))
                .header("Authorization", "Bearer " + token)
                .header("x-idempotency-key", UUID.randomUUID().toString())
                .POST(HttpRequest.BodyPublishers.noBody())
                .build();

        HttpResponse<String> response = client.send(
                request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new RuntimeException("Capture failed (" + response.statusCode()
                    + "): " + response.body());
        }
        System.out.println(response.body());
    }
}
```

### Rust

```rust
use uuid::Uuid;

const BASE_URL: &str = "https://api.sandbox.movmint.io";

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let token = "<access_token>";
    let quote_id = "123e4567-e89b-12d3-a456-426614174000";

    let client = reqwest::Client::new();
    let resp = client
        .post(format!("{BASE_URL}/fx/quote/capture/{quote_id}"))
        .bearer_auth(token)
        .header("x-idempotency-key", Uuid::new_v4().to_string())
        .send()
        .await?;

    if !resp.status().is_success() {
        let status = resp.status();
        return Err(format!("capture failed ({status}): {}", resp.text().await?).into());
    }

    let data: serde_json::Value = resp.json().await?;
    println!("{}", serde_json::to_string_pretty(&data)?);
    Ok(())
}
```

### Python

```python
import uuid
import requests

BASE_URL = "https://api.sandbox.movmint.io"


def capture(token: str, quote_id: str) -> dict:
    resp = requests.post(
        f"{BASE_URL}/fx/quote/capture/{quote_id}",
        headers={
            "Authorization": f"Bearer {token}",
            "x-idempotency-key": str(uuid.uuid4()),
        },
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json()


print(capture("<access_token>", "123e4567-e89b-12d3-a456-426614174000"))
```

## Example response (`200`)

```json
{
  "client_reference_id": "invoice-4821",
  "transaction_id": "50796632-715f-477c-991e-acd73bdc6144",
  "quote_id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "QUOTE_CAPTURED",
  "source_funding_instructions": {
    "source_type": "DLT_WALLET",
    "account_configuration": {
      "wallet_address": "0xabc987654321def",
      "network": "ethereum"
    }
  },
  "executed_amount": 998,
  "executed_at": "2026-06-24T12:04:55Z"
}
```

| Field                         | Description                                                                                                |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `client_reference_id`         | The reference you set in the quote's `tx_configuration`.                                                   |
| `transaction_id`              | Unique ID for the executed transaction. Use it for reconciliation and support.                             |
| `quote_id`                    | The captured quote.                                                                                        |
| `status`                      | The transaction status (see below).                                                                        |
| `source_funding_instructions` | Where to send source funds, when the source rail requires you to push funds (e.g., a DLT deposit address). |
| `executed_amount`             | Amount in the target currency.                                                                             |
| `executed_at`                 | When the transaction executed.                                                                             |

> 📘 **Acting on `source_funding_instructions`**
> For source rails where Movmint pulls funds (bank account, card, client balance), no further action is needed. For rails where you must push funds — notably `DLT_WALLET` — `source_funding_instructions` tells you the exact address and network to send the source asset to so settlement can complete.

## When can I expect funds to be delivered?

Delivery time depends primarily on the **target rail**, and settlement also depends on how quickly **source** funds arrive. The conversion itself is immediate; the surrounding rails determine wall-clock time.

| Target rail           | Typical delivery time           | Notes                                                                                                                                                           |
| --------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CLIENT_BALANCE`      | Immediate                       | Converted funds are credited to your [prefunded balance](../../Prefunded%20Accounts/prefunded-accounts/index.md) on the ledger at execution — no external rail. |
| `DLT_WALLET`          | Minutes                         | Bounded by network confirmation time for the target network.                                                                                                    |
| `CARD` (push-to-card) | Minutes to a few hours          | Depends on the card network and issuing bank.                                                                                                                   |
| `BANK_ACCOUNT`        | Same day to a few business days | ACH/FedNow timing and banking hours apply; FedNow is near-instant where supported, standard ACH is slower.                                                      |

Source-side timing matters too:

* **`CLIENT_BALANCE` source** — debited instantly at capture; no waiting on external funds.
* **`DLT_WALLET` source** — settlement waits for your deposit to the address in `source_funding_instructions` to confirm on-chain.
* **`BANK_ACCOUNT` / `CARD` source** — settlement follows the clearing time of the pull.

> 🚧 **Compliance screening can add time**
> Every transaction is screened for sanctions/risk. If a transaction is flagged, it is held for review before delivery completes. Complete, accurate [participant and address data](./quote.md#address-requirements) minimizes the chance of a hold.

### Transaction status

The `status` field reflects where the transaction is in its lifecycle. Immediately after capture you will typically see `QUOTE_CAPTURED`; it then progresses as funding and delivery complete. Common terminal and intermediate states:

* **`QUOTE_CAPTURED`** — capture accepted; the transaction has been initiated.
* **`PENDING`** — settlement in progress (e.g., awaiting source funds or rail clearing).
* **`COMPLETED`** — funds converted and delivered to the target.
* **`FAILED`** — the transaction could not complete. Contact support with the `transaction_id`.

## Error responses

| HTTP  | Cause                                                                         |
| ----- | ----------------------------------------------------------------------------- |
| `400` | Invalid request or malformed `quote_id`.                                      |
| `404` | No quote exists with the provided `quote_id`.                                 |
| `409` | The quote was already captured, or a capture workflow is already in progress. |
| `410` | The quote has expired — request a new one.                                    |
| `500` | Internal server error — retry with backoff.                                   |

## Putting it together

A typical integration:

1. **Quote** — `POST /fx/quote`; store `quote_id` and `valid_until`.
2. **Capture** — `POST /fx/quote/capture/{quote_id}` before expiry; store `transaction_id`.
3. **Settle the source side if needed** — if `source_funding_instructions` returns a DLT address, send the source asset there.
4. **Reconcile** — track the transaction to `COMPLETED` and match `transaction_id` against your records.