# Convert API

> 加盟店残高から直接暗号資産を交換できます — リアルタイムの見積もりを取得し、市場価格で実行します。

Convert API を使うと、加盟店残高が保有する通貨間を現在の市場価格で交換できます — 加盟店ダッシュボードの**スワップ**タブを支えているのと同じエンジンを、バックエンドから直接呼び出せます。

> **WARNING:** Convert のエンドポイントは、[Payment API](/docs/payments) のリクエストと同じ**通常の API キー**で署名します — Payout API キーでは**ありません**。実行すると加盟店残高が即座に借方・貸方処理されるため、資金を動かす他のクレデンシャルと同様に慎重に扱ってください。

## 交換レートの取得

現在の市場価格に基づく参考レート（有効レートと結果の金額）を返します。残高の引き落としや確保は一切行われません — 実行前に何度でも呼び出せます。

`POST /v1/convert/price`

### リクエストパラメータ

| フィールド | 型 | 必須 | 説明 | 値 |
|-----------|-----|------|------|-----|
| `from_currency` | string | 必須 | 変換元の通貨 | `BTC`, `ETH`, `USDT`, `USDC`, `TRX`, `BNB`, `GRAM`, `SOL`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `to_currency` | string | 必須 | 変換先の通貨。`from_currency` と異なる必要があります | `USDT`, `USDC`, `BTC`, `ETH`, `TRX`, `BNB`, `GRAM`, `SOL`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `amount` | decimal | 必須 | 変換する金額。`0` より大きい値 |  |
| `amount_type` | string | 必須 | `amount` がどちら側を指すか | `from`, `to` |

> **INFO:** `amount_type=from` は `from_currency` をちょうど `amount` 分支払います。`amount_type=to` は `to_currency` をちょうど `amount` 分受け取ります。

**🟢 200 OK** · `application/json`

```json
{
  "state": 0,
  "result": {
    "success": true,
    "from_currency": "BTC",
    "to_currency": "USDT",
    "amount_type": "from",
    "from_amount": "0.01000000",
    "to_amount": "947.86690000",
    "effective_rate": "94786.69000000",
    "from_amount_usd": "947.87",
    "to_amount_usd": "947.87"
  }
}
```

#### レスポンスフィールド

| フィールド | 型 | 説明 |
|-----------|-----|------|
| `success` | boolean | 見積もりの計算が成功したかどうか |
| `from_currency` | string | 変換元通貨 |
| `to_currency` | string | 変換先通貨 |
| `amount_type` | string | リクエストの `amount_type` をそのまま返す |
| `from_amount` | string | `from_currency` で引き落とされる予定の金額 |
| `to_amount` | string | `to_currency` で入金される予定の金額 |
| `effective_rate` | string | この見積もりに適用されたレート — `from_currency` 1単位あたりの `to_currency`（すでにプラットフォームの価格設定を含む） |
| `from_amount_usd` | string \| null | `from_amount` の USD 換算額 |
| `to_amount_usd` | string \| null | `to_amount` の USD 換算額 |

- このレートは**あくまで参考値**です — 見積もりから実行までの間に市場価格が変動する可能性があります。
- この呼び出しでは残高の引き落としや確保は行われません。

> Use your project UUID and the endpoint-appropriate API key from the merchant dashboard.

#### Interactive request: `POST /v1/convert/price`
  - `from_currency` (enum, required): BTC,ETH,USDT,USDC,TRX,BNB,GRAM,SOL,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `to_currency` (enum, required): USDT,USDC,BTC,ETH,TRX,BNB,GRAM,SOL,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `amount` (decimal, required)
  - `amount_type` (enum, required): from,to

## 交換の実行

現在の市場価格で交換を実行し、加盟店残高を更新します。「レートを確定する」という別ステップはありません — 交換したい金額を指定して直接このエンドポイントを呼び出してください。

`POST /v1/convert`

> **INFO:** **冪等性。** 最初の呼び出しから約1分以内に、まったく同じリクエスト（同じ `from_currency`、`to_currency`、`amount`、`amount_type`）を繰り返すと、新規作成ではなく既存の交換結果が返されます。この時間枠を過ぎると、同一のリクエストは新しい交換として扱われます — タイムアウト時にやみくもに再試行せず、まず前回の呼び出し結果を確認してください。

