# Migrating from S2S to the Orchestration API

A field-by-field guide for merchants moving from the legacy form-urlencoded S2S (Server-to-Server) API — the endpoint at `eu-test.oppwa.com` / `sandbox-card.peachpayments.com` — to the JSON Orchestration API.

## What this page covers
- Endpoint mapping from S2S `paymentType` values to Orchestration endpoints
- Authentication mapping (Bearer token / entityId → api-key + merchant connector account)
- Field-by-field request mapping: basic transaction fields, card details, wallets, customer, browser info (3DS 2.x), billing/shipping
- Use-case before/after examples: initial CIT (save card), subsequent MIT, CIT with saved card, external 3DS passthrough
- Custom parameters / metadata handling
- Response field mapping from S2S response fields to Orchestration response fields
- What you stop doing vs what you still need to do
- A minimum testing checklist

## Key concepts / endpoints
Endpoint mapping (S2S → Orchestration):
- `POST /v1/payments` (paymentType=DB / PA) → `POST /payments` — DB = authorise + capture; PA = auth-only via `capture_method: "manual"`
- `POST /v1/payments/{id}` (paymentType=CP) → `POST /payments/{id}/capture`
- `POST /v1/payments/{id}` (paymentType=RV) → `POST /payments/{id}/cancel` (void, pre-capture only)
- `POST /v1/payments/{id}` (paymentType=RF) → `POST /refunds`
- `GET /v1/payments/{id}` → `GET /payments/{id}?force_sync=true`
- `POST/GET /v1/threeDSecure` → not user-facing; Orchestration handles standalone 3DS when `authentication_type: "three_ds"`

Authentication:
- S2S `Authorization: Bearer <token>` → Orchestration `api-key: <merchant_api_key>` (per-merchant, not per-entity)
- S2S `entityId` (form param) → configured on the merchant connector account (MCA) as `connector_account_details.key1`
- One MCA per S2S entity; route between entities with Orchestration routing rules

Key request-field changes:
- Amounts move from major units (`92.00`) to minor units integer (`9200`)
- Card details nest under `payment_method_data.card.*` (`card_number`, `card_holder_name`, `card_exp_month`, `card_exp_year`, `card_cvc`); `payment_method` is `"card"`, `payment_method_type` is `"credit"`/`"debit"`
- `merchantTransactionId` → `connector_request_reference_id`; `descriptor` → `statement_descriptor_name`
- Browser info moves under `browser_info` (`accept_header`, `language`, `screen_height`, `user_agent`, etc.)

Mandates / MITs (derived by Orchestration, not set directly):
- Initial CIT: pass `setup_future_usage: "off_session"` + `customer_acceptance`; Orchestration sends `createRegistration=true` and the `standingInstruction.*` fields, and returns a `mandate_id` (store it). `connector_mandate_id` = S2S `registrationId`; `network_transaction_id` = CITI/traceId for Nedbank acquirers.
- Subsequent MIT: `mit_category` controls `standingInstruction.type` — `"recurring"` → RECURRING, `"installment"` → INSTALLMENT, `"unscheduled"` (default) → UNSCHEDULED, `"resubmission"` → UNSCHEDULED + reason RESUBMISSION.
- External 3DS passthrough: set `authentication_type: "no_three_ds"` and pass results via `three_ds_data`.

Response mapping highlights: S2S `id` → `connector_transaction_id`; `result.code` → classified `status` + `error_code`; `result.description` → `error_message`; `registrationId` → `connector_mandate_id`; `paymentBrand` → `payment_method_data.card.card_network`.

## Related
- [Gateway agnostic recurring payments](/gateway-agnostic.md): route saved-card MITs across multiple processors
- [Webhooks](/webhooks.md): receive `payment`/`refund` status events after migrating
- [Glossary](/glossary.md): definitions for CIT, MIT, mandate, MCA, and 3DS terms

---

Interactive version: https://playground.peachpayments.com/migration-s2s
