# 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.

<br />

## 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:

* **Email:** [hello@movmint.io](mailto:bd@movmint.io)
* **Web:** [https://movmint.io/](https://movmint.io/)

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.

| Environment | Base URL                             |
| ----------- | ------------------------------------ |
| Sandbox     | `https://sandbox.api.movmint.com/v1` |
| UAT         | `https://uat.api.movmint.com/v1`     |
| Production  | `https://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

```go
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))
}
```

```typescript
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();
```

```java
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());
    }
}
```

```rust
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(())
}
```

<br />

### Example Response

A successful `POST /fx/quote` returns HTTP `200` with a JSON object containing the quoted conversion details:

```json
{
  "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:

* **[Capturing a Quote](./capturing-a-quote.md)** — Execute a quoted transaction using the capture endpoint.
* **[API Reference](./api-reference.md)** — Explore all available endpoints, request schemas, and error codes.
* **[Participants & Compliance](./participants.md)** — Understand originator and beneficiary requirements for FX transactions.
* **[Transaction Configuration](./tx-configuration.md)** — Configure source and target funding methods (bank accounts, cards, DLT wallets).