# Create Settlements

Source: https://developers.bitgo.com/docs/oes-partner-settlements

## Overview

Settlement between your partner platform and BitGo must occur during a pre-determined settlement window, typically once every 24 hours. At that time you create settlements for all trading that occurs on your platform. Settlements transfer assets off chain between your BitGo account to client BitGo accounts.

### Settlement API Versions

There are two settlement endpoints. Which one to use depends on whether your integration has disputes enabled:

| Version | Endpoint | Use when |
| :---- | :---- | :---- |
| v1 | `POST /api/network/v1/enterprises/{enterpriseId}/partners/settlements` | Disputes are **not** enabled for your integration. BitGo processes settlement synchronously. |
| v2 | `POST /api/network/v2/enterprises/{enterpriseId}/partners/settlements` | Your integration has disputes enabled. Requires `cutoffAt`. BitGo processes settlement asynchronously after the dispute window ends. |

If you call the v1 endpoint and your integration has disputes enabled, you receive a `403` response.

> 📘 **Note**
>
> You can use the v2 endpoint for synchronized settlements by setting a dispute window of 0.

### Signature and Verification

Settlement requests from you to BitGo must be cryptographically signed and verified to provide integrity, authenticity, and nonrepudiation. Use the BitGo [JavaScript SDK](/docs/get-started-sdk-install) or [Express](/docs/get-started-express-install) to sign the payload with the trading account private key.

## Prerequisites

* [Get Started](/docs/get-started-intro) - Ensure your access token has the following permissions:
  * `Settlement Network - Read`
  * `Settlement Network - Write`
* [Request Signing and Verification](/docs/oes-partner-signature)
* [Activate Client Connections](/docs/oes-partner-connect)
* [Allocate Assets](/docs/oes-partner-allocate)
* Client trading occurred on your platform in the last 24 hours.

## Cookbooks

Need just the steps? Expand a cookbook below to get started:

<Cookbook slug="oes-partner-settlements" title="Create Settlements" />

<Cookbook slug="oes-partner-settlements-disputes" title="Settlements and Disputes" />

Use the following steps to generate a payload and send a signed settlement request.

## 1. Get Signing Payload

Add the `externalId`, `settlementAmounts`, and `nonce` attributes to the request. If you are submitting a v2 settlement (disputes enabled), also include `cutoffAt`.

>Endpoint: [Get Signing Payload for Partner Settlement](/reference/v1partnersettlementsigninggetroute)

> 📘 **Note**
>
> If your HTTP client does not support sending a request body on a GET request, use the POST variant: [POST .../partners/settlements-signing](/reference/v1partnersettlementssigningpostroute).

