> This is Payabli documentation. For a complete page index, fetch https://docs.payabli.com/llms.txt — append .md to any page URL for lightweight markdown. For section-level indexes, query parameters, and other AI-optimized access methods, see https://docs.payabli.com/ai-agents.md

# Submit a bank account change with the API

> Validate, create, and track a bank account change with the Case Management API

Bank account change access requires configuration by the Payabli team. Contact us to get started.

This guide walks through submitting a bank account change with the Case Management API: validate the account, create the case, and track it as verification runs. For the states a case moves through and who can act on it, see [Bank account change lifecycle](/guides/pay-ops-bank-account-changes-overview).

## Prerequisites

Before you start, make sure you have:

* Case Management access enabled for your organization. Contact the Payabli team if you're not sure.
* An OAuth Bearer token. These endpoints authenticate with a Bearer token, not the `requestToken` API key. See [OAuth authentication](/developers/oauth-authentication).
* The numeric ID of the paypoint whose account you're changing.

The examples use the sandbox base URL, `https://api-sandbox.payabli.com/api`. Switch to `https://api.payabli.com/api` for production.

## Steps

These steps take you from validating the account through to a completed change.

#### Validate the request

Before you create a case, validate the account details. Validation runs the same checks as creation without saving anything, so you can catch problems first.

### Request

