> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nymblecommerce.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Payments API Reference for Nymble Commerce

> REST API reference for Nymble Commerce payment processing — initiate hosted payment sessions, save payment methods, and retrieve saved cards for B2B checkout.

The Payments API handles card payment collection through hosted pages and saved payment methods (card-on-file). Nymble Commerce integrates with **Authorize.Net** and **WorldPay** as payment providers — your organization's active provider is configured in your tenant settings and used automatically unless you specify otherwise.

<Note>
  Raw card numbers are never sent to or stored by Nymble Commerce. All card data is submitted directly from your customer's browser to the payment provider's hosted page. Nymble Commerce receives only a token and masked card details after the transaction is complete.
</Note>

***

## Hosted payment flow

The standard card payment flow uses a provider-hosted page so that your application never handles raw card data.

<Steps>
  <Step title="Initiate a transaction setup">
    Call `POST /api/payments/worldpay/transaction-setup` with the customer number, the invoice amount, and a return URL. Nymble Commerce creates a transaction setup with the payment provider and returns a `HostedPaymentUrl` and a `TransactionSetupId`.
  </Step>

  <Step title="Redirect the customer">
    Redirect the customer's browser to the `HostedPaymentUrl`. The payment provider renders a secure, hosted payment form where the customer enters their card details.
  </Step>

  <Step title="Customer submits payment">
    The customer completes the payment form on the provider's hosted page. The provider processes the transaction directly.
  </Step>

  <Step title="Provider posts the callback">
    After the transaction completes (success or failure), the provider posts the result to Nymble Commerce's callback endpoint (`POST /api/payments/worldpay/callback`). Nymble Commerce records the payment against the invoice and updates the invoice status accordingly.
  </Step>

  <Step title="Customer is redirected back">
    The provider redirects the customer to the `ApplicationReturnUrl` you supplied in step 1. You can use this URL to display a payment confirmation or error message in your application.
  </Step>
</Steps>

<Tip>
  The `TransactionSetupId` is valid for **10 minutes**. If the customer does not complete the payment within that window, initiate a new transaction setup.
</Tip>

***

## Saved payment methods

You can save a customer's card as a payment method (card-on-file) to enable one-click checkout and recurring billing. Nymble Commerce stores only the payment provider's token and masked card details — never the raw card number.

* For **Authorize.Net**: you can save a card directly by posting card details to `POST /api/payments/payment-methods`. Authorize.Net tokenizes the card and returns a `PaymentProfileId`.
* For **WorldPay**: saving a card requires a redirect to a hosted page. `POST /api/payments/payment-methods` returns a `RequiresRedirect: true` response with a `RedirectUrl`. Send the customer to that URL to complete tokenization.

***

## The payment method object

<ResponseField name="id" type="string">
  Internal Nymble Commerce ID for this saved payment method.
</ResponseField>

<ResponseField name="customerNumber" type="string">
  The customer account this payment method belongs to.
</ResponseField>

<ResponseField name="paymentProfileId" type="string">
  The payment provider's identifier for this saved card profile. Use this ID when recording payments against an invoice.
</ResponseField>

<ResponseField name="customerProfileId" type="string">
  The payment provider's identifier for the customer profile that owns this payment method.
</ResponseField>

<ResponseField name="maskedCardNumber" type="string">
  The masked card number (e.g. `XXXX1234`).
</ResponseField>

<ResponseField name="cardType" type="string">
  Card brand (e.g. `Visa`, `Mastercard`, `AmericanExpress`, `Discover`).
</ResponseField>

<ResponseField name="expirationDate" type="string">
  Card expiry in `MMYY` or `MM/YYYY` format, as returned by the provider.
</ResponseField>

<ResponseField name="expMonth" type="integer">
  Expiry month as an integer (1–12).
</ResponseField>

<ResponseField name="expYear" type="integer">
  Expiry year as a four-digit integer.
</ResponseField>

<ResponseField name="billingAddress" type="object">
  The billing address associated with this card.

  <Expandable title="billingAddress fields" />