```shell Without disputes (v1)
curl -X GET http://$BITGO_EXPRESS_HOST/api/network/v1/enterprises/{enterpriseId}/partners/settlements-signing \
-H "Authorization: Bearer v123xyz..." \
-H "Content-Type: application/json" \
-d '{
  "externalId": "string",
  "notes": "string",
  "settlementAmounts": {
    "additionalProp": {
      "additionalProp": "string"
    }
  },
  "nonce": "string"
}'
```
```shell Disputes enabled (v2)
curl -X GET http://$BITGO_EXPRESS_HOST/api/network/v1/enterprises/{enterpriseId}/partners/settlements-signing \
-H "Authorization: Bearer v123xyz..." \
-H "Content-Type: application/json" \
-d '{
  "externalId": "string",
  "notes": "string",
  "settlementAmounts": {
    "additionalProp": {
      "additionalProp": "string"
    }
  },
  "nonce": "string",
  "cutoffAt": "2026-03-18T12:00:00.000Z"
}'
```
```javascript Without disputes (v1)
import superagent from 'superagent';
import { BitGoAPI } from '@bitgo/sdk-api';
import { coins } from '@bitgo/sdk-core';
require('dotenv').config({ path: '../../.env' });

const bitgo = new BitGoAPI({
  accessToken: process.env.TESTNET_ACCESS_TOKEN,
  env: 'test',
});

const coin = 'ofc';
bitgo.register(coin, coins.Ofc.createInstance);

function getWalletPwFromEnv(walletId: string): string {
  const name = `WALLET_${walletId}_PASSPHRASE`;
  const walletPw = process.env[name];
  if (walletPw === undefined) {
    throw new Error(`Could not find wallet passphrase ${name} in environment`);
  }
  return walletPw;
}

async function main() {
  const enterpriseId = '<YOUR_ENTERPRISE_ID>';
  const walletId = 'xyz123';
  const wallet = await bitgo.coin(coin).wallets().get({ id: walletId });
  const walletPassphrase = getWalletPwFromEnv(wallet.id());
  const tradingAccount = wallet.toTradingAccount();

  const settlementBody = {
    externalId: 'idForSettlementAtPartner',
    notes: 'this is a settlement note',
    settlementAmounts: {
      '09684b38-49ed-4cf6-a28e-c3a459494c69': {
        BTC: '100',
        ETH: '-200',
      },
      '136c1c69-8654-484f-8c5f-591b334a084f': {
        XRP: '300',
        BTC: '-400',
      },
    },
    nonce: '1',
  };

  // Step 1: Get signing payload
  const signingResponse = await superagent
    .get(`${process.env.BITGO_EXPRESS_HOST}/api/network/v1/enterprises/${enterpriseId}/partners/settlements-signing`)
    .set('Authorization', `Bearer ${process.env.TESTNET_ACCESS_TOKEN}`)
    .set('Content-Type', 'application/json')
    .send(settlementBody);

  const { payload } = signingResponse.body;

  // Sign the payload
  const signature = tradingAccount.signPayload({
    payload,
    walletPassphrase,
  });

  // Step 2: Send signed settlement payload
  const settlementResponse = await superagent
    .post(`${process.env.BITGO_EXPRESS_HOST}/api/network/v1/enterprises/${enterpriseId}/partners/settlements`)
    .set('Content-Type', 'application/json')
    .send({
      ...settlementBody,
      payload,
      signature,
    });

  console.log('Settlement:', settlementResponse.body);
}
```
```javascript Disputes enabled (v2)
import superagent from 'superagent';
import { BitGoAPI } from '@bitgo/sdk-api';
import { coins } from '@bitgo/sdk-core';
require('dotenv').config({ path: '../../.env' });

const bitgo = new BitGoAPI({
  accessToken: process.env.TESTNET_ACCESS_TOKEN,
  env: 'test',
});

const coin = 'ofc';
bitgo.register(coin, coins.Ofc.createInstance);

function getWalletPwFromEnv(walletId: string): string {
  const name = `WALLET_${walletId}_PASSPHRASE`;
  const walletPw = process.env[name];
  if (walletPw === undefined) {
    throw new Error(`Could not find wallet passphrase ${name} in environment`);
  }
  return walletPw;
}

async function main() {
  const enterpriseId = '<YOUR_ENTERPRISE_ID>';
  const walletId = 'xyz123';
  const wallet = await bitgo.coin(coin).wallets().get({ id: walletId });
  const walletPassphrase = getWalletPwFromEnv(wallet.id());
  const tradingAccount = wallet.toTradingAccount();

  const settlementBody = {
    externalId: 'idForSettlementAtPartner',
    notes: 'this is a settlement note',
    settlementAmounts: {
      '09684b38-49ed-4cf6-a28e-c3a459494c69': {
        BTC: '100',
        ETH: '-200',
      },
      '136c1c69-8654-484f-8c5f-591b334a084f': {
        XRP: '300',
        BTC: '-400',
      },
    },
    nonce: '1',
    cutoffAt: '2026-03-18T12:00:00.000Z',
  };

  // Step 1: Get signing payload
  const signingResponse = await superagent
    .get(`${process.env.BITGO_EXPRESS_HOST}/api/network/v1/enterprises/${enterpriseId}/partners/settlements-signing`)
    .set('Authorization', `Bearer ${process.env.TESTNET_ACCESS_TOKEN}`)
    .set('Content-Type', 'application/json')
    .send(settlementBody);

  const { payload } = signingResponse.body;

  // Sign the payload
  const signature = tradingAccount.signPayload({
    payload,
    walletPassphrase,
  });

  // Step 2: Send signed settlement payload
  const settlementResponse = await superagent
    .post(`${process.env.BITGO_EXPRESS_HOST}/api/network/v2/enterprises/${enterpriseId}/partners/settlements`)
    .set('Content-Type', 'application/json')
    .send({
      ...settlementBody,
      payload,
      signature,
    });

  console.log('Settlement:', settlementResponse.body);
}
```

#### Step Result

```json JSON
{
  "payload": "{ \"externalId\": \"...\", \"settlementAmounts\": { ... }, \"nonce\": \"...\" }"
}
```

