# Merchant Managed

This guide provides enterprise merchants with a comprehensive integration path for Forter's Orchestration service, enabling unified payment processing with built-in fraud protection, predictive routing, and 3DS handling. The Orchestration API consolidates multiple payment operations into a single, cohesive workflow that replaces traditional PSP-specific integrations while maintaining enterprise-grade reliability and performance.

## [Integration Flow](https://docs.forter.com/merchant-managed#integration-flow) Integration Flow

Decline  
Managed Order Token  
Approve  
No  
Yes  
Customer enters card details  
Phase 1: Hosted Fields Tokenization  
Phase 2: Pre-Authorization Fraud Check  
Fraud Decision  
Reject Transaction  
Execute 3DS  
Phase 3: Create Payment  
Handle 3DS Challenge  
Challenge Success?  
Phase 4: Capture Payment

```mermaid
flowchart TD
A["Customer enters card details"] --> B["Phase 1: Hosted Fields Tokenization"]
B --> C["Phase 2: Pre-Authorization Fraud Check"]
C --> D{"Fraud Decision"}
D -- Decline --> E["Reject Transaction"]
D -- "Managed Order Token" --> F["Execute 3DS"]
D -- Approve --> G["Phase 3: Create Payment"]
F --> H["Handle 3DS Challenge"]
H --> I{"Challenge Success?"}
I -- No --> E
I -- Yes --> G
G --> L["Phase 4: Capture Payment"]
```

## [Phase 1: Hosted Fields Integration (Tokenization)](https://docs.forter.com/merchant-managed#phase-1-hosted-fields-integration-tokenization) Phase 1: Hosted Fields Integration (Tokenization)

Securely capture payment credentials using Forter's Hosted Fields, replacing PSP-native checkout fields.

### [1.1 Backend Session Key Generation](https://docs.forter.com/merchant-managed#11-backend-session-key-generation) 1.1 Backend Session Key Generation

Generate an authentication token for the frontend to initialize Hosted Fields.

**Endpoint:** POST /v1/tokenization/client-key

```javascript
// Node.js example
router.get('/client-key', async (req, res) => {
  const authString = Buffer.from(`${FORTER_SITE_ID}:${FORTER_SITE_SECRET}`).toString('base64');
  const authorization = `Basic ${authString}`;
  const response = await axios({
    method: 'POST',
    url: `${baseUrl}/v1/tokenization/client-key`,
    headers: {
      Authorization: authorization,
      'Content-Type': 'application/json',
    },
    data: { ttlMinutes: 60 },
  });
  res.json({ token: response.data.clientKey });
});
```

### [1.2 Frontend SDK Initialization](https://docs.forter.com/merchant-managed#12-frontend-sdk-initialization) 1.2 Frontend SDK Initialization

Include Forter's SDK on your checkout page:

```html
<script
  type="text/javascript"
  data-site-id="YOUR_SITE_ID"
  id="checkoutTools__script"
  src="https://sdk.checkouttools.com/v1.2/collect.js">
</script>
```

Initialize and configure Hosted Fields:

```javascript
const forterCollect = await window.checkoutTools.collect.init({
  environment: 'production',
  authToken: await getAuthToken(),
  onValidityChange: (fieldId, isValid, error) =>
    updateFieldValidation(fieldId, isValid, error),
  onCardBrandChange: (cardBrand) => updateCardBrandDisplay(cardBrand),
});

await forterCollect.addFields({
  'card-holder-name': {
    type: 'CARD_HOLDER_NAME',
    placeholder: 'Name on card',
    style: getFieldStyles(),
  },
  'card-number': {
    type: 'CARD_NUMBER',
    placeholder: '1234 5678 9012 3456',
    style: getFieldStyles(),
  },
  'card-expiry': {
    type: 'CARD_EXPIRATION_DATE',
    placeholder: 'MM/YY',
    style: getFieldStyles(),
  },
  'card-cvc': {
    type: 'CARD_CVC',
    placeholder: 'CVC',
    style: getFieldStyles(),
  },
});
```

### [1.3 Token Submission](https://docs.forter.com/merchant-managed#13-token-submission) 1.3 Token Submission

```javascript
const handlePaymentSubmit = async (formData) => {
  const tokenResult = await forterCollect.submit();
  if (!tokenResult.success) {
    handleValidationErrors(tokenResult.errors);
    return;
  }
  await processPayment({ ...formData, forterToken: tokenResult.token });
};
```

### [1.3.1 Upgrade Token (Optional)](https://docs.forter.com/merchant-managed#131-upgrade-token-optional) 1.3.1 Upgrade Token (Optional)