</ResponseField>

<ResponseField name="isDefault" type="boolean">
  Whether this is the customer's default payment method.
</ResponseField>

<ResponseField name="paymentProvider" type="string">
  The payment provider that issued this profile token (e.g. `AuthorizeNet`, `WorldPay`).
</ResponseField>

<ResponseField name="active" type="boolean">
  Whether this payment method is active.
</ResponseField>

<ResponseField name="networkTransactionId" type="string">
  Network transaction ID from the provider, used for subsequent card-on-file transactions.
</ResponseField>

***

## Endpoints

### Initiate a hosted payment session

Creates a WorldPay transaction setup and returns a URL to which you redirect the customer to complete payment. This is the first step in the [hosted payment flow](#hosted-payment-flow).

#### Request body

<ParamField body="customerNumber" type="string" required>
  The account number of the customer making the payment. Used to associate the transaction and any saved card with the correct customer profile.
</ParamField>

<ParamField body="transactionAmount" type="number" required>
  The amount to charge. Pass `0.00` if you are using this setup only to save a payment method without charging the customer.
</ParamField>

<ParamField body="applicationReturnUrl" type="string" required>
  The URL in your application to redirect the customer to after payment completes (whether successful or failed). The provider appends the transaction result as query parameters.
</ParamField>

<ParamField body="marketCode" type="string">
  WorldPay market code. Defaults to `Default`. Contact your Nymble Commerce account team if you need a custom market code.
</ParamField>

<ParamField body="isDefault" type="boolean">
  If the customer saves their card during this transaction, whether to set it as their default payment method. Defaults to `false`.
</ParamField>

#### Example request

```bash theme={null}
curl -X POST https://api.achievemomentum.com/api/payments/worldpay/transaction-setup \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "customerNumber": "CUST-1042",
    "transactionAmount": 479.30,
    "applicationReturnUrl": "https://yourapp.com/checkout/payment-result",
    "isDefault": false
  }'
```

#### Response

<ResponseField name="transactionSetupId" type="string">
  The transaction setup ID from the payment provider. Valid for **10 minutes**. Store this to correlate the provider callback with the payment attempt.
</ResponseField>

<ResponseField name="hostedPaymentUrl" type="string">
  The complete URL to redirect the customer to. This URL contains the setup ID and provider-specific parameters — do not modify it.
</ResponseField>

#### Example response

```json theme={null}
{
  "transactionSetupId": "ABC123DEF456GHI789",
  "hostedPaymentUrl": "https://certtransaction.hostedpayments.com/?TransactionSetupID=ABC123DEF456GHI789"
}
```

After receiving this response, redirect the customer's browser to `hostedPaymentUrl`:

```javascript theme={null}
// Example: redirect in a browser context
window.location.href = response.hostedPaymentUrl;
```

***

### Get saved payment methods for a customer

Retrieves all saved payment methods (cards on file) for a customer. Use the returned `paymentProfileId` values when recording a payment against an invoice via [`POST /api/invoices/{invoiceId}/payments`](/api-reference/invoices#record-an-offline-payment).

#### Path parameters

<ParamField path="customerNumber" type="string" required>
  The customer's account number.
</ParamField>

#### Example request

```bash theme={null}
curl https://api.achievemomentum.com/api/payments/CUST-1042/profiles \
  -H "Authorization: Bearer <token>"
```

#### Response

Returns `200 OK` with an array of [payment method objects](#the-payment-method-object).

```json theme={null}
[
  {
    "id": "pm-uuid-001",
    "customerNumber": "CUST-1042",
    "paymentProfileId": "1234567890",
    "customerProfileId": "9876543210",
    "maskedCardNumber": "XXXX4242",
    "cardType": "Visa",
    "expirationDate": "1226",
    "expMonth": 12,
    "expYear": 2026,
    "billingAddress": {
      "firstName": "Alex",
      "lastName": "Chen",
      "company": "Brightfield Supply Co.",
      "address1": "300 Commerce Blvd",
      "city": "Portland",
      "state": "OR",
      "zipCode": "97201",
      "country": "US"
    },
    "isDefault": true,
    "paymentProvider": "AuthorizeNet",
    "active": true
  },
  {
    "id": "pm-uuid-002",
    "customerNumber": "CUST-1042",
    "paymentProfileId": "1234567891",
    "customerProfileId": "9876543210",
    "maskedCardNumber": "XXXX1881",
    "cardType": "Mastercard",
    "expirationDate": "0827",
    "expMonth": 8,
    "expYear": 2027,
    "billingAddress": {
      "firstName": "Alex",
      "lastName": "Chen",
      "company": "Brightfield Supply Co.",
      "address1": "300 Commerce Blvd",
      "city": "Portland",
      "state": "OR",
      "zipCode": "97201",
      "country": "US"
    },
    "isDefault": false,
    "paymentProvider": "AuthorizeNet",
    "active": true
  }
]
```

***

### Save a payment method

Saves a payment method (tokenizes a card) for a customer. The behaviour differs by payment provider:

* **Authorize.Net**: card details are submitted directly in the request body. Authorize.Net tokenizes the card server-side and returns the saved payment method immediately. `RequiresRedirect` is `false`.
* **WorldPay**: a direct card submission is not supported. The response contains `RequiresRedirect: true` and a `RedirectUrl`. Redirect the customer to that URL to enter their card details on the WorldPay hosted page.

<Warning>
  Only use the direct card submission flow (Authorize.Net) from a server-side integration where you control the PCI scope. For customer-facing web applications, prefer the hosted payment flow via `POST /api/payments/worldpay/transaction-setup` to avoid handling raw card data.
</Warning>

#### Request body

<ParamField body="customerNumber" type="string" required>
  The account number of the customer whose card is being saved.
</ParamField>

<ParamField body="emailAddress" type="string" required>
  Customer's email address, used to create or match the customer profile with the payment provider.
</ParamField>

<ParamField body="cardNumber" type="string" required>
  Full card number. Only used for Authorize.Net (direct flow). For WorldPay, any value is acceptable — the redirect flow ignores this field.
</ParamField>

<ParamField body="expirationMonth" type="string" required>
  Two-digit expiry month (e.g. `09`).
</ParamField>

<ParamField body="expirationYear" type="string" required>
  Four-digit expiry year (e.g. `2027`).
</ParamField>

<ParamField body="cardCode" type="string" required>
  Card security code (CVV/CVC). Required for Authorize.Net. Not stored after tokenization.
</ParamField>

<ParamField body="billingAddress" type="object" required>
  The billing address for the card.

  <Expandable title="billingAddress fields" />
</ParamField>

<ParamField body="isDefault" type="boolean">
  Set to `true` to make this the customer's default payment method. Defaults to `false`.
</ParamField>

<ParamField body="paymentProvider" type="string">
  Specify which payment provider to use (`AuthorizeNet` or `WorldPay`). When omitted, uses the organization's default active provider.
</ParamField>

<ParamField body="appUrl" type="string">
  For WorldPay (redirect flow) — the URL in your application to return the customer to after they save their card. Defaults to `http://localhost:3000/payment-success` when omitted.
</ParamField>

#### Example request (Authorize.Net — direct)

```bash theme={null}
curl -X POST https://api.achievemomentum.com/api/payments/payment-methods \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "customerNumber": "CUST-1042",
    "emailAddress": "alex.chen@brightfieldsupply.com",
    "cardNumber": "4111111111111111",
    "expirationMonth": "12",
    "expirationYear": "2027",
    "cardCode": "123",
    "billingAddress": {
      "firstName": "Alex",
      "lastName": "Chen",
      "company": "Brightfield Supply Co.",
      "address1": "300 Commerce Blvd",
      "city": "Portland",
      "state": "OR",
      "zipCode": "97201",
      "country": "US"
    },
    "isDefault": true,
    "paymentProvider": "AuthorizeNet"
  }'
```

#### Example request (WorldPay — redirect)

```bash theme={null}
curl -X POST https://api.achievemomentum.com/api/payments/payment-methods \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "customerNumber": "CUST-1042",
    "emailAddress": "alex.chen@brightfieldsupply.com",
    "cardNumber": "",
    "expirationMonth": "01",
    "expirationYear": "2030",
    "cardCode": "",
    "billingAddress": {
      "firstName": "Alex",
      "lastName": "Chen",
      "address1": "300 Commerce Blvd",
      "city": "Portland",
      "state": "OR",
      "zipCode": "97201",
      "country": "US"
    },
    "isDefault": false,
    "paymentProvider": "WorldPay",
    "appUrl": "https://yourapp.com/payment-methods/saved"
  }'
```

#### Response

<ResponseField name="requiresRedirect" type="boolean">
  `false` for Authorize.Net (card saved immediately). `true` for WorldPay (customer must complete a hosted page).
</ResponseField>

<ResponseField name="redirectUrl" type="string">
  The URL to redirect the customer to (WorldPay only). `null` for Authorize.Net.
</ResponseField>

<ResponseField name="provider" type="string">
  The payment provider used for this request.
</ResponseField>

<ResponseField name="paymentMethod" type="object">
  The saved payment method (Authorize.Net only, when `requiresRedirect` is `false`). See the [payment method object](#the-payment-method-object) for full field details.
</ResponseField>

#### Example response (Authorize.Net — direct)

```json theme={null}
{
  "requiresRedirect": false,
  "redirectUrl": null,
  "provider": "AuthorizeNet",
  "paymentMethod": {
    "id": "pm-uuid-003",
    "customerNumber": "CUST-1042",
    "paymentProfileId": "1234567892",
    "customerProfileId": "9876543210",
    "maskedCardNumber": "XXXX1111",
    "cardType": "Visa",
    "expirationDate": "1227",
    "expMonth": 12,
    "expYear": 2027,
    "billingAddress": {
      "firstName": "Alex",
      "lastName": "Chen",
      "company": "Brightfield Supply Co.",
      "address1": "300 Commerce Blvd",
      "city": "Portland",
      "state": "OR",
      "zipCode": "97201",
      "country": "US"
    },
    "isDefault": true,
    "paymentProvider": "AuthorizeNet",
    "active": true
  }
}
```

#### Example response (WorldPay — redirect)

```json theme={null}
{
  "requiresRedirect": true,
  "redirectUrl": "https://certtransaction.hostedpayments.com/?TransactionSetupID=XYZ987ABC654",
  "provider": "WorldPay",
  "paymentMethod": null
}
```

When `requiresRedirect` is `true`, redirect the customer's browser to `redirectUrl`:

```javascript theme={null}
if (response.requiresRedirect) {
  window.location.href = response.redirectUrl;
}
```

***

### WorldPay payment callback

WorldPay posts to this endpoint after a hosted payment transaction completes (successfully or otherwise). **Do not call this endpoint directly from your application** — it is called by WorldPay's payment infrastructure after every transaction initiated via `POST /api/payments/worldpay/transaction-setup`.

When Nymble Commerce receives a successful callback, it:

1. Records the payment against the associated invoice.
2. Updates the invoice status to `PartiallyPaid` or `Paid`.
3. Saves the card as a payment method if the customer opted in during the hosted page flow.

<Note>
  Document this endpoint if you operate a proxy or firewall in front of the Nymble Commerce API. You must allow inbound `POST` requests from WorldPay's IP ranges to this path.
</Note>

#### What WorldPay sends

WorldPay posts a form-encoded payload containing the `TransactionSetupID`, approval code, card details, and transaction result. Nymble Commerce validates the payload against the original transaction setup and processes the result accordingly.

You do not need to handle or forward this callback — it is consumed entirely by Nymble Commerce. Your application is notified of the result via the `ApplicationReturnUrl` redirect you supplied when creating the transaction setup.
