> 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

# Manage ghost cards with the API

> Learn how to create and manage multi-use virtual debit cards for vendor spend with the Payabli API

Payabli supports two types of virtual cards for Pay Out:

* **Single-use virtual cards** are tied to a specific payout and can only be used once. You create them by passing `vcard` as the payment method when you [authorize a payout](/developers/api-reference/moneyout/authorize-a-transaction-for-payout), or a vendor can select `vCard` as the payment method through a vendor link.
* **Ghost cards** (multi-use virtual cards) are issued directly to a vendor and aren't tied to a specific payout. They're designed for recurring or discretionary vendor spend with configurable limits.

This guide covers creating ghost cards and updating their status through the API.

## Considerations

When working with ghost cards, keep the following in mind:

* Only one ghost card can exist per vendor per paypoint. To issue a new card to the same vendor, cancel the existing card first.
* Ghost cards are linked to a vendor. The vendor must belong to the paypoint and have an active status.
* `expenseLimit` is required and must be greater than `0`. It can't exceed the paypoint's configured payout credit limit.
* Setting `exactAmount` to `true` forces `maxNumberOfUses` to `1`, regardless of any other value you pass.
* If you set `maxNumberOfUses` to `0` or a negative number, it defaults to `9999`.
* Card currency is always USD.

## Create a ghost card

Send a POST request to `/api/MoneyOutCard/GhostCard/{entry}` to create a ghost card. See the [API reference](/developers/api-reference/cards/create-ghost-card) for full documentation.

Most fields are required, including `vendorId`, `expenseLimit`, `amount`, `maxNumberOfUses`, `exactAmount`, `billingCycle`, `billingCycleDay`, `dailyTransactionCount`, `dailyAmountLimit`, and `transactionAmountLimit`. Optional fields include `expirationDate`, `mcc`, `tcc`, `misc1`, and `misc2`.

### Request

POST [https://api-sandbox.payabli.com/api/MoneyOutCard/GhostCard/\{entry}](https://api-sandbox.payabli.com/api/MoneyOutCard/GhostCard/\{entry})

```curl CreateGhostCard
curl -X POST https://api-sandbox.payabli.com/api/MoneyOutCard/GhostCard/8cfec2e0fa \
     -H "requestToken: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "vendorId": 42,
  "expenseLimit": 500,
  "amount": 500,
  "maxNumberOfUses": 3,
  "exactAmount": false,
  "expenseLimitPeriod": "monthly",
  "billingCycle": "monthly",
  "billingCycleDay": "1",
  "dailyTransactionCount": 5,
  "dailyAmountLimit": 200,
  "transactionAmountLimit": 100,
  "mcc": "5411",
  "tcc": "R",
  "misc1": "PO-98765",
  "misc2": "Dept-Finance"
}'
```

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

async function main() {
    const client = new PayabliClient({
        apiKey: "YOUR_API_KEY_HERE",
    });
    await client.ghostCard.createGhostCard("8cfec2e0fa", {
        vendorId: 42,
        expenseLimit: 500,
        amount: 500,
        maxNumberOfUses: 3,
        exactAmount: false,
        expenseLimitPeriod: "monthly",
        billingCycle: "monthly",
        billingCycleDay: "1",
        dailyTransactionCount: 5,
        dailyAmountLimit: 200,
        transactionAmountLimit: 100,
        mcc: "5411",
        tcc: "R",
        misc1: "PO-98765",
        misc2: "Dept-Finance",
    });
}
main();

```

```python CreateGhostCard
from payabli import payabli

client = payabli(
    api_key="YOUR_API_KEY_HERE",
)

client.ghost_card.create_ghost_card(
    entry="8cfec2e0fa",
    vendor_id=42,
    expense_limit=500,
    amount=500,
    max_number_of_uses=3,
    exact_amount=False,
    expense_limit_period="monthly",
    billing_cycle="monthly",
    billing_cycle_day="1",
    daily_transaction_count=5,
    daily_amount_limit=200,
    transaction_amount_limit=100,
    mcc="5411",
    tcc="R",
    misc_1="PO-98765",
    misc_2="Dept-Finance",
)

```

```java CreateGhostCard
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiClient;
import io.github.payabli.api.resources.ghostcard.requests.CreateGhostCardRequestBody;

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

        client.ghostCard().createGhostCard(
            "8cfec2e0fa",
            CreateGhostCardRequestBody
                .builder()
                .vendorId(42L)
                .expenseLimit(500.0)
                .amount(500.0)
                .maxNumberOfUses(3)
                .exactAmount(false)
                .expenseLimitPeriod("monthly")
                .billingCycle("monthly")
                .billingCycleDay("1")
                .dailyTransactionCount(5)
                .dailyAmountLimit(200.0)
                .transactionAmountLimit(100)
                .mcc("5411")
                .tcc("R")
                .misc1("PO-98765")
                .misc2("Dept-Finance")
                .build()
        );
    }
}
```

```ruby CreateGhostCard
require "payabli"

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

