> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.mercoa.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.mercoa.com/_mcp/server.

# Integrating Mercoa with your BillPay / AP System

## Overview

Mercoa's Virtual Card Agent seamlessly integrates into your existing BillPay / AP workflows to automatically process invoice payments using virtual cards. It's designed to automatically pay invoices using virtual cards whenever it's possible and cost-effective. The integration includes a straightforward decision-based flow with a fallback to your current payment system, ensuring no disruption.

## Integration Flow

This process is handled in two main phases: **validation** and **processing**. Your system first checks if an invoice is eligible for card payment and then acts on that information.

### Validation Flow

This chart shows the initial decision-making process.

```mermaid
graph LR
    A[**Payment<br />Scheduled**] --> B[Validate with<br />Mercoa Agent]
    B --> C{Card<br />Accepted?}
    C -->|No| D[Use Current<br />Workflow]
    C -->|Yes| E[Check<br />Processing Fee]
    E --> F{Fee<br />Acceptable?}
    F -->|No| D
    F -->|Yes| G[Proceed to<br />Processing]
    
    style A fill:#e1f5fe,color:#01579b,stroke:#b3e5fc
    style D fill:#fff3e0,color:#e65100,stroke:#ffe0b2
    style G fill:#e8f5e9,color:#1b5e20,stroke:#c8e6c9
```

### Processing Flow

If an invoice is cleared for card payment, this is the next step.

```mermaid
graph LR
    A[Start Processing] --> B[Process with<br />Virtual Card]
    B --> C{Payment<br />Success?}
    C -->|No| D[Use Current<br />Workflow]
    C -->|Yes| E[Reconcile<br />Payment]
    E --> F[Mark Invoice<br />as Paid]
    
    style A fill:#e1f5fe,color:#01579b,stroke:#b3e5fc
    style D fill:#fff3e0,color:#e65100,stroke:#ffe0b2
    style F fill:#e8f5e9,color:#1b5e20,stroke:#c8e6c9
```

## Implementation Steps

### 1. Trigger the Validation

When a payment is scheduled in your system, make a call to the Mercoa Agent's validation endpoint. This is the entry point to the workflow.

```javascript
// Example: When payment is scheduled
async function schedulePayment(invoice) {
  // Your existing payment scheduling logic
  const scheduledPayment = await createScheduledPayment(invoice);
  
  // Call Mercoa Agent validation
  const validationResult = await validateWithMercoaAgent(invoice);
  
  // Store validation result for later use
  await storeValidationResult(scheduledPayment.id, validationResult);
  
  return scheduledPayment;
}
```

### 2. Call the Validation Endpoint

Use the Mercoa Agent validation endpoint to check if the vendor's invoice can be processed with a virtual card.

\<EndpointReq### Request