If you need to store the payment method and/or provision a network token for it, you must use the /upgrade endpoint.
Calling this endpoint creates a new multi-use token and invalidates the existing single-use token along with its CVC. You can also choose to provision a network token during the upgrade, allowing Forter to use it later during authorization.

**Example Request**

```json
{
  "token": "ftr1d8a56cfa6b3745a39e4a42d5ab1048c8",
  "networkToken": {
    "provision": true
  }
}
```

**Example Response**

```json
{
  "token": "ftr1efsdfew54wetg54ugdn58ns0482ko",
  "networkTokenStatus": {
    "created": true
  }
}
```

## [Phase 2: Pre-Authorization Fraud Check](https://docs.forter.com/merchant-managed#phase-2-pre-authorization-fraud-check) Phase 2: Pre-Authorization Fraud Check

Prevent fraud before initiating payment authorization.

### [2.1 Order Creation](https://docs.forter.com/merchant-managed#21-order-creation) 2.1 Order Creation

**Endpoint:** POST /v3/orders

Payload includes:

- Order ID
- Forter token
- Cart and pricing details
- Customer + billing/shipping info

Response:

- decision: APPROVE / DECLINE
- reason: (optional explanation)
- forterDecisionCorrelationId: Correlation ID to be passed to Phase 3 payment creation

Or, in case Forter recommends 3DS the response will include:

- Managed order token
- forterDecisionCorrelationId: Correlation ID to be passed to Phase 3 payment creation

### [2.2 Decision Logic](https://docs.forter.com/merchant-managed#22-decision-logic) 2.2 Decision Logic

- **APPROVE** → proceed to payment
- **DECLINE** → reject transaction
- **Managed Order Token** → Execute 3DS

## [Phase 3: Payment Processing via Orchestration](https://docs.forter.com/merchant-managed#phase-3-payment-processing-via-orchestration) Phase 3: Payment Processing via Orchestration

Execute payments through Forter's unified orchestration layer with 3DS and routing support.

Include a unique idempotency-key header (e.g. a UUID) on each request. Reusing the same key for a retry ensures we return the original result instead of executing the operation again.

### [3.1 Create Payment](https://docs.forter.com/merchant-managed#31-create-payment) 3.1 Create Payment

**Endpoint:** POST /api/payments

Include the Forter orderId from Phase 2 in the request body to link the payment to the prior fraud assessment.

The forterDecisionCorrelationId field is **required** for Merchant Managed integrations. It links the payment to the pre-authorization fraud decision obtained in Phase 2, enabling Forter to correlate the authorization with the risk assessment.

If the Phase 2 order creation response includes a managedOrderToken, you **must** pass it in the Create Payment request.

Request fields:

- orderId — The Forter order ID from Phase 2
- amount — Payment amount in smallest currency unit (e.g. cents)
- currency — ISO 4217 currency code (e.g. usd)
- captureMethod — automatic for immediate capture or manual for a manual capture
- confirm — Set to true for immediate authorization or set to false to send another confirm call before authorization
- forterDecisionCorrelationId — Correlation ID from the Phase 2 fraud decision response
- managedOrderToken — If returned in the Phase 2 response, must be included here
- paymentMethod.type — Payment method type (e.g. token)
- paymentMethod.forterTokenString — The Forter token obtained from Phase 1
- connectionInformation.customerIp — IP address of the customer
- browserInfo.userAgent — User agent string of the customer's browser
- cartItems — List of cart items, each with name, price, quantity, and type
- shipping.deliveryMethod — Delivery method (e.g. standard)
- shipping.deliveryType — Delivery type (e.g. digital)
- customer.email — Customer email address
- customer.firstName — Customer first name
- customer.lastName — Customer last name

```json
{
  "orderId": "{{orderId}}",
  "amount": 1099,
  "currency": "USD",
  "captureMethod": "automatic",
  "confirm": true,
  "forterDecisionCorrelationId": "{{correlationId}}",
  "managedOrderToken": "{{managedOrderToken}}",
  "paymentMethod": {
    "type": "token",
    "forterTokenString": "{{paymentToken}}"
  },
  "connectionInformation": {
    "customerIP": "127.0.0.2"
  },
  "browserInfo": {
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
  },
  "cartItems": [
    {
      "name": "testItem",
      "price": 1099,
      "quantity": 1,
      "type": "TANGIBLE"
    }
  ],
  "shipping": {
    "deliveryMethod": "Standard",
    "deliveryType": "DIGITAL"
  },
  "customer": {
    "email": "customer@example.com",
    "firstName": "John",
    "lastName": "Smith"
  }
}
```