client.ghost_card.create_ghost_card(
  entry: "8cfec2e0fa",
  vendor_id: 42,
  expense_limit: 500,
  amount: 500,
  max_number_of_uses: 3,
  exact_amount: false,
  expense_limit_period: "monthly",
  billing_cycle: "monthly",
  billing_cycle_day: "1",
  daily_transaction_count: 5,
  daily_amount_limit: 200,
  transaction_amount_limit: 100,
  mcc: "5411",
  tcc: "R",
  misc_1: "PO-98765",
  misc_2: "Dept-Finance"
)

```

```csharp CreateGhostCard
using PayabliPayabliApi;
using System.Threading.Tasks;

namespace Usage;

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

        await client.GhostCard.CreateGhostCardAsync(
            "8cfec2e0fa",
            new CreateGhostCardRequestBody {
                VendorId = 42L,
                ExpenseLimit = 500,
                Amount = 500,
                MaxNumberOfUses = 3,
                ExactAmount = false,
                ExpenseLimitPeriod = "monthly",
                BillingCycle = "monthly",
                BillingCycleDay = "1",
                DailyTransactionCount = 5,
                DailyAmountLimit = 200,
                TransactionAmountLimit = 100,
                Mcc = "5411",
                Tcc = "R",
                Misc1 = "PO-98765",
                Misc2 = "Dept-Finance"
            }
        );
    }

}

```

```go CreateGhostCard
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.CreateGhostCardRequestBody{
        VendorId: int64(42),
        ExpenseLimit: 500,
        Amount: 500,
        MaxNumberOfUses: 3,
        ExactAmount: false,
        ExpenseLimitPeriod: "monthly",
        BillingCycle: "monthly",
        BillingCycleDay: "1",
        DailyTransactionCount: 5,
        DailyAmountLimit: 200,
        TransactionAmountLimit: 100,
        Mcc: payabli.String(
            "5411",
        ),
        Tcc: payabli.String(
            "R",
        ),
        Misc1: payabli.String(
            "PO-98765",
        ),
        Misc2: payabli.String(
            "Dept-Finance",
        ),
    }
    client.GhostCard.CreateGhostCard(
        context.TODO(),
        "8cfec2e0fa",
        request,
    )
}

```

```php CreateGhostCard
<?php

namespace Example;

use Payabli\PayabliClient;
use Payabli\GhostCard\Requests\CreateGhostCardRequestBody;

$client = new PayabliClient(
    apiKey: 'YOUR_API_KEY_HERE',
);
$client->ghostCard->createGhostCard(
    '8cfec2e0fa',
    new CreateGhostCardRequestBody([
        'vendorId' => 42,
        'expenseLimit' => 500,
        'amount' => 500,
        'maxNumberOfUses' => 3,
        'exactAmount' => false,
        'expenseLimitPeriod' => 'monthly',
        'billingCycle' => 'monthly',
        'billingCycleDay' => '1',
        'dailyTransactionCount' => 5,
        'dailyAmountLimit' => 200,
        'transactionAmountLimit' => 100,
        'mcc' => '5411',
        'tcc' => 'R',
        'misc1' => 'PO-98765',
        'misc2' => 'Dept-Finance',
    ]),
);

```

```swift CreateGhostCard
import Foundation

