> 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

# Use Remote Deposit Capture (API)

> Learn how to use remote deposit capture (RDC) to convert paper checks received in-person into electronic payments via the API

Remote Deposit Capture (RDC) is a service that allows you to convert paper checks received in-person into electronic payments without physically depositing them at a bank. This guide explains how to implement RDC via the API.

Remote Deposit Capture requires configuration by the Payabli team. Contact us to get started.

RDC uses Back Office Conversion (BOC), which only supports consumer checks received in-person at a point-of-sale or staffed payment location. Some checks aren't eligible, including mailed, drop box, business, cashier's, government, and insurance checks. See [Capturing in-person checks](/guides/pay-in-checks-rdc-overview#back-office-conversion-boc) for full eligibility details.

The implementation process consists of two main API calls:

1. Check image capture and OCR extraction
2. Payment processing using the extracted check information

Before you begin, make sure you read [Capturing in-person checks](/guides/pay-in-checks-rdc-overview) to understand the key concepts and requirements for Remote Deposit Capture (RDC).

## Step 1: Process check images

First, send the check images to Payabli for processing using the /CheckCapture/CheckProcessing endpoint. You need to send the front and back images of the check in JPEG or PNG format, base64 encoded.

### Request

POST [https://api-sandbox.payabli.com/api/CheckCapture/CheckProcessing](https://api-sandbox.payabli.com/api/CheckCapture/CheckProcessing)

```curl
curl -X POST https://api-sandbox.payabli.com/api/CheckCapture/CheckProcessing \
     -H "requestToken: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "entryPoint": "8cfec329267",
  "frontImage": "/9j/4AAQSkZJRgABAQEASABIAAD...",
  "rearImage": "/9j/4AAQSkZJRgABAQEASABIAAD...",
  "checkAmount": 12550
}'
```

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

async function main() {
    const client = new PayabliClient({
        apiKey: "YOUR_API_KEY_HERE",
    });
    await client.checkCapture.checkProcessing({
        entryPoint: "8cfec329267",
        frontImage: "/9j/4AAQSkZJRgABAQEASABIAAD...",
        rearImage: "/9j/4AAQSkZJRgABAQEASABIAAD...",
        checkAmount: 12550,
    });
}
main();

```

```python
from payabli import payabli

client = payabli(
    api_key="YOUR_API_KEY_HERE",
)

client.check_capture.check_processing(
    entry_point="8cfec329267",
    front_image="/9j/4AAQSkZJRgABAQEASABIAAD...",
    rear_image="/9j/4AAQSkZJRgABAQEASABIAAD...",
    check_amount=12550,
)

```

```java
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiOasClient;
import io.github.payabli.api.resources.checkcapture.requests.CheckCaptureRequestBody;

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

        client.checkCapture().checkProcessing(
            CheckCaptureRequestBody
                .builder()
                .entryPoint("8cfec329267")
                .frontImage("/9j/4AAQSkZJRgABAQEASABIAAD...")
                .rearImage("/9j/4AAQSkZJRgABAQEASABIAAD...")
                .checkAmount(12550)
                .build()
        );
    }
}
```

```ruby
require "payabli"

client = Payabli::Client.new(api_key: "YOUR_API_KEY_HERE")

client.check_capture.check_processing(
  entry_point: "8cfec329267",
  front_image: "/9j/4AAQSkZJRgABAQEASABIAAD...",
  rear_image: "/9j/4AAQSkZJRgABAQEASABIAAD...",
  check_amount: 12550
)

```

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

namespace Usage;

public class Example
{
    public async Task Do() {
        var client = new PayabliPayabliApiOasClient(
            apiKey: "YOUR_API_KEY_HERE"
        );

        await client.CheckCapture.CheckProcessingAsync(
            new CheckCaptureRequestBody {
                EntryPoint = "8cfec329267",
                FrontImage = "/9j/4AAQSkZJRgABAQEASABIAAD...",
                RearImage = "/9j/4AAQSkZJRgABAQEASABIAAD...",
                CheckAmount = 12550
            }
        );
    }

}

```

```go
package example

import (
    context "context"

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

func do() {
    client := client.NewClient(
        option.WithApiKey(
            "YOUR_API_KEY_HERE",
        ),
    )
    request := &payabli.CheckCaptureRequestBody{
        EntryPoint: "8cfec329267",
        FrontImage: "/9j/4AAQSkZJRgABAQEASABIAAD...",
        RearImage: "/9j/4AAQSkZJRgABAQEASABIAAD...",
        CheckAmount: 12550,
    }
    client.CheckCapture.CheckProcessing(
        context.TODO(),
        request,
    )
}

```

```php
<?php

namespace Example;

use Payabli\PayabliClient;
use Payabli\CheckCapture\Requests\CheckCaptureRequestBody;

$client = new PayabliClient(
    apiKey: 'YOUR_API_KEY_HERE',
);
$client->checkCapture->checkProcessing(
    new CheckCaptureRequestBody([
        'entryPoint' => '8cfec329267',
        'frontImage' => '/9j/4AAQSkZJRgABAQEASABIAAD...',
        'rearImage' => '/9j/4AAQSkZJRgABAQEASABIAAD...',
        'checkAmount' => 12550,
    ]),
);

```

