Using for Transactions

Process one-time sales for recurring customers using vault tokens with your merchant API key

Process one-time sales using vault tokens instead of raw payment data. This approach is ideal for serving returning customers without collecting payment information again.

📘

Vault tokens eliminate the need to handle sensitive payment data for repeat transactions.

Server-side Example

The following is an example code snippet. Full parameter support can be seen in our docs under the "Credit Card - Sale" request.

// Process sale using vault token
const axios = require('axios');

router.post('/vault-sale', async (req, res) => {
  try {
    const { customerVaultId, amount } = req.body;
    
    // Call NMI's v5 Payments API with customer vault ID
    const response = await axios.post('https://secure.nmi.com/api/v5/payments/sale', {
      amount: parseFloat(amount),
      payment_details: {
        customer_vault_id: customerVaultId
      }
    }, {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': '{user.privateApiKey}'
      }
    });
    
    if (response.data.response === '1') {
      return res.json({
        success: true,
        transactionId: response.data.id,
        authCode: response.data.auth_code,
        responseText: response.data.response_text
      });
    } else {
      return res.json({
        success: false,
        error: response.data.response_text
      });
    }
  } catch (error) {
    console.error('Error processing vault sale:', error);
    return res.status(500).json({
      success: false,
      error: 'An error occurred while processing vault sale'
    });
  }
});
# Process sale using vault token
import requests

def process_vault_sale(vault_id, amount):
    try:
        # vault_id should be the customer vault ID returned when adding a vault entry
        headers = {
            'Content-Type': 'application/json',
            'Authorization': '{user.privateApiKey}'
        }
        
        payload = {
            'amount': float(amount),
            'payment_details': {
                'customer_vault_id': vault_id
            }
        }
        
        response = requests.post(
            'https://secure.nmi.com/api/v5/payments/sale',
            json=payload,
            headers=headers
        )
        
        response_data = response.json()
        
        if response_data.get('response') == '1':
            print('Vault sale processed successfully')
            return {
                'transactionId': response_data.get('id'),
                'authCode': response_data.get('auth_code'),
                'responseText': response_data.get('response_text')
            }
        else:
            raise Exception(response_data.get('response_text', 'Failed to process vault sale'))
            
    except Exception as error:
        print(f'Error processing vault sale: {error}')
        raise error
// Process sale using vault token
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
import java.util.HashMap;

@PostMapping("/vault-sale")
public ResponseEntity<Map<String, Object>> processVaultSale(@RequestBody VaultSaleRequest request) {
    try {
        RestTemplate restTemplate = new RestTemplate();
        
        // vault_id should be the customer vault ID returned when adding a vault entry
        Map<String, Object> paymentDetails = new HashMap<>();
        paymentDetails.put("customer_vault_id", request.getCustomerVaultId());
        
        Map<String, Object> payload = new HashMap<>();
        payload.put("amount", request.getAmount());
        payload.put("payment_details", paymentDetails);
        
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "{user.privateApiKey}");
        
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(payload, headers);
        
        // Call NMI's v5 Payments API
        ResponseEntity<Map> response = restTemplate.exchange(
            "https://secure.nmi.com/api/v5/payments/sale",
            HttpMethod.POST,
            entity,
            Map.class
        );
        
        Map<String, Object> responseData = response.getBody();
        Map<String, Object> result = new HashMap<>();
        
        if ("1".equals(responseData.get("response"))) {
            result.put("success", true);
            result.put("transactionId", responseData.get("id"));
            result.put("authCode", responseData.get("auth_code"));
            result.put("responseText", responseData.get("response_text"));
        } else {
            result.put("success", false);
            result.put("error", responseData.getOrDefault("response_text", "Failed to process vault sale"));
        }
        
        return ResponseEntity.ok(result);
        
    } catch (Exception error) {
        System.err.println("Error processing vault sale: " + error.getMessage());
        
        Map<String, Object> errorResult = new HashMap<>();
        errorResult.put("success", false);
        errorResult.put("error", "An error occurred while processing vault sale");
        
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResult);
    }
}
// Process sale using vault token
using System.Text;
using System.Text.Json;