> **WARNING:** このエンドポイントは呼び出し元ごとに**1分あたり10リクエスト**に制限されています — 呼び出しのたびに実際の残高が動くため、通常の API レート制限より厳しくなっています。

### リクエストパラメータ

| フィールド | 型 | 必須 | 説明 | 値 |
|-----------|-----|------|------|-----|
| `from_currency` | string | 必須 | 変換元の通貨 | `BTC`, `ETH`, `USDT`, `USDC`, `TRX`, `BNB`, `GRAM`, `SOL`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `to_currency` | string | 必須 | 変換先の通貨。`from_currency` と異なる必要があります | `USDT`, `USDC`, `BTC`, `ETH`, `TRX`, `BNB`, `GRAM`, `SOL`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `amount` | decimal | 必須 | 変換する金額。`0` より大きい値 |  |
| `amount_type` | string | 必須 | `amount` がどちら側を指すか | `from`, `to` |

**🟢 200 OK** · `application/json`

```json
{
  "state": 0,
  "result": {
    "id": 12345,
    "type": "manual",
    "status": "completed",
    "from_currency": "BTC",
    "to_currency": "USDT",
    "from_amount": "0.01000000",
    "requested_from_amount": "0.01000000",
    "refund_amount": null,
    "to_amount": "947.86690000",
    "exchange_rate": "94786.69000000",
    "fee_amount": "0.00000000",
    "from_amount_usd": "947.87",
    "to_amount_usd": "947.87",
    "processed_at": "2026-01-20T15:30:24Z",
    "created_at": "2026-01-20T15:30:22Z"
  }
}
```

#### レスポンスフィールド

| フィールド | 型 | 説明 |
|-----------|-----|------|
| `id` | int | システムが割り当てた交換注文 ID |
| `type` | string | この API では常に `manual` |
| `status` | string | 現在のステータス（下記「交換ステータス」を参照） |
| `from_currency` | string | 変換元通貨 |
| `to_currency` | string | 変換先通貨 |
| `from_amount` | string | `from_currency` で引き落とされた金額 |
| `requested_from_amount` | string \| null | `amount_type = from` の場合に元々リクエストされた元の金額。`amount_type = to` の場合は `null` |
| `refund_amount` | string \| null | 部分約定後にお客様へ返金された、事前引き落とし分の一部。注文が完全に約定した場合は `null` |
| `to_amount` | string | `to_currency` で入金された金額 |
| `exchange_rate` | string | この交換に実際に適用されたレート — `from_currency` 1単位あたりの `to_currency`（すでにプラットフォームの価格設定を含む） |
| `fee_amount` | string | この交換に課されたプラットフォーム手数料。取引の方向によって `from_currency` または `to_currency` で表示され、すでに `exchange_rate` に反映済み — 透明性のために表示 |
| `from_amount_usd` | string \| null | `from_amount` の USD 換算額 |
| `to_amount_usd` | string \| null | `to_amount` の USD 換算額 |
| `processed_at` | string (ISO 8601) \| null | 交換の実行が完了した日時。処理中は `null` |
| `created_at` | string (ISO 8601) | 交換注文が作成された日時 |

#### 交換ステータス

| ステータス | 説明 |
|-----------|------|
| `pending` | 作成済み、まだ市場に送信されていない |
| `processing` | 残高がロックされ、注文が市場に出された |
| `completed` | 完全に約定 — `to_amount` が残高に入金済み |
| `failed` | 実行できなかった — 事前に引き落とされた金額は自動的に返金済み |
| `partially_completed` | 直接の市場がない通貨ペア（中間通貨経由でルーティング）専用: 最初のステップは完了したが、2番目が失敗。`to_currency` の代わりに中間通貨が入金されるため、そこから改めて交換して本来の目的の通貨に到達してください |

#### Interactive request: `POST /v1/convert`
  - `from_currency` (enum, required): BTC,ETH,USDT,USDC,TRX,BNB,GRAM,SOL,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `to_currency` (enum, required): USDT,USDC,BTC,ETH,TRX,BNB,GRAM,SOL,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `amount` (decimal, required)
  - `amount_type` (enum, required): from,to

## エラー

失敗した場合、レスポンスには `state: 1` と `error_code` が含まれます —  `/v1/convert/price` と `/v1/convert` で共通:

**🔴 422 / 400** · `application/json`