POST [https://api.mercoa.com/payment-gateway/validate](https://api.mercoa.com/payment-gateway/validate)

**`Document`**

```curl Document
curl -X POST https://api.mercoa.com/payment-gateway/validate \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '{
  "type": "document",
  "document": "data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg=="
}'
```

**`Document`**

```python Document
import requests

url = "https://api.mercoa.com/payment-gateway/validate"

payload = {
    "type": "document",
    "document": "data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg=="
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`Document`**

```typescript Document
import { MercoaClient } from "@mercoa/javascript";

const client = new MercoaClient({ token: "YOUR_TOKEN" });
await client.paymentGateway.validate.create({
    type: "document",
    document: "data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg=="
});

```

**`Document`**

```go Document
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.mercoa.com/payment-gateway/validate"

	payload := strings.NewReader("{\n  \"type\": \"document\",\n  \"document\": \"data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg==\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Document`**

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

url = URI("https://api.mercoa.com/payment-gateway/validate")

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

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"type\": \"document\",\n  \"document\": \"data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg==\"\n}"

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

**`Document`**

```java Document
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.mercoa.com/payment-gateway/validate")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"type\": \"document\",\n  \"document\": \"data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg==\"\n}")
  .asString();
```

**`Document`**

```php Document
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.mercoa.com/payment-gateway/validate', [
  'body' => '{
  "type": "document",
  "document": "data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg=="
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

**`Document`**

```csharp Document
using RestSharp;

var client = new RestClient("https://api.mercoa.com/payment-gateway/validate");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"type\": \"document\",\n  \"document\": \"data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg==\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Document`**

````swift Document
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "type": "document",
  "document": "data:application/pdf;base64,JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg=="
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api.mercoa.com/payment-gateway/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()
```Tab title="JavaScript">
```javascript
import { MercoaClient } from "@mercoa/javascript"

const mercoa = new MercoaClient({
  token: "YOUR_API_KEY",
})

async function validateWithMercoaAgent(invoice) {
  const validationJob = await mercoa.paymentGateway.createValidationJob({
    type: "html",
    html: `<html><body><h1>Invoice ${invoice.id}</h1><p>Amount: $${invoice.amount}</p></body></html>`
  })
  
  return validationJob
}
````

\</Tab>

#### Python

```python
from mercoa.client import Mercoa

mercoa = Mercoa(token="YOUR_API_KEY")

async def validate_with_mercoa_agent(invoice):
    validation_job = await mercoa.payment_gateway.create_validation_job({
        "type": "html",
        "html": f"<html><body><h1>Invoice {invoice['id']}</h1><p>Amount: ${invoice['amount']}</p></body></html>"
    })
    
    return validation_job
```

#### Go

```go
import (
    mercoa "github.com/mercoa-finance/go"
    mercoaclient "github.com/mercoa-finance/go/client"
    "github.com/mercoa-finance/go/option"
)

client := mercoaclient.NewClient(
    option.WithToken("YOUR_API_KEY"),
)

func validateWithMercoaAgent(invoice map[string]interface{}) (*mercoa.CreateValidationJobResponse, error) {
    response, err := client.PaymentGateway.CreateValidationJob(
        context.TODO(),
        &mercoa.CreateValidationJobRequest{
            Type: "html",
            Html: fmt.Sprintf("<html><body><h1>Invoice %s</h1><p>Amount: $%.2f</p></body></html>", 
                invoice["id"], invoice["amount"]),
        },
    )
    
    return response, err
}
```

#### Java

```java
import com.mercoa.Mercoa;

Mercoa client = Mercoa.builder()
    .token("YOUR_API_KEY")
    .build();

public CreateValidationJobResponse validateWithMercoaAgent(Map<String, Object> invoice) {
    CreateValidationJobRequest request = CreateValidationJobRequest.builder()
        .type("html")
        .html(String.format("<html><body><h1>Invoice %s</h1><p>Amount: $%.2f</p></body></html>", 
            invoice.get("id"), invoice.get("amount")))
        .build();
    
    return client.paymentGateway().createValidationJob(request);
}
```

\</Tabs>

### 3. Analyze the Validation Response

The validation endpoint returns a response indicating whether the invoice can be paid with a card and lists any applicable fees.

* Whether the invoice can be processed with a virtual card
* The processing fee (if applicable)
* Any additional requirements or restrictions

```json
{
  "canProcessWithCard": true,
  "processingFee": 2.50,
  "feeCurrency": "USD",
  "restrictions": [],
  "estimatedProcessingTime": "1-2 business days"
}
```

### 4. Apply Your Decision Logic

Based on the validation response, implement logic on your side to decide the next step.

* If card processing isn't available, fall back to your current workflow.

* If it is available, check if the fee is within your acceptable threshold. If not, fall back.

* If the fee is acceptable, proceed to process the payment with a virtual card.

#### JavaScript

```javascript
async function processPaymentDecision(invoice, validationResult) \{
  // If card processing is not available, use current workflow
  if (validationResult.card?.eligibility !== 'ACCEPTED') {
    return await processWithCurrentWorkflow(invoice);
  }
  
  // Check if fee is acceptable (implement your threshold logic)
  const feeThreshold = getFeeThreshold(invoice.amount);
  const processingFee = validationResult.card?.fee?.value || 0;
  if (processingFee > feeThreshold) {
    return await processWithCurrentWorkflow(invoice);
  }
  
  // Proceed with virtual card processing
  return await processWithVirtualCard(invoice, validationResult);
}
```

#### Python

```python
async def process_payment_decision(invoice, validation_result):
    # If card processing is not available, use current workflow
    if validation_result.card.eligibility != 'ACCEPTED':
        return await process_with_current_workflow(invoice)
    
    # Check if fee is acceptable (implement your threshold logic)
    fee_threshold = get_fee_threshold(invoice['amount'])
    processing_fee = validation_result.card.fee.value if validation_result.card.fee else 0
    if processing_fee > fee_threshold:
        return await process_with_current_workflow(invoice)
    
    # Proceed with virtual card processing
    return await process_with_virtual_card(invoice, validation_result)
```

#### Go

```go
func processPaymentDecision(invoice map[string]interface{}, validationResult *mercoa.CreateValidationJobResponse) (*mercoa.CreateProcessJobResponse, error) \{
    // If card processing is not available, use current workflow
    if validationResult.Card.Eligibility != "ACCEPTED" {
        return processWithCurrentWorkflow(invoice)
    }
    
    // Check if fee is acceptable (implement your threshold logic)
    feeThreshold := getFeeThreshold(invoice["amount"].(float64))
    processingFee := 0.0
    if validationResult.Card.Fee != nil {
        processingFee = validationResult.Card.Fee.Value
    }
    if processingFee > feeThreshold {
        return processWithCurrentWorkflow(invoice)
    }
    
    // Proceed with virtual card processing
    return processWithVirtualCard(invoice, validationResult)
}
```

#### Java

```java
public CreateProcessJobResponse processPaymentDecision(Map<String, Object> invoice, CreateValidationJobResponse validationResult) \{
    // If card processing is not available, use current workflow
    if (!"ACCEPTED".equals(validationResult.getCard().getEligibility())) {
        return processWithCurrentWorkflow(invoice);
    }
    
    // Check if fee is acceptable (implement your threshold logic)
    double feeThreshold = getFeeThreshold((Double) invoice.get("amount"));
    double processingFee = 0.0;
    if (validationResult.getCard().getFee() != null) {
        processingFee = validationResult.getCard().getFee().getValue();
    }
    if (processingFee > feeThreshold) {
        return processWithCurrentWorkflow(invoice);
    }
    
    // Proceed with virtual card processing
    return processWithVirtualCard(invoice, validationResult);
}
```

### 5. Process the Payment

If the decision is to use a virtual card, call Mercoa process endpoint. Your implementation should handle both success and failure. If the payment fails for any reason, fall back to your existing workflow.

#### JavaScript

```javascript
async function processWithVirtualCard(invoice, validationResult) {
  try {
    const processJob = await mercoa.paymentGateway.createProcessJob({
      type: "html",
      html: `<html><body><h1>Invoice ${invoice.id}</h1><p>Amount: $${invoice.amount}</p></body></html>`,
      cardDetails: {
        type: "stripeIssuing",
        firstName: "John",
        lastName: "Doe",
        postalCode: "12345",
        country: "US",
        stripeCardId: "ic_1234567890abcdef",
        stripePublishableKey: "pk_test_1234567890abcdef",
        ephemeralKeyEndpoint: {
          url: "https://api.example.com/ephemeral-keys",
          method: "POST",
          headers: {
            "Authorization": "Bearer YOUR_AUTH_SCHEME",
            "Content-Type": "application/json"
          },
          postBody: "{\"card_id\": \"{{cardId}}\", \"nonce\": \"{{nonce}}\", \"account_id\": \"{{accountId}}\"}"
        }
      }
    })
    
    if (processJob.jobStatus === 'success') {
      // Reconcile the payment with your invoice
      await reconcilePayment(invoice.id, processJob.receiptUrl);
      return { success: true, method: 'virtual_card' };
    } else {
      // Fall back to current workflow
      return await processWithCurrentWorkflow(invoice);
    }
  } catch (error) {
    // Handle errors and fall back to current workflow
    console.error('Virtual card processing failed:', error);
    return await processWithCurrentWorkflow(invoice);
  }
}
```

#### Python

```python
async def process_with_virtual_card(invoice, validation_result):
    try:
        process_job = await mercoa.payment_gateway.create_process_job({
            "type": "html",
            "html": f"<html><body><h1>Invoice {invoice['id']}</h1><p>Amount: ${invoice['amount']}</p></body></html>",
            "cardDetails": {
                "type": "stripeIssuing",
                "firstName": "John",
                "lastName": "Doe",
                "postalCode": "12345",
                "country": "US",
                "stripeCardId": "ic_1234567890abcdef",
                "stripePublishableKey": "pk_test_1234567890abcdef",
                "ephemeralKeyEndpoint": {
                    "url": "https://api.example.com/ephemeral-keys",
                    "method": "POST",
                    "headers": {
                        "Authorization": "Bearer YOUR_AUTH_SCHEME",
                        "Content-Type": "application/json"
                    },
                    "postBody": "{\"card_id\": \"{{cardId}}\", \"nonce\": \"{{nonce}}\", \"account_id\": \"{{accountId}}\"}"
                }
            }
        })
        
        if process_job.job_status == 'success':
            # Reconcile the payment with your invoice
            await reconcile_payment(invoice['id'], process_job.receipt_url)
            return {"success": True, "method": "virtual_card"}
        else:
            # Fall back to current workflow
            return await process_with_current_workflow(invoice)
    except Exception as error:
        # Handle errors and fall back to current workflow
        print(f"Virtual card processing failed: {error}")
        return await process_with_current_workflow(invoice)
```

#### Go

```go
func processWithVirtualCard(invoice map[string]interface{}, validationResult *mercoa.CreateValidationJobResponse) (*mercoa.CreateProcessJobResponse, error) {
    response, err := client.PaymentGateway.CreateProcessJob(
        context.TODO(),
        &mercoa.CreateProcessJobRequest{
            Type: "html",
            Html: fmt.Sprintf("<html><body><h1>Invoice %s</h1><p>Amount: $%.2f</p></body></html>", 
                invoice["id"], invoice["amount"]),
            CardDetails: &mercoa.CardDetails{
                Type:        "stripeIssuing",
                FirstName:   "John",
                LastName:    "Doe",
                PostalCode:  "12345",
                Country:     "US",
                StripeCardId: "ic_1234567890abcdef",
                StripePublishableKey: "pk_test_1234567890abcdef",
                EphemeralKeyEndpoint: &mercoa.EphemeralKeyEndpoint{
                    Url: "https://api.example.com/ephemeral-keys",
                    Method: "POST",
                    Headers: map[string]string{
                        "Authorization": "Bearer YOUR_AUTH_SCHEME",
                        "Content-Type":  "application/json",
                    },
                    PostBody: "{\"card_id\": \"{{cardId}}\", \"nonce\": \"{{nonce}}\", \"account_id\": \"{{accountId}}\"}",
                },
            },
        },
    )
    
    if err != nil {
        return nil, err
    }
    
    if response.JobStatus == "success" {
        // Reconcile the payment with your invoice
        reconcilePayment(invoice["id"].(string), response.ReceiptUrl)
        return response, nil
    } else {
        // Fall back to current workflow
        return processWithCurrentWorkflow(invoice)
    }
}
```

#### Java

```java
public CreateProcessJobResponse processWithVirtualCard(Map<String, Object> invoice, CreateValidationJobResponse validationResult) {
    try {
        CreateProcessJobRequest request = CreateProcessJobRequest.builder()
            .type("html")
            .html(String.format("<html><body><h1>Invoice %s</h1><p>Amount: $%.2f</p></body></html>", 
                invoice.get("id"), invoice.get("amount")))
            .cardDetails(CardDetails.builder()
                .type("stripeIssuing")
                .firstName("John")
                .lastName("Doe")
                .postalCode("12345")
                .country("US")
                .stripeCardId("ic_1234567890abcdef")
                .stripePublishableKey("pk_test_1234567890abcdef")
                .ephemeralKeyEndpoint(EphemeralKeyEndpoint.builder()
                    .url("https://api.example.com/ephemeral-keys")
                    .method("POST")
                    .headers(Map.of(
                        "Authorization", "Bearer YOUR_AUTH_SCHEME",
                        "Content-Type", "application/json"
                    ))
                    .postBody("{\"card_id\": \"{{cardId}}\", \"nonce\": \"{{nonce}}\", \"account_id\": \"{{accountId}}\"}")
                    .build())
                .build())
            .build();
        
        CreateProcessJobResponse processJob = client.paymentGateway().createProcessJob(request);
        
        if ("success".equals(processJob.getJobStatus())) {
            // Reconcile the payment with your invoice
            reconcilePayment((String) invoice.get("id"), processJob.getReceiptUrl());
            return processJob;
        } else {
            // Fall back to current workflow
            return processWithCurrentWorkflow(invoice);
        }
    } catch (Exception error) {
        // Handle errors and fall back to current workflow
        System.err.println("Virtual card processing failed: " + error.getMessage());
        return processWithCurrentWorkflow(invoice);
    }
}
```

### 6. Reconcile the Payment

When a virtual card payment succeeds, you must reconcile the payment on your side. This typically means updating your invoice's status to "paid" and storing the transaction details for your records.

#### JavaScript

```javascript
async function reconcilePayment(invoiceId, receiptUrl) {
  // Update your invoice status to paid
  await updateInvoiceStatus(invoiceId, 'paid');
  
  // Store transaction details for audit trail
  await storeTransactionDetails(invoiceId, receiptUrl, {
    method: 'virtual_card',
    processedAt: new Date(),
    // Include other relevant transaction data
  });
  
  // Trigger any post-payment workflows
  await triggerPostPaymentWorkflows(invoiceId);
}
```

#### Python

```python
async def reconcile_payment(invoice_id, receipt_url):
    # Update your invoice status to paid
    await update_invoice_status(invoice_id, 'paid')
    
    # Store transaction details for audit trail
    await store_transaction_details(invoice_id, receipt_url, {
        'method': 'virtual_card',
        'processed_at': datetime.now(),
        # Include other relevant transaction data
    })
    
    # Trigger any post-payment workflows
    await trigger_post_payment_workflows(invoice_id)
```

#### Go

```go
func reconcilePayment(invoiceId string, receiptUrl string) error {
    // Update your invoice status to paid
    err := updateInvoiceStatus(invoiceId, "paid")
    if err != nil {
        return err
    }
    
    // Store transaction details for audit trail
    err = storeTransactionDetails(invoiceId, receiptUrl, map[string]interface{}{
        "method":       "virtual_card",
        "processed_at": time.Now(),
        // Include other relevant transaction data
    })
    if err != nil {
        return err
    }
    
    // Trigger any post-payment workflows
    return triggerPostPaymentWorkflows(invoiceId)
}
```

#### Java

```java
public void reconcilePayment(String invoiceId, String receiptUrl) {
    // Update your invoice status to paid
    updateInvoiceStatus(invoiceId, "paid");
    
    // Store transaction details for audit trail
    Map<String, Object> transactionDetails = Map.of(
        "method", "virtual_card",
        "processed_at", LocalDateTime.now(),
        // Include other relevant transaction data
    );
    storeTransactionDetails(invoiceId, receiptUrl, transactionDetails);
    
    // Trigger any post-payment workflows
    triggerPostPaymentWorkflows(invoiceId);
}
```

## Migration Strategy

We recommend a phased approach to roll out the integration.

### Phase 1: Validation Only

* Implement the validation endpoint call.

* Log the results to analyze vendor eligibility rates and potential fees without actually processing payments.

### Phase 2: Limited Processing

* Enable virtual card processing for a small, selected group of low-risk vendors or invoices.

* Monitor success rates and ensure your reconciliation logic works as expected.

### Phase 3: Full Integration

* Enable the workflow for all eligible invoices.

* Ensure your fallback mechanisms are robust.

* Continuously monitor and optimize based on performance data.