let headers = [
  "requestToken": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "vendorId": 42,
  "expenseLimit": 500,
  "amount": 500,
  "maxNumberOfUses": 3,
  "exactAmount": false,
  "expenseLimitPeriod": "monthly",
  "billingCycle": "monthly",
  "billingCycleDay": "1",
  "dailyTransactionCount": 5,
  "dailyAmountLimit": 200,
  "transactionAmountLimit": 100,
  "mcc": "5411",
  "tcc": "R",
  "misc1": "PO-98765",
  "misc2": "Dept-Finance"
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/MoneyOutCard/GhostCard/8cfec2e0fa")! 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 request returns a `ReferenceId` in `responseData`. This is the card token. Store it to reference the card in subsequent operations.

### Response (200)

```json
{
  "responseText": "Success",
  "isSuccess": true,
  "responseData": {
    "ReferenceId": "gc_abc123def456",
    "ResultCode": 1,
    "ResultText": "Ghost Card created"
  }
}
```

## Update a card's status

Send a PATCH request to `/api/MoneyOutCard/card/{entry}` to update a card's status. See the [API reference](/developers/api-reference/cards/update-card-status) for full documentation.

Pass the `cardToken` (the `ReferenceId` from the create response) and the new `status`. Valid statuses are `Active`, `Inactive`, `Cancelled`, and `Expired`.

Not all status transitions are allowed:

| From        | Allowed transitions                |
| ----------- | ---------------------------------- |
| `Active`    | `Inactive`, `Cancelled`, `Expired` |
| `Inactive`  | `Active`                           |
| `Expired`   | `Active` (renews the card)         |
| `Cancelled` | None — `Cancelled` is terminal     |

### Request

PATCH [https://api-sandbox.payabli.com/api/MoneyOutCard/card/\{entry}](https://api-sandbox.payabli.com/api/MoneyOutCard/card/\{entry})

```curl CancelGhostCard
curl -X PATCH https://api-sandbox.payabli.com/api/MoneyOutCard/card/8cfec2e0fa \
     -H "requestToken: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "cardToken": "gc_abc123def456",
  "status": "Cancelled"
}'
```

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

async function main() {
    const client = new PayabliClient({
        apiKey: "YOUR_API_KEY_HERE",
    });
    await client.ghostCard.updateCard("8cfec2e0fa", {
        cardToken: "gc_abc123def456",
        status: "Cancelled",
    });
}
main();

```

```python CancelGhostCard
from payabli import payabli

client = payabli(
    api_key="YOUR_API_KEY_HERE",
)

client.ghost_card.update_card(
    entry="8cfec2e0fa",
    card_token="gc_abc123def456",
    status="Cancelled",
)

```

```java CancelGhostCard
package com.example.usage;

import io.github.payabli.api.PayabliPayabliApiClient;
import io.github.payabli.api.resources.ghostcard.requests.UpdateCardRequestBody;
import io.github.payabli.api.resources.ghostcard.types.CardStatus;

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

        client.ghostCard().updateCard(
            "8cfec2e0fa",
            UpdateCardRequestBody
                .builder()
                .cardToken("gc_abc123def456")
                .status(CardStatus.CANCELLED)
                .build()
        );
    }
}
```

```ruby CancelGhostCard
require "payabli"

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

client.ghost_card.update_card(
  entry: "8cfec2e0fa",
  card_token: "gc_abc123def456",
  status: "Cancelled"
)

```

```csharp CancelGhostCard
using PayabliPayabliApi;
using System.Threading.Tasks;

namespace Usage;

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

        await client.GhostCard.UpdateCardAsync(
            "8cfec2e0fa",
            new UpdateCardRequestBody {
                CardToken = "gc_abc123def456",
                Status = CardStatus.Cancelled
            }
        );
    }

}

```

```go CancelGhostCard
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.UpdateCardRequestBody{
        CardToken: "gc_abc123def456",
        Status: payabli.CardStatusCancelled.Ptr(),
    }
    client.GhostCard.UpdateCard(
        context.TODO(),
        "8cfec2e0fa",
        request,
    )
}

```

```php CancelGhostCard
<?php

namespace Example;

use Payabli\PayabliClient;
use Payabli\GhostCard\Requests\UpdateCardRequestBody;
use Payabli\GhostCard\Types\CardStatus;

$client = new PayabliClient(
    apiKey: 'YOUR_API_KEY_HERE',
);
$client->ghostCard->updateCard(
    '8cfec2e0fa',
    new UpdateCardRequestBody([
        'cardToken' => 'gc_abc123def456',
        'status' => CardStatus::Cancelled->value,
    ]),
);

```

```swift CancelGhostCard
import Foundation

let headers = [
  "requestToken": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "cardToken": "gc_abc123def456",
  "status": "Cancelled"
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.payabli.com/api/MoneyOutCard/card/8cfec2e0fa")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PATCH"
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()
```

### Response (200)

```json
{
  "responseText": "Success",
  "isSuccess": true,
  "responseData": null
}
```