---
updatedAt: 2026-03-31T14:03:43.000Z
agentTools:
  projectIndex: https://docs.nmi.com/llms.txt
---

# Classic API Migration Playbook

# Payment API Migration

This document is a migration playbook for moving server-side payment submissions from the Classic API endpoint (`/api/transact.php`) to the modern JSON-encoded endpoints (`/api/v5/payments/...`).

## Overview of changes

<Cards columns={2}>
  <Card title="Endpoint Model Changes">
    From a single endpoint with a `type` parameter to explicit paths.
  </Card>

  <Card title="Request Format Changes">
    From flat form fields to JSON objects.
  </Card>

  <Card title="Authentication Transport Changes">
    From `security_key` parameter in the request body to `Authorization` header.
  </Card>

  <Card title="Response Handling Changes">
    From query-string style payloads to JSON payloads and HTTP status handling.
  </Card>
</Cards>

### What doesn't change

* If you already use Payment Component or Collect.js, that client-side token creation flow doesn't need to change.
* No need to generate new API keys or alter permissions, both are inherited by the new endpoints.

## Operation mapping

### Online Payments

Replace `type=<operation>` on `transact.php` with the matching new endpoint, for example:

* `sale` → `POST /api/v5/payments/sale`
* `capture` → `POST /api/v5/payments/{transaction_id}/capture`
* Single-transaction lookup → `GET /api/v5/payments/{transaction_id}`

Use the transaction identifier returned within the JSON response (`id`) as `{transaction_id}` in follow-on URLs. See our [API Reference](../reference/getting-started) for the full list of endpoints.

### In-Person Payments

If a payment is initiated on a **registered device** (for example, cloud terminal or PIN pad workflows), use the asynchronous device endpoints:

* `sale` → `POST /api/v5/devices/{device_id}/payment-requests/sale`
* `validate` → `POST /api/v5/devices/{device_id}/payment-requests/validate`

These requests return a payment request identifier when successful. To check the status and retrieve transaction details, poll:

* `GET /api/v5/devices/{device_id}/payment-requests/{request_id}`

Once complete, the response includes summary transaction information. For additional device management and operations endpoints, see the full [API Reference](../reference/create-device-payment-request-sale-v5).

## Payload reshaping

1. Open the [Code Examples](../docs/payment-code-examples) for representative **Classic API vs JSON** body comparisons.
2. Use the [API Reference](../reference/create-sale-v5) for the complete field catalog, optional fields, and processor-specific parameters.

Some changes to expect:

* Introduction of the `payment_details` object containing Credit Card, Check, or Token data.
* New `billing_address` and `shipping_address` objects to more easily pass and parse customer data.

## Response handling changes

### Classic API response pattern

* Query-string style (`response=...&responsetext=...`)

### JSON response pattern

* Standard transaction shape includes:
  * Resource name in the `object` field with a unique `id`
  * Maintained `response`, `response_text`, `response_code`
  * Nested objects matching requests (ex: `payment_details`, `billing_address`, etc.)

### Error handling

Use the response's HTTP status code (ex: 409, 404, etc.) alongside the error body together:

* Basic error identifiers provided in `type`, `error_code`, and `message`
* While `details` will elaborate more on things like validation errors

# What's next?

<Cards>
  <Card title="API Reference" href="../reference/create-sale-v5" icon="fa-magnifying-glass">
    Understand base URLs, authentication, and request/response formats.
  </Card>

  <Card title="Code Examples" href="../docs/payment-code-examples" icon="fa-terminal">
    Review and copy common payment flows with ready-to-use examples.
  </Card>
</Cards>

# FAQ

<Accordion title="Why does Authorization: Bearer fail after migrating my integration?">
  Payment endpoints expect your merchant private API key as the entire `Authorization` header value—do not provide `Bearer`, `ApiKey`, or any other scheme.
</Accordion>

<Accordion title="Does validate use the same permission as sale?">
  Validate uses the same permission inheritance as on the classic payments API for your key (including how validate relates to **sale**). You do **not** configure that separately—if it worked with your key on `transact.php`, the same rules apply on `/api/v5/payments/validate`.
</Accordion>

<Accordion title="I use Payment Component or Collect.js. What changes?">
  Only the server request to the gateway: pass `payment_details.payment_token` in your request body instead of posting `payment_token` to `transact.php`. Your Payment Component or Collect.js setup stays as-is.
</Accordion>

<Accordion title="Do I need to migrate my Classic Payment API to the JSON endpoints?">
  No. The Classic Payment API will continue to be fully supported. However, we recommend migrating to JSON endpoints to take advantage of a cleaner and more intuitive integration experience.
</Accordion>