```json
{
  "state": 1,
  "error_code": "amount_too_small",
  "errors": {
    "amount": "Amount is too small for this conversion. Please increase the amount and try again."
  }
}
```

| `error_code` | HTTP ステータス | 説明 |
|--------------|-----------------|------|
| `validation_failed` | 422 | パラメータが不正または不足している、あるいはビジネスルールにより拒否された（例: 残高不足）— 詳細は `errors` フィールドを参照 |
| `amount_too_small` | 422 | `amount` がこの通貨ペアの最小取引可能サイズを下回っている |
| `convert_unavailable` | 400 | 現時点で交換を実行できなかった（市場データが取得できない、または2つの通貨間にルートがない）— しばらくしてから再試行してください |
| `internal_error` | 400 | リクエスト処理中に予期しないサーバー内部エラーが発生した |

## 受信支払いの自動変換

自動変換は、受信請求書およびスタティックウォレットクレジットのためのプロジェクト設定です。これは `/v1/payment` にフィールドを追加することで設定するのではなく、マーチャントダッシュボードで設定されます。各ルールは、1つ以上のソース通貨と1つのターゲット通貨を選択します。

変換が完了すると、支払い情報およびマーチャントのWebhookには以下の情報が含まれる場合があります：

```json
{
  "payment_amount": "0.14800000",
  "merchant_amount": "0.146520000000000000",
  "payer_currency": "XMR",
  "convert": {
    "to_currency": "USDT",
    "commission": "0.09000000",
    "rate": "323.21000000",
    "amount": "47.262015740000000000"
  }
}
```

金額のドメインは意図的に分けられています：

- `payment_amount` — ソース支払い通貨でオンチェーンで検出されたもの;
- `merchant_amount` — 変換前にマーチャントに帰属する純ソース金額;
- `convert.amount` — `convert.to_currency` にクレジットされた金額;
- `convert.rate` と `convert.commission` — 実行された換算結果であり、ローカルで再計算すべき価格ではありません。

> **WARNING:** `convert` の欠如には意味があります：換算が完了していない可能性がある、当該ソースに対して設定されていない可能性がある、またはソース通貨でのクレジットにフォールバックした可能性があります。`/exchange-rates` や公的な市場価格から目標金額を勝手に作成してはいけません。

### 自動換算失敗およびフォールバック

換算はブロックチェーン支払いの受領の下流で行われます。市場の可用性、最小注文サイズ、精度の制限、取引所のタイムアウト、実行可能な流動性の不足が、換算を遅延または妨げることがあります。

- グローバル／プロジェクトの最小値未満の入金は換算パイプラインをバイパスし、ソース通貨をクレジットします。
- 一時的な失敗は非同期でリトライすることができます。
- 大きなまたは取引不可能な預金は、リトライポリシーが尽きた後、元の通貨でのクレジットに戻ることがあります。
- したがって、目的の通貨換算が行われなかった場合でも、支払いは有効であり得ます。

統合ではまず検証済みの支払いを永続化し、その後、支払い情報、任意の`convert`ブロック、ならびに加盟店残高から実際にクレジットされた通貨を照合する必要があります。自身の分析や通知システムを待っている間に、支払いウェブフックの確認をブロックしてはいけません。

### 自動変換受入テスト

少なくとも次の項目をテストしてください：成功した直接変換、ブリッジ／マルチホップ変換、最小値以下のダスト、一時的な再試行、ソース通貨へのフォールバック、支払い不足、過剰支払い、重複ウェブフック、`convert`の欠落、および曖昧なタイムアウト後の照合。

## 手動変換のエッジケース

- `/v1/convert/price`は参考用のプレビューです。市場の動きにより実行結果が変わる可能性があります。
- `amount_type: from`はソース側のリクエストを修正し、`amount_type: to`はターゲット側の金額をリクエストします。確認UIを表示する際に意味を入れ替えないでください。
- 直接取引のない通貨ペアは、仲介通貨を経由してルーティングできます。一方の取引だけが完了した場合、`partially_completed`は中間クレジットを報告します。
- 実行呼び出しがタイムアウトした場合は、再試行する前に調整してください。HTTPレスポンスが失われても、成行注文は実行される可能性があります。
- `failed`はローカルの補償残高エントリを適用する権限としてではなく、調整すべき状態として扱ってください。プラットフォームが借方/返金の会計を管理します。