[HttpPost("vault-sale")]
public async Task<IActionResult> ProcessVaultSale([FromBody] VaultSaleRequest request)
{
    try
    {
        // customerVaultId should be the ID returned when adding a vault entry
        var payload = new
        {
            amount = request.Amount,
            payment_details = new
            {
                customer_vault_id = request.CustomerVaultId
            }
        };

        var jsonContent = new StringContent(
            JsonSerializer.Serialize(payload),
            Encoding.UTF8,
            "application/json"
        );

        _httpClient.DefaultRequestHeaders.Clear();
        _httpClient.DefaultRequestHeaders.Add("Authorization", "{user.privateApiKey}");

        var response = await _httpClient.PostAsync(
            "https://secure.nmi.com/api/v5/payments/sale",
            jsonContent
        );
        
        var responseContent = await response.Content.ReadAsStringAsync();
        var responseData = JsonSerializer.Deserialize<Dictionary<string, object>>(responseContent);
        
        if (responseData.TryGetValue("response", out var responseCode) && responseCode?.ToString() == "1")
        {
            return Ok(new
            {
                success = true,
                transactionId = responseData.GetValueOrDefault("id")?.ToString(),
                authCode = responseData.GetValueOrDefault("auth_code")?.ToString(),
                responseText = responseData.GetValueOrDefault("response_text")?.ToString()
            });
        }
        else
        {
            return BadRequest(new
            {
                success = false,
                error = responseData.GetValueOrDefault("response_text")?.ToString() ?? "Failed to process vault sale"
            });
        }
    }
    catch (Exception ex)
    {
        return StatusCode(500, new
        {
            success = false,
            error = "An error occurred while processing vault sale"
        });
    }
}
<?php
// Process sale using vault token
function processVaultSale($vaultId, $amount) {
    try {
        // $vaultId should be the customer vault ID returned when adding a vault entry
        $payload = [
            'amount' => (float) $amount,
            'payment_details' => [
                'customer_vault_id' => $vaultId
            ]
        ];
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 'https://secure.nmi.com/api/v5/payments/sale');
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Authorization: {user.privateApiKey}'
        ]);
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        if ($response === false) {
            throw new Exception('cURL error occurred');
        }
        
        // Parse the JSON response
        $responseData = json_decode($response, true);
        
        if ($responseData['response'] === '1') {
            return [
                'success' => true,
                'transactionId' => $responseData['id'],
                'authCode' => $responseData['auth_code'],
                'responseText' => $responseData['response_text']
            ];
        } else {
            return [
                'success' => false,
                'error' => $responseData['response_text'] ?? 'Failed to process vault sale'
            ];
        }
        
    } catch (Exception $error) {
        error_log('Error processing vault sale: ' . $error->getMessage());
        return [
            'success' => false,
            'error' => 'An error occurred while processing vault sale'
        ];
    }
}

// Example usage
function handleVaultSale() {
    $result = processVaultSale('cust_12345', '10.00');
    
    if ($result['success']) {
        echo 'Vault sale processed successfully' . PHP_EOL;
        echo 'Transaction ID: ' . $result['transactionId'] . PHP_EOL;
        echo 'Auth Code: ' . $result['authCode'] . PHP_EOL;
        echo 'Response: ' . $result['responseText'] . PHP_EOL;
    } else {
        echo 'Error: ' . $result['error'] . PHP_EOL;
    }
}

// REST API endpoint example
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/vault-sale') {
    header('Content-Type: application/json');
    
    $input = json_decode(file_get_contents('php://input'), true);
    
    if (!$input || !isset($input['customerVaultId']) || !isset($input['amount'])) {
        http_response_code(400);
        echo json_encode(['success' => false, 'error' => 'Invalid JSON input or missing required fields']);
        exit;
    }
    
    $result = processVaultSale($input['customerVaultId'], $input['amount']);
    
    if ($result['success']) {
        http_response_code(200);
    } else {
        http_response_code(500);
    }
    
    echo json_encode($result);
}
?>
<?php
// app/Http/Controllers/TransactionController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use App\Services\TransactionService;

class TransactionController extends Controller
{
    public function __construct(
        private TransactionService $transactionService
    ) {}

    /**
     * Process sale using vault token
     */
    public function processVaultSale(Request $request): JsonResponse
    {
        $request->validate([
            'customerVaultId' => 'required|string',
            'amount' => 'required|numeric|min:0.01'
        ]);

        try {
            $result = $this->transactionService->processVaultSale(
                $request->customerVaultId,
                $request->amount
            );

            if ($result['success']) {
                return response()->json([
                    'success' => true,
                    'transactionId' => $result['transactionId'],
                    'authCode' => $result['authCode'],
                    'responseText' => $result['responseText']
                ]);
            } else {
                return response()->json([
                    'success' => false,
                    'error' => $result['error']
                ], 400);
            }

        } catch (\Exception $e) {
            Log::error('Error processing vault sale: ' . $e->getMessage());
            
            return response()->json([
                'success' => false,
                'error' => 'An error occurred while processing vault sale'
            ], 500);
        }
    }
}

// app/Services/TransactionService.php
namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class TransactionService
{
    public function processVaultSale(string $vaultId, float $amount): array
    {
        try {
            // $vaultId should be the customer vault ID returned when adding a vault entry
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'Authorization' => '{user.privateApiKey}'
            ])->post('https://secure.nmi.com/api/v5/payments/sale', [
                'amount' => $amount,
                'payment_details' => [
                    'customer_vault_id' => $vaultId
                ]
            ]);

            $responseData = $response->json();

            if ($responseData['response'] === '1') {
                return [
                    'success' => true,
                    'transactionId' => $responseData['id'],
                    'authCode' => $responseData['auth_code'],
                    'responseText' => $responseData['response_text']
                ];
            } else {
                return [
                    'success' => false,
                    'error' => $responseData['response_text'] ?? 'Failed to process vault sale'
                ];
            }

        } catch (\Exception $e) {
            Log::error('Error processing vault sale: ' . $e->getMessage());
            return [
                'success' => false,
                'error' => 'An error occurred while processing vault sale'
            ];
        }
    }
}