POST [https://api-sandbox.payabli.com/api/v2/cases/bank-account/\{paypointId}/validate](https://api-sandbox.payabli.com/api/v2/cases/bank-account/\{paypointId}/validate)

```curl
curl -X POST https://api-sandbox.payabli.com/api/v2/cases/bank-account/3040/validate \
     -H "Content-Type: application/json" \
     -d '{
  "routingNumber": "123456789",
  "accountNumber": "987654321",
  "accountType": "checking",
  "bankAccountHolderType": "business",
  "bankAccountFunction": "Deposits",
  "services": {
    "moneyIn": [
      "Ach"
    ],
    "moneyOut": [
      "Ach"
    ]
  }
}'
```

```typescript
import { PayabliClient } from "@payabli/sdk-node";

async function main() {
    const client = new PayabliClient();
    await client.caseManagement.validateBankAccountChange(3040, {
        routingNumber: "123456789",
        accountNumber: "987654321",
        accountType: "checking",
        bankAccountHolderType: "business",
        bankAccountFunction: "Deposits",
        services: {
            moneyIn: [
                "Ach",
            ],
            moneyOut: [
                "Ach",
            ],
        },
    });
}
main();

```

```python
from payabli import payabli, BankAccountServices

client = payabli()

client.case_management.validate_bank_account_change(
    paypoint_id=3040,
    routing_number="123456789",
    account_number="987654321",
    account_type="checking",
    bank_account_holder_type="business",
    bank_account_function="Deposits",
    services=BankAccountServices(
        money_in=[
            "Ach"
        ],
        money_out=[
            "Ach"
        ],
    ),
)

```

```java
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiOasClient;
import io.github.payabli.api.resources.casemanagement.requests.ValidateBankAccountChangeRequest;
import io.github.payabli.api.types.BankAccountServices;
import io.github.payabli.api.types.CaseManagementBankAccountFunction;
import io.github.payabli.api.types.MoneyInService;
import io.github.payabli.api.types.MoneyOutService;
import java.util.Arrays;
import java.util.Optional;

public class Example {
    public static void main(String[] args) {
        PayabliPayabliApiOasClient client = PayabliPayabliApiOasClient
            .builder()
            .build();

        client.caseManagement().validateBankAccountChange(
            3040L,
            ValidateBankAccountChangeRequest
                .builder()
                .routingNumber("123456789")
                .accountNumber("987654321")
                .accountType("checking")
                .bankAccountHolderType("business")
                .bankAccountFunction(CaseManagementBankAccountFunction.DEPOSITS)
                .services(
                    BankAccountServices
                        .builder()
                        .moneyIn(
                            Optional.of(
                                Arrays.asList(MoneyInService.ACH)
                            )
                        )
                        .moneyOut(
                            Optional.of(
                                Arrays.asList(MoneyOutService.ACH)
                            )
                        )
                        .build()
                )
                .build()
        );
    }
}
```

```csharp
using PayabliPayabliApiOas;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace Usage;

public class Example
{
    public async Task Do() {
        var client = new PayabliPayabliApiOasClient();

        await client.CaseManagement.ValidateBankAccountChangeAsync(
            3040L,
            new ValidateBankAccountChangeRequest {
                RoutingNumber = "123456789",
                AccountNumber = "987654321",
                AccountType = "checking",
                BankAccountHolderType = "business",
                BankAccountFunction = CaseManagementBankAccountFunction.Deposits,
                Services = new BankAccountServices {
                    MoneyIn = new List<MoneyInService>(){
                        MoneyInService.Ach,
                    }
                    ,
                    MoneyOut = new List<MoneyOutService>(){
                        MoneyOutService.Ach,
                    }

                }
            }
        );
    }

}

```

```go
package example

import (
    context "context"

    payabli "github.com/payabli/sdk-go"
    client "github.com/payabli/sdk-go/client"
)

func do() {
    client := client.NewClient()
    request := &payabli.ValidateBankAccountChangeRequest{
        RoutingNumber: "123456789",
        AccountNumber: "987654321",
        AccountType: "checking",
        BankAccountHolderType: "business",
        BankAccountFunction: payabli.CaseManagementBankAccountFunctionDeposits,
        Services: &payabli.BankAccountServices{
            MoneyIn: []payabli.MoneyInService{
                payabli.MoneyInServiceAch,
            },
            MoneyOut: []payabli.MoneyOutService{
                payabli.MoneyOutServiceAch,
            },
        },
    }
    client.CaseManagement.ValidateBankAccountChange(
        context.TODO(),
        int64(3040),
        request,
    )
}

```

```php
<?php

namespace Example;

use Payabli\PayabliClient;
use Payabli\CaseManagement\Requests\ValidateBankAccountChangeRequest;
use Payabli\Types\CaseManagementBankAccountFunction;
use Payabli\Types\BankAccountServices;
use Payabli\Types\MoneyInService;
use Payabli\Types\MoneyOutService;

$client = new PayabliClient();
$client->caseManagement->validateBankAccountChange(
    3040,
    new ValidateBankAccountChangeRequest([
        'routingNumber' => '123456789',
        'accountNumber' => '987654321',
        'accountType' => 'checking',
        'bankAccountHolderType' => 'business',
        'bankAccountFunction' => CaseManagementBankAccountFunction::Deposits->value,
        'services' => new BankAccountServices([
            'moneyIn' => [
                MoneyInService::Ach->value,
            ],
            'moneyOut' => [
                MoneyOutService::Ach->value,
            ],
        ]),
    ]),
);

```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.payabli.com/api/v2/cases/bank-account/3040/validate")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n  \"routingNumber\": \"123456789\",\n  \"accountNumber\": \"987654321\",\n  \"accountType\": \"checking\",\n  \"bankAccountHolderType\": \"business\",\n  \"bankAccountFunction\": \"Deposits\",\n  \"services\": {\n    \"moneyIn\": [\n      \"Ach\"\n    ],\n    \"moneyOut\": [\n      \"Ach\"\n    ]\n  }\n}"

response = http.request(request)
puts response.read_body
```

```swift
import Foundation

let headers = ["Content-Type": "application/json"]
let parameters = [
  "routingNumber": "123456789",
  "accountNumber": "987654321",
  "accountType": "checking",
  "bankAccountHolderType": "business",
  "bankAccountFunction": "Deposits",
  "services": [
    "moneyIn": ["Ach"],
    "moneyOut": ["Ach"]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/v2/cases/bank-account/3040/validate")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

The response tells you whether the request is valid:

### Response (200)

```json
{
  "isValid": true,
  "blockingConditions": [],
  "warnings": [
    "This paypoint has active batches. Consider scheduling the bank account change after the current batch is closed."
  ],
  "validationErrors": []
}
```

Resolve any `blockingConditions` before you continue. `warnings` are informational, so you can create the case with them present.

#### Create the case

Once validation passes, create the case. Add a `nickname`, a `bankName`, and `default` to the same details you validated. Payabli tokenizes the account and takes the account holder name from the paypoint's legal name.

### Request

POST [https://api-sandbox.payabli.com/api/v2/cases/bank-account/\{paypointId}](https://api-sandbox.payabli.com/api/v2/cases/bank-account/\{paypointId})

```curl
curl -X POST https://api-sandbox.payabli.com/api/v2/cases/bank-account/3040 \
     -H "Content-Type: application/json" \
     -d '{
  "nickname": "Main Settlement Account",
  "bankName": "First National Bank",
  "routingNumber": "123456789",
  "accountNumber": "987654321",
  "accountType": "checking",
  "bankAccountHolderType": "business",
  "bankAccountFunction": "Deposits",
  "services": {
    "moneyIn": [
      "Ach"
    ],
    "moneyOut": [
      "Ach"
    ]
  },
  "default": true
}'
```

```typescript
import { PayabliClient } from "@payabli/sdk-node";

async function main() {
    const client = new PayabliClient();
    await client.caseManagement.createBankAccountChange(3040, {
        nickname: "Main Settlement Account",
        bankName: "First National Bank",
        routingNumber: "123456789",
        accountNumber: "987654321",
        accountType: "checking",
        bankAccountHolderType: "business",
        bankAccountFunction: "Deposits",
        services: {
            moneyIn: [
                "Ach",
            ],
            moneyOut: [
                "Ach",
            ],
        },
        default: true,
    });
}
main();

```

```python
from payabli import payabli, BankAccountServices

client = payabli()

client.case_management.create_bank_account_change(
    paypoint_id=3040,
    nickname="Main Settlement Account",
    bank_name="First National Bank",
    routing_number="123456789",
    account_number="987654321",
    account_type="checking",
    bank_account_holder_type="business",
    bank_account_function="Deposits",
    services=BankAccountServices(
        money_in=[
            "Ach"
        ],
        money_out=[
            "Ach"
        ],
    ),
    default=True,
)

```

```java
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiOasClient;
import io.github.payabli.api.resources.casemanagement.requests.CreateBankAccountChangeCaseRequest;
import io.github.payabli.api.types.BankAccountServices;
import io.github.payabli.api.types.CaseManagementBankAccountFunction;
import io.github.payabli.api.types.MoneyInService;
import io.github.payabli.api.types.MoneyOutService;
import java.util.Arrays;
import java.util.Optional;

public class Example {
    public static void main(String[] args) {
        PayabliPayabliApiOasClient client = PayabliPayabliApiOasClient
            .builder()
            .build();

        client.caseManagement().createBankAccountChange(
            3040L,
            CreateBankAccountChangeCaseRequest
                .builder()
                .nickname("Main Settlement Account")
                .bankName("First National Bank")
                .routingNumber("123456789")
                .accountNumber("987654321")
                .accountType("checking")
                .bankAccountHolderType("business")
                .bankAccountFunction(CaseManagementBankAccountFunction.DEPOSITS)
                .services(
                    BankAccountServices
                        .builder()
                        .moneyIn(
                            Optional.of(
                                Arrays.asList(MoneyInService.ACH)
                            )
                        )
                        .moneyOut(
                            Optional.of(
                                Arrays.asList(MoneyOutService.ACH)
                            )
                        )
                        .build()
                )
                .default_(true)
                .build()
        );
    }
}
```

```csharp
using PayabliPayabliApiOas;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace Usage;

public class Example
{
    public async Task Do() {
        var client = new PayabliPayabliApiOasClient();

        await client.CaseManagement.CreateBankAccountChangeAsync(
            3040L,
            new CreateBankAccountChangeCaseRequest {
                Nickname = "Main Settlement Account",
                BankName = "First National Bank",
                RoutingNumber = "123456789",
                AccountNumber = "987654321",
                AccountType = "checking",
                BankAccountHolderType = "business",
                BankAccountFunction = CaseManagementBankAccountFunction.Deposits,
                Services = new BankAccountServices {
                    MoneyIn = new List<MoneyInService>(){
                        MoneyInService.Ach,
                    }
                    ,
                    MoneyOut = new List<MoneyOutService>(){
                        MoneyOutService.Ach,
                    }

                },
                Default = true
            }
        );
    }

}

```

```go
package example

import (
    context "context"

    payabli "github.com/payabli/sdk-go"
    client "github.com/payabli/sdk-go/client"
)

func do() {
    client := client.NewClient()
    request := &payabli.CreateBankAccountChangeCaseRequest{
        Nickname: "Main Settlement Account",
        BankName: "First National Bank",
        RoutingNumber: "123456789",
        AccountNumber: "987654321",
        AccountType: "checking",
        BankAccountHolderType: "business",
        BankAccountFunction: payabli.CaseManagementBankAccountFunctionDeposits,
        Services: &payabli.BankAccountServices{
            MoneyIn: []payabli.MoneyInService{
                payabli.MoneyInServiceAch,
            },
            MoneyOut: []payabli.MoneyOutService{
                payabli.MoneyOutServiceAch,
            },
        },
        Default: true,
    }
    client.CaseManagement.CreateBankAccountChange(
        context.TODO(),
        int64(3040),
        request,
    )
}

```

```php
<?php

namespace Example;

use Payabli\PayabliClient;
use Payabli\CaseManagement\Requests\CreateBankAccountChangeCaseRequest;
use Payabli\Types\CaseManagementBankAccountFunction;
use Payabli\Types\BankAccountServices;
use Payabli\Types\MoneyInService;
use Payabli\Types\MoneyOutService;

$client = new PayabliClient();
$client->caseManagement->createBankAccountChange(
    3040,
    new CreateBankAccountChangeCaseRequest([
        'nickname' => 'Main Settlement Account',
        'bankName' => 'First National Bank',
        'routingNumber' => '123456789',
        'accountNumber' => '987654321',
        'accountType' => 'checking',
        'bankAccountHolderType' => 'business',
        'bankAccountFunction' => CaseManagementBankAccountFunction::Deposits->value,
        'services' => new BankAccountServices([
            'moneyIn' => [
                MoneyInService::Ach->value,
            ],
            'moneyOut' => [
                MoneyOutService::Ach->value,
            ],
        ]),
        'default' => true,
    ]),
);

```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.payabli.com/api/v2/cases/bank-account/3040")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n  \"nickname\": \"Main Settlement Account\",\n  \"bankName\": \"First National Bank\",\n  \"routingNumber\": \"123456789\",\n  \"accountNumber\": \"987654321\",\n  \"accountType\": \"checking\",\n  \"bankAccountHolderType\": \"business\",\n  \"bankAccountFunction\": \"Deposits\",\n  \"services\": {\n    \"moneyIn\": [\n      \"Ach\"\n    ],\n    \"moneyOut\": [\n      \"Ach\"\n    ]\n  },\n  \"default\": true\n}"

response = http.request(request)
puts response.read_body
```

```swift
import Foundation

let headers = ["Content-Type": "application/json"]
let parameters = [
  "nickname": "Main Settlement Account",
  "bankName": "First National Bank",
  "routingNumber": "123456789",
  "accountNumber": "987654321",
  "accountType": "checking",
  "bankAccountHolderType": "business",
  "bankAccountFunction": "Deposits",
  "services": [
    "moneyIn": ["Ach"],
    "moneyOut": ["Ach"]
  ],
  "default": true
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/v2/cases/bank-account/3040")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

To run the change later instead of right after approval, add a `scheduleFor` UTC timestamp between 1 hour and 30 days out. Payabli verifies and reviews the case right away, then waits until that time to complete the switch.

A `201` response returns the full case in the `Submitted` state. Save the `uuid` — you'll use it to track the case. The raw account and routing numbers aren't returned; the case carries a `bankToken` instead.

### Response (201)

```json
{
  "uuid": "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
  "state": "Submitted",
  "caseType": "BankAccountChange",
  "parameters": {
    "type": "BankAccountChange",
    "nickname": "Main Settlement Account",
    "bankName": "First National Bank",
    "bankToken": "bnk_2b1c9e40f5a34c9a8f219e7c6b1a2d34",
    "accountType": "Checking",
    "bankAccountHolderName": "Gruzya Adventure Outfitters LLC",
    "bankAccountHolderType": "business",
    "bankAccountFunction": "Deposits",
    "services": {
      "moneyIn": [
        "Ach"
      ],
      "moneyOut": [
        "Ach"
      ]
    },
    "default": true
  },
  "orgId": 123,
  "paypointId": 3040,
  "scheduleFor": null,
  "createdAt": "2026-01-15T10:30:00Z",
  "updatedAt": "2026-01-15T10:30:00Z",
  "createdBy": 0,
  "assigneeId": null,
  "lastReviewedById": null,
  "stateHistory": [],
  "attachments": [],
  "roomId": null,
  "metadata": null,
  "org": {
    "id": 123,
    "name": "Example Partner Org"
  },
  "paypoint": {
    "id": 3040,
    "name": "Gruzya Adventure Outfitters"
  },
  "createdByUser": null,
  "assignee": null,
  "lastReviewedBy": null
}
```

#### Track verification

After creation, the case moves to `Verifying` on its own and automatic verification runs. Fetch the case to check its status.

### Request

GET [https://api-sandbox.payabli.com/api/v2/cases/\{uuid}](https://api-sandbox.payabli.com/api/v2/cases/\{uuid})

```curl
curl https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70
```

```typescript
import { PayabliClient } from "@payabli/sdk-node";

async function main() {
    const client = new PayabliClient();
    await client.caseManagement.getCase("9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70");
}
main();

```

```python
from payabli import payabli

client = payabli()

client.case_management.get_case(
    uuid_="9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
)

```

```java
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiOasClient;

public class Example {
    public static void main(String[] args) {
        PayabliPayabliApiOasClient client = PayabliPayabliApiOasClient
            .builder()
            .build();

        client.caseManagement().getCase("9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70");
    }
}
```

```csharp
using PayabliPayabliApiOas;
using System.Threading.Tasks;

namespace Usage;

public class Example
{
    public async Task Do() {
        var client = new PayabliPayabliApiOasClient();

        await client.CaseManagement.GetCaseAsync(
            "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70"
        );
    }

}

```

```go
package example

import (
    context "context"

    client "github.com/payabli/sdk-go/client"
)

func do() {
    client := client.NewClient()
    client.CaseManagement.GetCase(
        context.TODO(),
        "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
    )
}

```

```php
<?php

namespace Example;

use Payabli\PayabliClient;

$client = new PayabliClient();
$client->caseManagement->getCase(
    '9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70',
);

```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
```

```swift
import Foundation

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

Verification resolves to one of three states:

* `AutoApproved` — the account passed cleanly and moves toward completion.
* `PendingReview` — the result was inconclusive and needs a reviewer.
* `Denied` — the account failed verification. This is final.

The outcome appears in `metadata.verification` once verification finishes:

### Response (200)

```json
{
  "uuid": "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
  "state": "PendingCompletion",
  "caseType": "BankAccountChange",
  "parameters": {
    "type": "BankAccountChange",
    "nickname": "Main Settlement Account",
    "bankName": "First National Bank",
    "bankToken": "bnk_2b1c9e40f5a34c9a8f219e7c6b1a2d34",
    "accountType": "Checking",
    "bankAccountHolderName": "Gruzya Adventure Outfitters LLC",
    "bankAccountHolderType": "business",
    "bankAccountFunction": "Deposits",
    "services": {
      "moneyIn": [
        "Ach"
      ],
      "moneyOut": [
        "Ach"
      ]
    },
    "default": true
  },
  "orgId": 123,
  "paypointId": 3040,
  "scheduleFor": null,
  "createdAt": "2026-01-15T10:30:00Z",
  "updatedAt": "2026-01-15T10:30:43Z",
  "createdBy": 0,
  "assigneeId": null,
  "lastReviewedById": null,
  "stateHistory": [
    {
      "uuid": "019f806f-453f-701c-b77d-cb585b743bef",
      "caseUuid": "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
      "fromState": "Submitted",
      "toState": "Verifying",
      "ipAddress": null,
      "triggeredBy": null,
      "reason": "Background verification started",
      "createdAt": "2026-01-15T10:30:03Z",
      "triggeredByUser": null
    },
    {
      "uuid": "019f806f-e00e-73d2-b6a4-9dd5b540e11e",
      "caseUuid": "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
      "fromState": "Verifying",
      "toState": "AutoApproved",
      "ipAddress": null,
      "triggeredBy": null,
      "reason": "Polling outcome: approved",
      "createdAt": "2026-01-15T10:30:43Z",
      "triggeredByUser": null
    },
    {
      "uuid": "019f806f-e015-730b-be18-ec695f42f133",
      "caseUuid": "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
      "fromState": "AutoApproved",
      "toState": "PendingCompletion",
      "ipAddress": null,
      "triggeredBy": null,
      "reason": "funding hold acquired",
      "createdAt": "2026-01-15T10:30:43Z",
      "triggeredByUser": null
    }
  ],
  "attachments": [],
  "roomId": 96369,
  "metadata": {
    "verification": {
      "verificationResult": {
        "code": 6,
        "name": "Pass",
        "description": "The suggested action is to accept the bank account and/or customer data for this inquiry."
      },
      "accountResponseCode": {
        "code": 12,
        "name": "_1111",
        "description": "Account Verified – The account was found to be an open and valid checking account."
      },
      "customerResponseCode": null
    },
    "reviewDecision": null
  },
  "org": {
    "id": 123,
    "name": "Example Partner Org"
  },
  "paypoint": {
    "id": 3040,
    "name": "Gruzya Adventure Outfitters"
  },
  "createdByUser": null,
  "assignee": null,
  "lastReviewedBy": null
}
```

Poll the case rather than waiting on the create call, since the flow is asynchronous.

#### Review the case (Enterprise Partners)

If a case is `PendingReview`, an Enterprise Partner acts on it. Platform Partners skip this step — Payabli makes the decision, and the case moves to `Approved` or `Denied` on its own.

First check which actions are available:

### Request

GET [https://api-sandbox.payabli.com/api/v2/cases/\{uuid}/transitions](https://api-sandbox.payabli.com/api/v2/cases/\{uuid}/transitions)

```curl
curl https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/transitions
```

```typescript
import { PayabliClient } from "@payabli/sdk-node";

async function main() {
    const client = new PayabliClient();
    await client.caseManagement.listTransitions("9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70");
}
main();

```

```python
from payabli import payabli

client = payabli()

client.case_management.list_transitions(
    uuid_="9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
)

```

```java
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiOasClient;

public class Example {
    public static void main(String[] args) {
        PayabliPayabliApiOasClient client = PayabliPayabliApiOasClient
            .builder()
            .build();

        client.caseManagement().listTransitions("9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70");
    }
}
```

```csharp
using PayabliPayabliApiOas;
using System.Threading.Tasks;

namespace Usage;

public class Example
{
    public async Task Do() {
        var client = new PayabliPayabliApiOasClient();

        await client.CaseManagement.ListTransitionsAsync(
            "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70"
        );
    }

}

```

```go
package example

import (
    context "context"

    client "github.com/payabli/sdk-go/client"
)

func do() {
    client := client.NewClient()
    client.CaseManagement.ListTransitions(
        context.TODO(),
        "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
    )
}

```

```php
<?php

namespace Example;

use Payabli\PayabliClient;

$client = new PayabliClient();
$client->caseManagement->listTransitions(
    '9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70',
);

```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/transitions")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
```

```swift
import Foundation

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/transitions")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

Assign the case to a reviewer with the assign endpoint:

### Request

POST [https://api-sandbox.payabli.com/api/v2/cases/\{uuid}/assign](https://api-sandbox.payabli.com/api/v2/cases/\{uuid}/assign)

```curl
curl -X POST https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/assign \
     -H "Content-Type: application/json" \
     -d '{
  "assigneeId": 4238,
  "reason": "Routing to the risk team for review."
}'
```

```typescript
import { PayabliClient } from "@payabli/sdk-node";

async function main() {
    const client = new PayabliClient();
    await client.caseManagement.assignCase("9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70", {
        assigneeId: 4238,
        reason: "Routing to the risk team for review.",
    });
}
main();

```

```python
from payabli import payabli

client = payabli()

client.case_management.assign_case(
    uuid_="9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
    assignee_id=4238,
    reason="Routing to the risk team for review.",
)

```

```java
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiOasClient;
import io.github.payabli.api.resources.casemanagement.requests.AssignCaseRequest;

public class Example {
    public static void main(String[] args) {
        PayabliPayabliApiOasClient client = PayabliPayabliApiOasClient
            .builder()
            .build();

        client.caseManagement().assignCase(
            "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
            AssignCaseRequest
                .builder()
                .assigneeId(4238L)
                .reason("Routing to the risk team for review.")
                .build()
        );
    }
}
```

```csharp
using PayabliPayabliApiOas;
using System.Threading.Tasks;

namespace Usage;

public class Example
{
    public async Task Do() {
        var client = new PayabliPayabliApiOasClient();

        await client.CaseManagement.AssignCaseAsync(
            "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
            new AssignCaseRequest {
                AssigneeId = 4238L,
                Reason = "Routing to the risk team for review."
            }
        );
    }

}

```

```go
package example

import (
    context "context"

    payabli "github.com/payabli/sdk-go"
    client "github.com/payabli/sdk-go/client"
)

func do() {
    client := client.NewClient()
    request := &payabli.AssignCaseRequest{
        AssigneeId: int64(4238),
        Reason: payabli.String(
            "Routing to the risk team for review.",
        ),
    }
    client.CaseManagement.AssignCase(
        context.TODO(),
        "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
        request,
    )
}

```

```php
<?php

namespace Example;

use Payabli\PayabliClient;
use Payabli\CaseManagement\Requests\AssignCaseRequest;

$client = new PayabliClient();
$client->caseManagement->assignCase(
    '9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70',
    new AssignCaseRequest([
        'assigneeId' => 4238,
        'reason' => 'Routing to the risk team for review.',
    ]),
);

```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/assign")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n  \"assigneeId\": 4238,\n  \"reason\": \"Routing to the risk team for review.\"\n}"

response = http.request(request)
puts response.read_body
```

```swift
import Foundation

let headers = ["Content-Type": "application/json"]
let parameters = [
  "assigneeId": 4238,
  "reason": "Routing to the risk team for review."
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/assign")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

Approve or deny the case with the transitions endpoint. Include a `declineReason` when you deny.

### Request

POST [https://api-sandbox.payabli.com/api/v2/cases/\{uuid}/transitions](https://api-sandbox.payabli.com/api/v2/cases/\{uuid}/transitions)

```curl
curl -X POST https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/transitions \
     -H "Content-Type: application/json" \
     -d '{
  "trigger": "Approve",
  "reason": "Account ownership confirmed with the merchant by phone."
}'
```

```typescript
import { PayabliClient } from "@payabli/sdk-node";

async function main() {
    const client = new PayabliClient();
    await client.caseManagement.transition("9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70", {
        trigger: "Approve",
        reason: "Account ownership confirmed with the merchant by phone.",
    });
}
main();

```

```python
from payabli import payabli

client = payabli()

client.case_management.transition(
    uuid_="9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
    trigger="Approve",
    reason="Account ownership confirmed with the merchant by phone.",
)

```

```java
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiOasClient;
import io.github.payabli.api.resources.casemanagement.requests.TransitionCaseRequest;
import io.github.payabli.api.types.CaseTrigger;

public class Example {
    public static void main(String[] args) {
        PayabliPayabliApiOasClient client = PayabliPayabliApiOasClient
            .builder()
            .build();

        client.caseManagement().transition(
            "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
            TransitionCaseRequest
                .builder()
                .trigger(CaseTrigger.APPROVE)
                .reason("Account ownership confirmed with the merchant by phone.")
                .build()
        );
    }
}
```

```csharp
using PayabliPayabliApiOas;
using System.Threading.Tasks;

namespace Usage;

public class Example
{
    public async Task Do() {
        var client = new PayabliPayabliApiOasClient();

        await client.CaseManagement.TransitionAsync(
            "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
            new TransitionCaseRequest {
                Trigger = CaseTrigger.Approve,
                Reason = "Account ownership confirmed with the merchant by phone."
            }
        );
    }

}

```

```go
package example

import (
    context "context"

    payabli "github.com/payabli/sdk-go"
    client "github.com/payabli/sdk-go/client"
)

func do() {
    client := client.NewClient()
    request := &payabli.TransitionCaseRequest{
        Trigger: payabli.CaseTriggerApprove,
        Reason: "Account ownership confirmed with the merchant by phone.",
    }
    client.CaseManagement.Transition(
        context.TODO(),
        "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
        request,
    )
}

```

```php
<?php

namespace Example;

use Payabli\PayabliClient;
use Payabli\CaseManagement\Requests\TransitionCaseRequest;
use Payabli\Types\CaseTrigger;

$client = new PayabliClient();
$client->caseManagement->transition(
    '9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70',
    new TransitionCaseRequest([
        'trigger' => CaseTrigger::Approve->value,
        'reason' => 'Account ownership confirmed with the merchant by phone.',
    ]),
);

```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/transitions")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n  \"trigger\": \"Approve\",\n  \"reason\": \"Account ownership confirmed with the merchant by phone.\"\n}"

response = http.request(request)
puts response.read_body
```

```swift
import Foundation

let headers = ["Content-Type": "application/json"]
let parameters = [
  "trigger": "Approve",
  "reason": "Account ownership confirmed with the merchant by phone."
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/v2/cases/9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70/transitions")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

A successful call returns the updated case with its new state and a new `stateHistory` entry recording the action.

### Response (200)

```json
{
  "uuid": "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
  "state": "Approved",
  "caseType": "BankAccountChange",
  "parameters": {
    "type": "BankAccountChange",
    "nickname": "Main Settlement Account",
    "bankName": "First National Bank",
    "bankToken": "bnk_2b1c9e40f5a34c9a8f219e7c6b1a2d34",
    "accountType": "Checking",
    "bankAccountHolderName": "Gruzya Adventure Outfitters LLC",
    "bankAccountHolderType": "business",
    "bankAccountFunction": "Deposits",
    "services": {
      "moneyIn": [
        "Ach"
      ],
      "moneyOut": [
        "Ach"
      ]
    },
    "default": true
  },
  "orgId": 123,
  "paypointId": 3040,
  "scheduleFor": null,
  "createdAt": "2026-01-15T10:30:00Z",
  "updatedAt": "2026-01-15T12:15:00Z",
  "createdBy": 0,
  "assigneeId": 4238,
  "lastReviewedById": 4238,
  "stateHistory": [
    {
      "uuid": "019f8100-1a2b-73c4-9d5e-6f7a8b9c0d1e",
      "caseUuid": "9c2b7e14-3a5f-4d21-b8e0-1f6a4c9d2e70",
      "fromState": "Assigned",
      "toState": "Approved",
      "ipAddress": "203.0.113.10",
      "triggeredBy": 4238,
      "reason": "Account ownership confirmed with the merchant by phone.",
      "createdAt": "2026-01-15T12:15:00Z",
      "triggeredByUser": {
        "id": 4238,
        "name": "Jordan Rivera"
      }
    }
  ],
  "attachments": [],
  "roomId": 96370,
  "metadata": {
    "verification": {
      "verificationResult": {
        "code": 5,
        "name": "RiskAlert",
        "description": "The suggested action is to further investigate the bank account and/or customer data for this inquiry due to a risk alert ."
      },
      "accountResponseCode": {
        "code": 12,
        "name": "_1111",
        "description": "Account Verified – The account was found to be an open and valid checking account."
      },
      "customerResponseCode": {
        "code": 3,
        "name": "CA21",
        "description": "The customer or business name data did not match gAuthenticate data."
      }
    },
    "reviewDecision": null
  },
  "org": {
    "id": 123,
    "name": "Example Partner Org"
  },
  "paypoint": {
    "id": 3040,
    "name": "Gruzya Adventure Outfitters"
  },
  "createdByUser": null,
  "assignee": {
    "id": 4238,
    "name": "Jordan Rivera"
  },
  "lastReviewedBy": {
    "id": 4238,
    "name": "Jordan Rivera"
  }
}
```

Firing an action that isn't valid for the case's current state returns a `409`. Use the transitions list to confirm what's allowed first.

#### Confirm completion

An approved case moves to `PendingCompletion` while the account switch runs, then to `Completed` when the processor confirms it. Fetch the case one more time to confirm it reached `Completed`.

`PendingCompletion` typically clears in under a minute. If a case stays there for more than an hour, contact the Payabli team rather than resubmitting.

## Related resources

See these related resources to help you get the most out of Payabli.

#### References

* **[Case Management API reference](/developers/api-reference/bankChanges/create-bank-account-change)** - Request and response details for each bank-account-change endpoint

#### Related topics

* **[Bank account change lifecycle](/guides/pay-ops-bank-account-changes-overview)** - The states a case moves through and who can act on it
* **[Manage bank account changes (Portal)](/guides/pay-ops-portal-bank-account-changes-manage)** - Do the same thing from the hosted Bank Changes queue instead of the API