Welcome to Movmint

Movmint is the creator of the world's first Central Bank Digital Currency (CBDC), the Bahamian Sand Dollar. We are now using this technology along with a strong ecosystem to enable bespoke Foreign Exchange corridors for clients.


Getting Started

Obtain API Credentials

Access to the Movmint FX Services API requires a valid set of API credentials. To get started, contact the Movmint Business Development team:

During onboarding, Business Development will provision the following:

  • A Bearer Token (JWT) — used to authenticate every request to the API.
  • Access to the Sandbox and UAT environments for integration testing.
  • Documentation on participant and transaction configuration requirements specific to your use case.

Keep your bearer token confidential. Do not commit it to version control or expose it in client-side code. If you believe your token has been compromised, contact Business Development immediately to have it rotated.

Environments

Movmint provides three environments. Use Sandbox during early development, UAT for pre-production validation, and Production for live transactions.

EnvironmentBase URL
Sandboxhttps://sandbox.api.movmint.com/v1
UAThttps://uat.api.movmint.com/v1
Productionhttps://api.movmint.com/v1

All endpoints, request formats, and error codes behave identically across environments. Sandbox and UAT operate against test balances and do not settle real funds.

Authentication

Include your bearer token in the Authorization header of every request:

Authorization: Bearer <your-token>

Requests with a missing or invalid token will be rejected with an HTTP 401 Unauthorized response.

Your First API Call

The best way to verify that your credentials are working is to request an FX quote. The POST /fx/quote endpoint accepts a source currency, target currency, amount, and transaction configuration, then returns a quote with a quote_id you can later capture to execute the transaction.

The following examples request a quote to convert 1,000 BSD to USDC, funding from a bank account and settling to a DLT wallet.

Code Examples

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

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

func main() {
	body := map[string]any{
		"from_currency": "BSD",
		"to_currency":   "USDC",
		"amount":        1000,
		"participants": []map[string]any{
			{
				"participant_type":    "ORIGINATOR",
				"given_name":          "Jane",
				"sur_name":            "Doe",
				"address":             "123 Bay Street, Nassau, Bahamas",
				"national_identifier": "000-00-0000",
			},
			{
				"participant_type":    "BENEFICIARY",
				"given_name":          "Jane",
				"sur_name":            "Doe",
				"address":             "123 Bay Street, Nassau, Bahamas",
				"national_identifier": "000-00-0000",
			},
		},
		"tx_configuration": map[string]any{
			"client_reference_id": "my-first-quote",
			"source_configuration": map[string]any{
				"source_type": "BANK_ACCOUNT",
				"account_configuration": map[string]any{
					"account_number": "123456789",
					"routing_number": "987654321",
					"account_type":   "CHECKING",
				},
			},
			"target_configuration": map[string]any{
				"source_type": "DLT_WALLET",
				"account_configuration": map[string]any{
					"wallet_address": "0x123456789abcdef",
					"network":        "ethereum",
				},
			},
		},
	}

	payload, err := json.Marshal(body)
	if err != nil {
		log.Fatalf("marshalling request: %v", err)
	}

	req, err := http.NewRequest(http.MethodPost, baseURL+"/fx/quote", bytes.NewReader(payload))
	if err != nil {
		log.Fatalf("creating request: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")
	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()

	respBody, 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, respBody)
	}

	fmt.Println(string(respBody))
}
const BASE_URL = "https://sandbox.api.movmint.com/v1";

async function getQuote(): Promise<void> {
  const response = await fetch(`${BASE_URL}/fx/quote`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer <your-token>",
    },
    body: JSON.stringify({
      from_currency: "BSD",
      to_currency: "USDC",
      amount: 1000,
      participants: [
        {
          participant_type: "ORIGINATOR",
          given_name: "Jane",
          sur_name: "Doe",
          address: "123 Bay Street, Nassau, Bahamas",
          national_identifier: "000-00-0000",
        },
        {
          participant_type: "BENEFICIARY",
          given_name: "Jane",
          sur_name: "Doe",
          address: "123 Bay Street, Nassau, Bahamas",
          national_identifier: "000-00-0000",
        },
      ],
      tx_configuration: {
        client_reference_id: "my-first-quote",
        source_configuration: {
          source_type: "BANK_ACCOUNT",
          account_configuration: {
            account_number: "123456789",
            routing_number: "987654321",
            account_type: "CHECKING",
          },
        },
        target_configuration: {
          source_type: "DLT_WALLET",
          account_configuration: {
            wallet_address: "0x123456789abcdef",
            network: "ethereum",
          },
        },
      },
    }),
  });

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

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

