[Tech Spec] Ppro — CreateClientAuthenticationToken
- Dominant language
- Python
- Stars
- 4
- Forks
- 6
- PR merge metrics
- No merged PRs in 30d
Description
# Ppro — CreateClientAuthenticationToken
**Complexity:** low
**Generated by:** Grace pipeline run `run-2026-05-13T11-34-52-053Z-f3ed51`
## Summary
Implement CreateClientAuthenticationToken payment method for Ppro connector. Ppro CreateClientAuthenticationToken — Technical Specification
## Scope
# Ppro CreateClientAuthenticationToken — Technical Specification
## 1. Connector Profile
| Field | Value |
|---|---|
| **Connector Name** | Ppro |
| **Primary Flow Scope** | CreateClientAuthenticationToken (MerchantAuthenticationService) |
| **API Family** | REST/JSON over HTTPS |
| **Production Host** | `https://api.eu.ppro.com` |
| **Sandbox Host** | `https://api.sandbox.eu.ppro.com` |
| **Currency Unit** | Minor (amounts expressed as integer minor units, e.g. 1000 = €10.00) |
Ppro is a white-label payment service provider and local payment method aggregator. It routes payments across BANCONTACT, IDEAL, BLIK, ALIPAY, WECHATPAY, MBWAY, SATISPAY, WERO, TRUSTLY, UPI, and others through a single API. The `CreateClientAuthenticationToken` flow initialises a Ppro checkout session that returns a `sessionId` (and optional `sessionToken`) used to mount Ppro's hosted checkout page or client-side SDK.
---
## 2. Authentication
| Field | Value |
|---|---|
| **Scheme** | Bearer Token + Merchant-Id header |
| **Authorization header** | `Authorization: Bearer {api_key}` |
| **Merchant header** | `Merchant-Id: {merchant_id}` |
| **Content-Type** | `application/json` |
| **Credentials required** | `api_key` (Secret), `merchant_id` (Secret) |
| **Optional idempotency key** | `Request-Idempotency-Key` header (UUID, optional per request) |
**Implementation notes:**
- The `api_key` is issued per merchant by Ppro and must be kept server-side.
- `merchant_id` is a Ppro-assigned identifier; both are present in `ConnectorSpecificConfig::Ppro`.
- All Ppro endpoints require both headers; omitting either yields a `401 Unauthorized`.
---
## 3. Supported Flows
| Flow | HTTP | Path | Notes |
|---|---|---|---|
| **CreateClientAuthenticationToken** | POST | `/v1/checkout-sessions` | Creates a checkout session; returns `sessionId` + optional `sessionToken` for SDK init |
| Authorize | POST | `/v1/payment-charges` | Direct payment charge creation |
| PSync | GET | `/v1/paym
## Out of Scope
Not specified in techspec
## Technical Constraints
- Follow existing connector patterns in the codebase
---
## Full Tech Spec
# Ppro CreateClientAuthenticationToken — Technical Specification
## 1. Connector Profile
| Field | Value |
|---|---|
| **Connector Name** | Ppro |
| **Primary Flow Scope** | CreateClientAuthenticationToken (MerchantAuthenticationService) |
| **API Family** | REST/JSON over HTTPS |
| **Production Host** | `https://api.eu.ppro.com` |
| **Sandbox Host** | `https://api.sandbox.eu.ppro.com` |
| **Currency Unit** | Minor (amounts expressed as integer minor units, e.g. 1000 = €10.00) |
Ppro is a white-label payment service provider and local payment method aggregator. It routes payments across BANCONTACT, IDEAL, BLIK, ALIPAY, WECHATPAY, MBWAY, SATISPAY, WERO, TRUSTLY, UPI, and others through a single API. The `CreateClientAuthenticationToken` flow initialises a Ppro checkout session that returns a `sessionId` (and optional `sessionToken`) used to mount Ppro's hosted checkout page or client-side SDK.
---
## 2. Authentication
| Field | Value |
|---|---|
| **Scheme** | Bearer Token + Merchant-Id header |
| **Authorization header** | `Authorization: Bearer {api_key}` |
| **Merchant header** | `Merchant-Id: {merchant_id}` |
| **Content-Type** | `application/json` |
| **Credentials required** | `api_key` (Secret), `merchant_id` (Secret) |
| **Optional idempotency key** | `Request-Idempotency-Key` header (UUID, optional per request) |
**Implementation notes:**
- The `api_key` is issued per merchant by Ppro and must be kept server-side.
- `merchant_id` is a Ppro-assigned identifier; both are present in `ConnectorSpecificConfig::Ppro`.
- All Ppro endpoints require both headers; omitting either yields a `401 Unauthorized`.
---
## 3. Supported Flows
| Flow | HTTP | Path | Notes |
|---|---|---|---|
| **CreateClientAuthenticationToken** | POST | `/v1/checkout-sessions` | Creates a checkout session; returns `sessionId` + optional `sessionToken` for SDK init |
| Authorize | POST | `/v1/payment-charges` | Direct payment charge creation |
| PSync | GET | `/v1/payment-charges/{id}` | Fetch charge status by Ppro charge ID |
| Capture | POST | `/v1/payment-charges/{id}/captures` | Manual capture of an authorised charge |
| Void | POST | `/v1/payment-charges/{id}/voids` | Cancel/void an authorised charge |
| Refund | POST | `/v1/payment-charges/{id}/refunds` | Create a refund against a captured charge |
| RSync | GET | `/v1/payment-charges/{id}` | Fetch refund status (same endpoint, check `refunds[]`) |
| SetupMandate | POST | `/v1/payment-agreements` | Create a recurring payment agreement |
| RepeatPayment | POST | `/v1/payment-agreements/{id}/payment-charges` | Charge against an existing agreement |
| Webhooks | POST | _(merchant-configured URL)_ | PPRO pushes CloudEvents-formatted events |
---
## 4. Request Schema Highlights — CreateClientAuthenticationToken
### Endpoint
```
POST {base_url}/v1/checkout-sessions
Content-Type: application/json
Authorization: Bearer {api_key}
Merchant-Id: {merchant_id}
```
### Request Body
```json
{
"amount": {
"currency": "EUR",
"value": 1000
},
"paymentMethod": "IDEAL",
"merchantPaymentChargeReference": "order-ref-001",
"consumer": {
"email": "user@example.com",
"country": "NL"
},
"authenticationSettings": [
{
"type": "REDIRECT",
"settings": {
"returnUrl": "https://merchant.example.com/return"
}
}
],
"webhooksUrl": "https://merchant.example.com/webhook"
}
```
### Field Reference
| Field | Type | Required | Notes |
|---|---|---|---|
| `amount.currency` | string (ISO 4217) | yes | e.g. `"EUR"`, `"USD"` |
| `amount.value` | integer (minor units) | yes | e.g. `1000` = €10.00 |
| `paymentMethod` | string enum | no | Optional at session creation; can be fixed or left open for SDK to select. One of: `BANCONTACT`, `IDEAL`, `BLIK`, `ALIPAY`, `WECHATPAY`, `MBWAY`, `SATISPAY`, `WERO`, `TRUSTLY`, `UPI` |
| `merchantPaymentChargeReference` | string | yes | Merchant-generated unique reference for the payment |
| `consumer.email` | string (email) | no | Consumer's email address |
| `consumer.country` | string (ISO 3166-1 alpha-2) | no | Consumer's country code |
| `consumer.name` | string | no | Consumer's full name |
| `consumer.merchantConsumerReference` | string | no | Required by certain PMs (e.g. Trustly) for consumer identification |
| `authenticationSettings[].type` | enum | no | `REDIRECT` (currently supported); future: `SCAN_CODE`, `MULTI_FACTOR`, `APP_NOTIFICATION`, `APP_INTENT` |
| `authenticationSettings[].settings.returnUrl` | string (URL) | no | Required when type is `REDIRECT`; consumer is redirected here after authentication |
| `webhooksUrl` | string (URL) | no | Override webhook delivery URL for this session |
| `paymentDescriptor` | string | no | Soft descriptor shown on consumer statement |
| `paymentMedium` | enum | no | `ECOMMERCE` (default), `MOTO`, `POS` |
**Idempotency:** Include `Request-Idempotency-Key: ` header to safely retry session creation.
---
## 5. Response Schema Highlights
### Success Response (HTTP 200 / 201)
```json
{
"sessionId": "sess_abc123def456",
"sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresAt": "2026-05-13T12:30:00Z",
"checkoutUrl": "https://checkout.ppro.com/session/sess_abc123def456",
"status": "CREATED"
}
```
### Key Response Fields
| Field | Type | Description |
|---|---|---|
| `sessionId` | string | Unique Ppro session identifier; used as the `ConnectorSpecific` response `session_id` |
| `sessionToken` | string (JWT, Secret) | Short-lived token for client-side SDK initialisation; may be absent for redirect-only flows |
| `expiresAt` | string (ISO 8601) | Session expiry timestamp |
| `checkoutUrl` | string (URL) | Full redirect URL to Ppro's hosted checkout page; client should redirect to this |
| `status` | string enum | `CREATED` on success |
### UCS Response Mapping
The `sessionId` and `sessionToken` are surfaced as `ClientAuthenticationTokenData::ConnectorSpecific(ConnectorSpecificClientAuthenticationResponse::Ppro(...))` containing:
- `session_id: String` — the Ppro `sessionId`
- `session_token: Secret` — the Ppro `sessionToken` (if present)
- `checkout_url: Option` — the `checkoutUrl` for redirect flows
---
## 6. Error Handling
### Error Response Body
```json
{
"status": 400,
"failureMessage": "Invalid paymentMethod value: UNSUPPORTED"
}
```
### HTTP Status → Error Cause Mapping
| HTTP | `status` (body) | Cause |
|---|---|---|
| 400 | 400 | Malformed request; invalid field value, missing required field |
| 401 | 401 | Missing or invalid `Authorization` header; invalid `api_key` |
| 403 | 403 | `Merchant-Id` not authorised for the requested payment method or operation |
| 404 | 404 | Referenced resource (session, charge) not found |
| 409 | 409 | Idempotency conflict — same `Request-Idempotency-Key` with different request body |
| 422 | 422 | Semantically invalid request (e.g. amount below minimum, unsupported currency for PM) |
| 429 | 429 | Rate limit exceeded |
| 500 | 500 | Ppro internal server error; safe to retry with backoff |
**UCS Error Parsing:** The existing `PproErrorResponse { status: u16, failure_message: String }` struct handles the error body. The `status` field from the body maps to `ErrorResponse.code`; `failure_message` maps to `ErrorResponse.message`.
---
## 7. Webhooks / Async Notifications
### Subscription
Webhook delivery URL is configured per-merchant in the Ppro merchant portal, or overridden per-request via the `webhooksUrl` field in the session creation request.
### Delivery Format
Ppro delivers CloudEvents v1.0-formatted JSON payloads over HTTP POST:
```json
{
"specversion": "1.0",
"type": "PAYMENT_CHARGE_SUCCESS",
"source": "ppro",
"id": "evt_abc123",
"time": "2026-05-13T10:00:00Z",
"data": {
"charge": {
"id": "chg_xyz789",
"status": "SUCCEEDED",
"amount": 1000,
"currency": "EUR"
}
}
}
```
### Signature Verification
- **Algorithm:** HMAC-SHA-256
- **Header:** `Webhook-Signature` (hex-encoded digest)
- **Message construction:** `{raw_body}.{webhook_secret_bytes}` (body bytes + `.` + secret bytes)
- **Verification:** `SHA256(body + "." + secret) == hex_decode(Webhook-Signature header)`
### Event Types
| Event type (`type` field) | UCS EventType |
|---|---|
| `PAYMENT_CHARGE_AUTHORIZATION_SUCCEEDED` | `PaymentIntentAuthorizationSuccess` |
| `PAYMENT_CHARGE_SUCCESS` | `PaymentIntentAuthorizationSuccess` |
| `PAYMENT_CHARGE_AUTHORIZATION_FAILED` | `PaymentIntentFailure` |
| `PAYMENT_CHARGE_FAILED` | `PaymentIntentFailure` |
| `PAYMENT_CHARGE_DISCARDED` | `PaymentIntentFailure` |
| `PAYMENT_CHARGE_CAPTURE_SUCCEEDED` | `PaymentIntentCaptureSuccess` |
| `PAYMENT_CHARGE_CAPTURE_FAILED` | `PaymentIntentCaptureFailure` |
| `PAYMENT_CHARGE_VOID_SUCCEEDED` | `PaymentIntentCancelled` |
| `PAYMENT_CHARGE_VOID_FAILED` | `PaymentIntentCancelFailure` |
| `PAYMENT_CHARGE_REFUND_SUCCEEDED` | `RefundSuccess` |
| `PAYMENT_CHARGE_REFUND_FAILED` | `RefundFailure` |
| `PAYMENT_AGREEMENT_ACTIVE` | `MandateActive` |
| `PAYMENT_AGREEMENT_FAILED` | `MandateFailed` |
| `PAYMENT_AGREEMENT_REVOKED_*` | `MandateRevoked` |
### Retry Policy
Ppro retries failed webhook deliveries with exponential backoff. The merchant should respond with HTTP 2xx within 5 seconds to acknowledge receipt.
### Documented Gaps
- The `CreateClientAuthenticationToken` flow (checkout session) does not have a dedicated session-status webhook; session lifecycle (expiry) is not notified via webhook.
- The `sessionToken` expiry is returned synchronously in the session response (`expiresAt`); no async notification is sent when it expires.
---
## 8. References
| Source | Details |
|---|---|
| Existing Ppro connector implementation | `crates/integrations/connector-integration/src/connectors/ppro.rs` |
| Ppro transformer types | `crates/integrations/connector-integration/src/connectors/ppro/transformers.rs` |
| ClientAuthenticationToken domain types | `crates/types-traits/domain_types/src/connector_types.rs` (lines 1603–1620, 3518–3590) |
| ConnectorSpecificConfig::Ppro | `crates/types-traits/domain_types/src/router_data.rs` (lines 275–279) |
| Sandbox base URL | `config/development.toml` — `ppro.base_url = "https://api.sandbox.eu.ppro.com"` |
| Nexinets ClientAuthenticationToken reference impl | `crates/integrations/connector-integration/src/connectors/nexinets.rs` (lines 520–540) |
| Revolut ClientAuthenticationToken reference impl | `crates/integrations/connector-integration/src/connectors/revolut.rs` (lines 295–320) |
| Ppro API Documentation (public) | `https://docs.ppro.com/api/` |
| Ppro Checkout Session API | `https://docs.ppro.com/api/#tag/Checkout-Sessions` |
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by locating the existing connector patterns for MerchantAuthenticationService and the Ppro CreateClientAuthenticationToken flow. Implement the POST /v1/checkout-sessions request, authentication, response mapping, and error handling described in the specification; done means the session_id, session_token, and checkout_url reach the corresponding connector-specific response and the documented failures map correctly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend, payments
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100