## 2. Send Signed Settlement Payload

>Endpoints: [Perform Partner Settlement (v1)](/reference/v1partnersettlementspostroute) · [Initiate Partner Settlement (v2)](/reference/v2partnersettlementspostroute)

`cutoffAt` is the ISO 8601 timestamp of the most recent trade in this settlement. BitGo uses it to inform clients of the trading activity in this settlement. Include it in both the signing request (Step 1) and the settlement request body so the signature covers it.

```shell Without disputes (v1)
curl -X POST http://$BITGO_EXPRESS_HOST/api/network/v1/enterprises/{enterpriseId}/partners/settlements \
-H "Content-Type: application/json" \
-d '{
  "externalId": "idForSettlementAtPartner",
  "notes": "this is a settlement note",
  "settlementAmounts": {
    "09684b38-49ed-4cf6-a28e-c3a459494c69": {
      "BTC": "100",
      "ETH": "-200"
    },
    "136c1c69-8654-484f-8c5f-591b334a084f": {
      "XRP": "300",
      "BTC": "-400"
    }
  },
  "nonce": "1",
  "payload": "<payload string from step 1>",
  "signature": "<signature>"
}'
```
```shell Disputes enabled (v2)
curl -X POST http://$BITGO_EXPRESS_HOST/api/network/v2/enterprises/{enterpriseId}/partners/settlements \
-H "Content-Type: application/json" \
-d '{
  "externalId": "idForSettlementAtPartner",
  "notes": "this is a settlement note",
  "settlementAmounts": {
    "09684b38-49ed-4cf6-a28e-c3a459494c69": {
      "BTC": "100",
      "ETH": "-200"
    },
    "136c1c69-8654-484f-8c5f-591b334a084f": {
      "XRP": "300",
      "BTC": "-400"
    }
  },
  "nonce": "1",
  "cutoffAt": "2026-03-18T12:00:00.000Z",
  "payload": "<payload string from step 1>",
  "signature": "<signature>"
}'
```

#### Step Result

The v2 response has an initial `status` of `pending`, and BitGo processes it asynchronously:

1. When the dispute window ends, BitGo makes a call to your finalize settlement endpoint. This call includes the final settlement amounts which may differ from the initially posted settlement amounts. There may be prior settlement disputes closing or clients submitting disputes on this current settlement.

2. The settlement enters the top up window, where you can reconcile disputes on your platform.

3. Once the top up window ends, BitGo attempts to process the settlement. If funds in your Go Account are not sufficient to satisfy your liabilities for settlement, the settlement will move to the failed state and the settlement will be retried on a continual basis until the settlement goes through.


```json Without disputes (v1)
{
  "settlement": {
    "id": "string",
    "partnerId": "string",
    "externalId": "string",
    "status": "completed",
    "settlementType": "onchain",
    "reconciled": true,
    "initiatedBy": "string",
    "notes": "string",
    "createdAt": "2025-11-11T19:12:37.874Z",
    "updatedAt": "2025-11-11T19:12:37.874Z",
    "finalizedAt": "2025-11-11T19:12:37.874Z",
    "rtId": "string",
    "lossSLAAlertSent": true,
    "gainSLAAlertSent": true,
    "cutoffAt": null,
    "disputed": false
  }
}
```
```json Disputes enabled (v2)
{
  "settlement": {
    "id": "string",
    "partnerId": "string",
    "externalId": "string",
    "status": "pending",
    "settlementType": "onchain",
    "reconciled": false,
    "initiatedBy": "string",
    "notes": "string",
    "createdAt": "2026-03-18T12:00:00.000Z",
    "updatedAt": "2026-03-18T12:00:00.000Z",
    "finalizedAt": null,
    "rtId": "string",
    "lossSLAAlertSent": false,
    "gainSLAAlertSent": false,
    "cutoffAt": "2026-03-18T12:00:00.000Z",
    "disputed": false
  }
}
```

## Next

[Deallocate Assets](/docs/oes-partner-deallocate)

## See Also

* [API Reference: Perform Partner Settlement (v1)](/reference/v1partnersettlementspostroute)
* [API Reference: Initiate Partner Settlement (v2)](/reference/v2partnersettlementspostroute)
* [API Reference: Get Signing Payload for Partner Settlement](/reference/v1partnersettlementsigninggetroute)