getQuote();
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class QuoteExample {

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

    public static void main(String[] args) throws Exception {
        String payload = """
            {
              "from_currency": "BSD",
              "to_currency": "USDC",
              "amount": 1000,
              "participants": [
                {
                  "participant_type": "ORIGINATOR",
                  "given_name": "Jane",
                  "sur_name": "Doe",
                  "address": "123 Bay Street, Nassau, Bahamas",
                  "national_identifier": "000-00-0000"
                },
                {
                  "participant_type": "BENEFICIARY",
                  "given_name": "Jane",
                  "sur_name": "Doe",
                  "address": "123 Bay Street, Nassau, Bahamas",
                  "national_identifier": "000-00-0000"
                }
              ],
              "tx_configuration": {
                "client_reference_id": "my-first-quote",
                "source_configuration": {
                  "source_type": "BANK_ACCOUNT",
                  "account_configuration": {
                    "account_number": "123456789",
                    "routing_number": "987654321",
                    "account_type": "CHECKING"
                  }
                },
                "target_configuration": {
                  "source_type": "DLT_WALLET",
                  "account_configuration": {
                    "wallet_address": "0x123456789abcdef",
                    "network": "ethereum"
                  }
                }
              }
            }
            """;

        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + "/fx/quote"))
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer <your-token>")
                .POST(HttpRequest.BodyPublishers.ofString(payload))
                .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());
    }
}
use reqwest::header::{AUTHORIZATION, CONTENT_TYPE};
use serde_json::json;

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let body = json!({
        "from_currency": "BSD",
        "to_currency": "USDC",
        "amount": 1000,
        "participants": [
            {
                "participant_type": "ORIGINATOR",
                "given_name": "Jane",
                "sur_name": "Doe",
                "address": "123 Bay Street, Nassau, Bahamas",
                "national_identifier": "000-00-0000"
            },
            {
                "participant_type": "BENEFICIARY",
                "given_name": "Jane",
                "sur_name": "Doe",
                "address": "123 Bay Street, Nassau, Bahamas",
                "national_identifier": "000-00-0000"
            }
        ],
        "tx_configuration": {
            "client_reference_id": "my-first-quote",
            "source_configuration": {
                "source_type": "BANK_ACCOUNT",
                "account_configuration": {
                    "account_number": "123456789",
                    "routing_number": "987654321",
                    "account_type": "CHECKING"
                }
            },
            "target_configuration": {
                "source_type": "DLT_WALLET",
                "account_configuration": {
                    "wallet_address": "0x123456789abcdef",
                    "network": "ethereum"
                }
            }
        }
    });

    let client = reqwest::Client::new();
    let response = client
        .post(format!("{BASE_URL}/fx/quote"))
        .header(CONTENT_TYPE, "application/json")
        .header(AUTHORIZATION, "Bearer <your-token>")
        .json(&body)
        .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 returns HTTP 200 with a JSON object containing the quoted conversion details:

{
  "quote_id": "123e4567-e89b-12d3-a456-426614174000",
  "from_currency": "BSD",
  "to_currency": "USDC",
  "amount": 1000,
  "quoted_amount": 998,
  "valid_until": "2025-06-15T12:05:00Z"
}

The quote_id identifies this quote and is used in the next step to capture and execute the transaction via POST /fx/quote/capture/{quote_id}. Note that quotes expire at the time indicated by valid_until — capture the quote before this deadline to lock in the quoted rate.

If you receive a 200 with a valid quote_id, your credentials are configured correctly and you are ready to begin integrating with the Movmint FX Services API.

Next Steps

With your credentials verified, you can proceed to: