Capturing a Quote

To "capture" a quote is to confirm your acceptance of the quote parameters

Capturing a Quote

Once you have obtained a quote via POST /fx/quote, the next step is to capture it. Capturing a quote locks in the quoted rate and initiates the FX transaction. This is done by calling POST /fx/quote/capture/{quote_id} with the quote_id returned from the quote response.

Before You Capture

There are a few things to keep in mind before capturing a quote:

  • Quotes expire. Every quote response includes a valid_until timestamp. If you attempt to capture a quote after this time, the request will fail with an HTTP 400. You will need to request a new quote.
  • Quotes are single-use. Once a quote has been successfully captured, it cannot be captured again. Attempting to do so will return an HTTP 400.
  • Capture is irreversible. Once a quote is captured, the transaction is initiated and funds will begin moving according to the source and target configurations provided during the quote request.

Request

The capture endpoint requires no request body — the quote_id path parameter is the only input.

POST /fx/quote/capture/{quote_id}
Authorization: Bearer <your-token>

Code Examples

The following examples capture the quote obtained in the Getting Started guide using the quote_id from the quote response.

Go

package main

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

const baseURL = "https://sandbox.api.movmint.com/v1"

func main() {
	quoteID := "123e4567-e89b-12d3-a456-426614174000"

	req, err := http.NewRequest(
		http.MethodPost,
		fmt.Sprintf("%s/fx/quote/capture/%s", baseURL, quoteID),
		nil,
	)
	if err != nil {
		log.Fatalf("creating request: %v", err)
	}
	req.Header.Set("Authorization", "Bearer <your-token>")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalf("sending request: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("reading response: %v", err)
	}

	if resp.StatusCode != http.StatusOK {
		log.Fatalf("unexpected status %d: %s", resp.StatusCode, body)
	}

	fmt.Println(string(body))
}

TypeScript

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

async function captureQuote(quoteId: string): Promise<void> {
  const response = await fetch(`${BASE_URL}/fx/quote/capture/${quoteId}`, {
    method: "POST",
    headers: {
      Authorization: "Bearer <your-token>",
    },
  });

  if (!response.ok) {
    throw new Error(`Request failed with status ${response.status}`);
  }

  const data = await response.json();
  console.log(JSON.stringify(data, null, 2));
}

captureQuote("123e4567-e89b-12d3-a456-426614174000");

Java

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class CaptureExample {

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

    public static void main(String[] args) throws Exception {
        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 <your-token>")
                .POST(HttpRequest.BodyPublishers.noBody())
                .build();

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

        if (response.statusCode() != 200) {
            System.err.printf("Unexpected status %d: %s%n",
                    response.statusCode(), response.body());
            System.exit(1);
        }

        System.out.println(response.body());
    }
}

Rust

use reqwest::header::AUTHORIZATION;

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

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

    let client = reqwest::Client::new();
    let response = client
        .post(format!("{BASE_URL}/fx/quote/capture/{quote_id}"))
        .header(AUTHORIZATION, "Bearer <your-token>")
        .send()
        .await?;

    if !response.status().is_success() {
        let status = response.status();
        let text = response.text().await?;
        eprintln!("Unexpected status {status}: {text}");
        std::process::exit(1);
    }

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

    Ok(())
}

Example Response

A successful POST /fx/quote/capture/{quote_id} returns HTTP 200 with the transaction details:

{
  "client_reference_id": "my-first-quote",
  "transaction_id": "50796632-715f-477c-991e-acd73bdc6144",
  "quote_id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "COMPLETED",
  "source_funding_instructions": {
    "source_type": "DLT_WALLET",
    "account_configuration": {
      "wallet_address": "0xabc987654321def",
      "network": "ethereum"
    }
  },
  "executed_amount": 998,
  "executed_at": "2025-06-15T12:01:30Z"
}

Response Fields

FieldDescription
client_reference_idThe reference ID you provided in the original quote request's tx_configuration.
transaction_idA unique identifier for the executed FX transaction. Use this for support inquiries and reconciliation.
quote_idThe quote that was captured.
statusThe transaction status: PENDING, COMPLETED, or FAILED.
source_funding_instructionsThe target account or wallet where the participant must send source funds to complete settlement.
executed_amountThe amount received in the target currency.
executed_atTimestamp of when the transaction was executed.

Transaction Status

The status field indicates where the transaction is in its lifecycle:

  • PENDING — The transaction has been initiated but settlement is still in progress. This is common for bank-account-funded transactions where clearing takes time.
  • COMPLETED — Funds have been converted and delivered to the target configuration.
  • FAILED — The transaction could not be completed. Contact Movmint support with the transaction_id for details.

Error Responses

HTTP StatusCause
400The quote has expired, has already been captured, or the quote_id is malformed.
404No quote exists with the provided quote_id.
500An internal error occurred. Retry the request or contact Movmint support.

Putting It All Together

A typical integration follows this two-step flow:

  1. Request a quotePOST /fx/quote with your currency pair, amount, participants, and transaction configuration. Store the returned quote_id and valid_until.
  2. Capture the quotePOST /fx/quote/capture/{quote_id} before valid_until expires. Inspect the status and source_funding_instructions in the response to determine next steps.

For transactions that return a PENDING status, your system should poll or listen for status updates. Refer to the API Reference for details on transaction status retrieval.

Next Steps