### [3.2 Confirm Payment](https://docs.forter.com/merchant-managed#32-confirm-payment) 3.2 Confirm Payment

Use this step when confirm was set to false.

**Endpoint:** POST /api/payments/:id/confirm

Response returns final status: authorized or failed

### [3.3 Capture Authorized Payment](https://docs.forter.com/merchant-managed#33-capture-authorized-payment) 3.3 Capture Authorized Payment

Use this step when captureMethod was set to manual.

**Endpoint:** POST /api/payments/:id/capture

```json
{
  "amount": 10993
}
```

### [3.4 Cancel Payment](https://docs.forter.com/merchant-managed#34-cancel-payment) 3.4 Cancel Payment

Cancel a payment that has not yet been captured.

**Endpoint:** POST /api/payments/:id/cancel

```json
{
  "reason": "requested_by_customer"
}
```

## [Phase 4: Refunds](https://docs.forter.com/merchant-managed#phase-4-refunds) Phase 4: Refunds

**Full Refund**

Issue a reversal for a captured payment. Omit amount for a full refund.

Forter automatically determines the correct operation based on the transaction's settlement status — if the payment has not yet settled with the PSP, Forter will execute a void on your behalf. If it has settled, a refund is issued. This distinction is handled internally and requires no changes to your integration.

**Note:** This behavior is particularly relevant for PSPs, where sending a refund against an unsettled transaction would otherwise result in a failure at the PSP level.

**Partial Refund**

To issue a partial refund, include the amount field in your request. Forter will apply the same settlement-status check — if the transaction has settled, the partial refund is processed normally.
If the transaction has not yet settled, partial refunds are not possible and Forter will return an error. In that case, you can wait for the next settlement cycle — once the transaction has settled (according to your settlement cycles), retry the partial refund using POST /api/refunds

**Endpoint:** POST /api/refunds

```json
{
  "paymentId": "{{paymentId}}",
  "amount": 500,
  "reason": "requested_by_customer"
}
```

**Example Response**

```json
{
  "id": "ref_abc123",
  "amount": 500,
  "currency": "USD",
  "status": "succeeded",
  "reason": "requested_by_customer",
  "createdAt": "2025-07-14T12:34:56.789Z"
}
```

You can also retrieve refund details using GET /api/refunds/{id} or list all refunds for a payment using GET /api/refunds?paymentId={paymentId}.

## [Phase 5: Automatic Retry Logic – Predictive Payment Routing (PPR)](https://docs.forter.com/merchant-managed#phase-5-automatic-retry-logic-predictive-payment-r) Phase 5: Automatic Retry Logic – Predictive Payment Routing (PPR)

If the selected PSP declines or fails, Forter automatically generates a new routing recommendation:

1. The previous PSP + failure reason is sent to PPR
2. The next best PSP is returned based on live success metrics
3. Forter retries authorization with the new PSP transparently
4. Retries are idempotent and bounded by configurable limits

This is an internal process and does not require any merchant action.

## [Phase 6: Webhooks](https://docs.forter.com/merchant-managed#phase-6-webhooks) Phase 6: Webhooks

Forter delivers asynchronous updates for every lifecycle event:

| Event Type        | Description                                           |
|-------------------|------------------------------------------------------|
| payment.authorized | Payment successfully authorized                        |
| payment.captured   | Funds successfully captured                            |
| payment.failed      | Payment or capture failed                             |
| payment.cancelled   | Payment was cancelled (by merchant or by Forter)    |
| refund.succeeded    | Refund processed successfully                          |
| refund.failed       | Refund failed to process                              |

**Example Webhook Payload**

```json
{
  "type": "payment.authorized",
  "eventId": "123456",
  "timestamp": "2024-11-07T05:31:56Z",
  "data": {
    "paymentId": "PAY-9981",
    "processor": "adyen"
  }
}
```

Forter webhooks include x-forter-signature and x-forter-timestamp headers for validation.

## [Phase 7: Implementation Notes](https://docs.forter.com/merchant-managed#phase-7-implementation-notes) Phase 7: Implementation Notes

- Forter's Hosted Fields must be used for PCI compliance - merchants are never exposed to raw PCI data
- Single-use Forter Token expires within a maximum of 24 hours. In case the customer chooses to store the payment method, you can upgrade to a long-lived token using the Forter Tokenization API
- Each transaction is idempotent by idempotency key to prevent double charges

---