```swift
import Foundation

let headers = [
  "requestToken": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "entryPoint": "8cfec329267",
  "frontImage": "/9j/4AAQSkZJRgABAQEASABIAAD...",
  "rearImage": "/9j/4AAQSkZJRgABAQEASABIAAD...",
  "checkAmount": 12550
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/CheckCapture/CheckProcessing")! 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 response includes the extracted check information, including the OCR account and routing numbers, as well as the check amount.

### Response (200)

```json
{
  "success": true,
  "processDate": "2025-04-10T04:17:09.875Z",
  "amountDiscrepancyDetected": false,
  "endorsementDetected": true,
  "checkType": 1,
  "id": "txn_abc123def456",
  "ocrMicr": "⑆123456789⑆ ⑈123456⑈ 0123",
  "ocrMicrStatus": "SUCCESS",
  "ocrMicrConfidence": "95",
  "ocrAccountNumber": "123456",
  "ocrRoutingNumber": "123456789",
  "ocrCheckNumber": "0123",
  "ocrCheckTranCode": "",
  "ocrAmount": "125.50",
  "ocrAmountStatus": "SUCCESS",
  "ocrAmountConfidence": "98",
  "errors": [],
  "messages": [
    "Check processed successfully"
  ],
  "carLarMatchConfidence": "97",
  "carLarMatchStatus": "MATCH",
  "referenceNumber": "REF_XYZ789",
  "pageIdentifier": null
}
```

If the check processing fails, the response includes error information to help you troubleshoot the issue. Some errors appear in the `errors` array of 200 response, and validation errors are returned as a 400 response.

```json 200 response with errors {17-19}
  {
    "id": "",
    "success": false,
    "processDate": "0001-01-01T00:00:00",
    "ocrMicr": null,
    "ocrMicrStatus": "",
    "ocrMicrConfidence": null,
    "ocrAccountNumber": null,
    "ocrRoutingNumber": null,
    "ocrCheckNumber": null,
    "ocrCheckTranCode": null,
    "ocrAmount": "107",
    "ocrAmountStatus": "",
    "ocrAmountConfidence": null,
    "amountDiscrepancyDetected": false,
    "endorsementDetected": false,
    "errors": [
      "It appears you submitted 2 images of front of check.  Please retake both front and rear photos."
    ],
    "messages": [],
    "carLarMatchConfidence": null,
    "carLarMatchStatus": null,
    "frontImage": null,
    "rearImage": null,
    "checkType": 0,
    "referenceNumber": "0"
  }
```

```json 400 response due to validation errors
  {
    "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "errors": {
      "CheckAmount": [
        "The field checkAmount must be between 1 and 2147483647."
      ]
    },
    "traceId": "00-1c904c7c430bcc27d345d2a01bf0adb0-c3eb27340963e477-01"
  }
```

## Step 2: Process payment

After successfully processing the check images, use the extracted information to complete the payment transaction.

Send a POST request to /MoneyIn/getpaid:

```json
{
  "entryPoint": "41035afaa7",
  "paymentMethod": {
    "method": "ach",
    "achAccount": "123456",         // Use ocrAccountNumber from step 1
    "achRouting": "123456789",      // Use ocrRoutingNumber from step 1
    "achCode": "BOC",               // Must be "BOC" for check conversion
    "achHolder": "John Doe",        // Account holder name
    "achAccountType": "Checking"    // Must be "Checking"
  },
  "paymentDetails": {
    "checkUniqueId": "abc123def456", // Use id from step 1 response
    "totalAmount": 125.50            // Use dot (.) as decimal separator
  },
}
```

This request has some differences from the standard transaction, pay attention to the following fields:

| Field            | Value          | Description                                                   |
| ---------------- | -------------- | ------------------------------------------------------------- |
| `method`         | `ach`          | Payment method must be ACH                                    |
| `achCode`        | `BOC`          | ACH SEC code must be BOC for check conversion                 |
| `achAccountType` | "Checking"     | Account type must be Checking                                 |
| `totalAmount`    | `125.50`       | Amount in dollars, using a dot (`.`) as the decimal separator |
| `checkUniqueId`  | `abc123def456` | ID from the check processing response                         |

A successful request returns a 200 response.

### Response (200)

```json
{
  "responseText": "Success",
  "isSuccess": true,
  "responseData": {
    "authCode": "123456",
    "referenceId": "129-219",
    "resultCode": 1,
    "resultText": "Approved",
    "avsResponseText": "",
    "cvvResponseText": "",
    "customerId": 4440,
    "methodReferenceId": null
  },
  "pageIdentifier": null
}
```

## Implementation recommendations

When implementing RDC, consider the following recommendations, which can help create a smoother user experience and reduce errors.

### Data validation

Before submitting to the API:

* Ensure check images are correctly encoded and within size limits
* Verify the check amount sent to `/CheckCapture/CheckProcessing` is in cents (integer value), and the amount sent to `/MoneyIn/getpaid` uses dot (`.`) decimal notation
* Check that the required parameters are correctly formatted

### Error handling strategies

When implementing error handling, consider the following scenarios and strategies:

| Error scenario                 | Handling strategy                                     |
| ------------------------------ | ----------------------------------------------------- |
| OCR confidence below threshold | Implement manual review for low confidence results    |
| Image quality issues           | Give the user feedback to retake images               |
| Amount discrepancies           | Show warning and allow user to confirm correct amount |
| Connectivity problems          | Implement retry logic with exponential backoff        |

### Testing recommendations

When testing your RDC implementation, consider the following scenarios:

1. **Image quality testing**: Test with varied image qualities and lighting conditions.
2. **Error handling**: Test with intentionally poor images and various check types to verify error handling.
3. **End-to-end flow**: Test the complete flow from image capture to payment processing.
4. **Integration testing**: Verify proper integration with your existing systems.

## Related resources

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

* **[Capturing in-person checks](/guides/pay-in-checks-rdc-overview)** - Learn how to use remote deposit capture (RDC) to convert paper checks into electronic payments