# Checkout (New) - Complete API Reference > Fast, reliable payment collection with real-time webhooks and standard OAuth2 authentication. Built for modern e-commerce with 99.9% uptime and sub-second response times. ## Critical Information ### Amount Format - **Request**: String in minor currency units (e.g., `"2500"` for €25.00) - **Response**: Long/integer in minor currency units (e.g., `2500` for €25.00) - **NEVER use decimal format** like `"25.00"` - always use minor units ### Timestamp Format - All timestamps are **Unix epoch** (seconds since 1970-01-01) - Example: `1736433270` (not ISO 8601 like `"2024-01-15T10:30:00Z"`) ### Three Distinct Status Types Paysera Checkout has THREE separate status types - do not conflate them: 1. **Order Status** (4 values): `pending_payment`, `paid`, `canceled`, `closed` 2. **Payment Status** (13 values): `initiated`, `awaiting_authorization`, `authorized`, `processing`, `pending_settlement`, `on_hold`, `settled`, `failed`, `rejected`, `canceled`, `expired`, `refunded`, `chargeback` 3. **Payment Link Status** (4 values): `active`, `completed`, `expired`, `canceled` ## API Endpoints ### Available APIs | API | Base Path | Purpose | |-----|-----------|---------| | Orders | `/merchant-order/integration/v1/` | Create and manage payment orders | | Payment Links | `/checkout-payment-link/integration/v1/` | Generate shareable payment URLs | | Payment Methods | `/checkout-project/integration/v1/` | Query available payment options | ### Base URL ``` https://api.paysera.com ``` ## Obtaining Credentials Before integrating, you need API credentials from the Paysera Merchant Portal: | Credential | Description | |------------|-------------| | **Client ID** | Unique identifier for your integration | | **Client Secret** | Secret key for authentication (shown only once) | | **Project ID** | Identifier for your merchant project | **How to get credentials:** 1. Log in to the Paysera Merchant Portal 2. Navigate to your project settings 3. Open the **Integrations** tab 4. Copy your Client ID, Client Secret, and Project ID **Important**: Store your Client Secret immediately - it's only shown once. If lost, regenerate credentials. ## Authentication ### OAuth2 Client Credentials **Token Endpoint**: POST /auth/realms/Paysera/protocol/openid-connect/token **Request**: ``` Content-Type: application/x-www-form-urlencoded grant_type=client_credentials client_id=YOUR_CLIENT_ID client_secret=YOUR_CLIENT_SECRET ``` **Response**: ```json { "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600 } ``` **Usage**: Include in all API requests: ``` Authorization: Bearer ``` ## API Endpoints ### Create Order **POST** /merchant-order/integration/v1/orders **Request** (amounts in minor units as string): ```json { "project_id": "01990618-2c90-7103-9169-752bdaac7a52", "redirect_urls": { "success_url": "https://example.com/success", "failure_url": "https://example.com/failure", "callback_url": "https://example.com/webhook" }, "purchase": { "reference": "ORDER-12345", "amount": "2500", "currency": "EUR" } } ``` **Response** (amounts as Long, timestamps as Unix epoch): ```json { "id": "a6f2b8e3-5e5f-47d9-b13f-87ed2db2938a", "projectId": "01990618-2c90-7103-9169-752bdaac7a52", "status": "pending_payment", "amount": 2500, "currency": "EUR", "reference": "ORDER-12345", "amountPaid": 0, "balanceDue": 2500, "createdAt": 1736433270, "updatedAt": 1736433270 } ``` ### Get Order **GET** /merchant-order/integration/v1/orders/{id} **Response**: ```json { "id": "a6f2b8e3-5e5f-47d9-b13f-87ed2db2938a", "projectId": "01990618-2c90-7103-9169-752bdaac7a52", "status": "paid", "amount": 2500, "currency": "EUR", "reference": "ORDER-12345", "amountPaid": 2500, "balanceDue": 0, "createdAt": 1736433270, "updatedAt": 1736433570 } ``` ### Create Payment Link **POST** /checkout-payment-link/integration/v1/payment-links **Request**: ```json { "order_id": "a6f2b8e3-5e5f-47d9-b13f-87ed2db2938a", "name": "Order #12345", "amount": "2500", "currency": "EUR", "language": "en", "link_lifetime": 3600, "payer": { "name": "John Doe", "email": "john@example.com" } } ``` **Response**: ```json { "id": "c8d9e0f1-2a3b-4c5d-6e7f-8a9b0c1d2e3f", "link": { "url": "https://api.paysera.com/checkout-payment-link/payment-collection/v1/payment-links/abc123def456GhiJkl_mNOpQrStUvWxYz0123456" }, "status": "active", "amount": 2500, "currency": "EUR", "expiredAt": 1736436870, "createdAt": 1736433270 } ``` ### Get Payment Methods **GET** /checkout-project/integration/v1/methods?currency=EUR&country=LT **Response** (amounts in minor units): ```json { "items": [ { "key": "swedbank", "name": "Swedbank", "country_code": "LT", "min_amount": 1, "max_amount": 5000000 } ] } ``` ## Webhooks ### Configuration - Delivered to `callback_url` specified in order creation - Method: POST - Content-Type: application/json - Signature: `X-Paysera-Signature` header (HMAC-SHA256) ### Signature Verification ``` expected = HMAC-SHA256(raw_payload, client_secret) valid = constant_time_compare(expected, X-Paysera-Signature) ``` ### Event Types | Event | Type | Description | |-------|------|-------------| | `order.paid` | order | Order has been fully paid | | `order.pending_payment` | order | Order awaiting payment | | `payment_link.completed` | payment_link | Payment completed via this link | | `payment_link.expired` | payment_link | Payment link expired | | `payment_link.canceled` | payment_link | Payment link was canceled | ### Webhook Payload Structure ```json { "event": { "name": "order.paid", "type": "order", "timestamp": 1736433570 }, "order": { "id": "a6f2b8e3-5e5f-47d9-b13f-87ed2db2938a", "projectId": "01990618-2c90-7103-9169-752bdaac7a52", "status": "paid", "amount": 2500, "currency": "EUR", "reference": "ORDER-12345", "amountPaid": 2500, "balanceDue": 0, "createdAt": 1736433270, "updatedAt": 1736433570 }, "paymentLink": { "id": "c8d9e0f1-2a3b-4c5d-6e7f-8a9b0c1d2e3f", "status": "completed" } } ``` ### Retry Policy | Attempt | Delay | |---------|-------| | 1st retry | 5 seconds | | 2nd retry | 60 seconds | | 3rd retry | 3600 seconds (1 hour) | ## Status Reference ### Order Statuses (4 values) | Status | Code | Description | Terminal | |--------|------|-------------|----------| | Pending Payment | `pending_payment` | Order created, awaiting payment | No | | Paid | `paid` | Total amount = amount paid | No* | | Canceled | `canceled` | Manually canceled | Yes | | Closed | `closed` | No further operations allowed | Yes | *`paid` can transition to `canceled` or `closed` **Note**: `canceled` and `closed` are defined but not yet fully implemented. ### Payment Statuses (13 values) | Status | Description | Terminal | |--------|-------------|----------| | `initiated` | Payment request created | No | | `awaiting_authorization` | Requires SCA (3DS) | No | | `authorized` | Bank authorized | No | | `processing` | Internal processing | No | | `pending_settlement` | Clearing stage | No | | `on_hold` | Compliance review | No | | `settled` | Funds transferred | No* | | `failed` | Technical failure | Yes | | `rejected` | Bank refused | Yes | | `canceled` | Canceled | Yes | | `expired` | Timeout | Yes | | `refunded` | Returned to payer | Yes | | `chargeback` | Dispute initiated | Yes | *`settled` can transition to `refunded` or `chargeback` ### Payment Link Statuses (4 values) | Status | Code | Description | Terminal | |--------|------|-------------|----------| | Active | `active` | Link is valid and can be used | No | | Completed | `completed` | Payment completed via this link | Yes | | Expired | `expired` | Link has expired | Quasi* | | Canceled | `canceled` | Link was canceled | Yes | *`expired` can transition to `completed` if payment settles during bank flow **Important**: Payment links do NOT have a `failed` status. If a payment fails, the link remains `active` for retry. ## Error Handling ### Response Format ```json { "error": "error_code", "message": "Human-readable description", "details": [ {"field": "field_name", "message": "Field-specific error"} ] } ``` ### HTTP Status Codes | Code | Meaning | Retry | |------|---------|-------| | 200/201 | Success | - | | 400 | Bad Request | No | | 401 | Unauthorized | Maybe (refresh token) | | 403 | Forbidden | No | | 404 | Not Found | No | | 409 | Conflict | No | | 422 | Validation Error | No | | 429 | Rate Limited | Yes (use Retry-After) | | 5xx | Server Error | Yes (with backoff) | ### Common Error Codes | Error Code | HTTP | Description | |------------|------|-------------| | `invalid_client` | 401 | Invalid credentials | | `invalid_token` | 401 | Token expired or invalid | | `validation_error` | 422 | Field validation failed | | `not_found` | 404 | Resource not found | | `conflict` | 409 | Resource conflict (duplicate reference) | | `rate_limited` | 429 | Too many requests | ## Rate Limits | Consumer Group | Limit | |----------------|-------| | merchant | 50 requests/minute | | integration | 50 requests/minute | | public | 5000 requests/minute | ## PHP SDK ### Installation ```bash composer require paysera/lib-checkout-integration-sdk ``` ### Basic Usage ```php use Paysera\CheckoutSdk\SdkFacadeBuilder; use Paysera\CheckoutSdk\Entity\PaymentApiCredentials; $sdk = (new SdkFacadeBuilder())->build(); // Authenticate $credentials = new PaymentApiCredentials('client-id', 'client-secret'); $sdk->getAuthorizationFacade()->authorize($credentials); // Create payment (SDK uses integers for amounts) $paymentsFacade = $sdk->getPaymentsFacade(); $orderRequest = $paymentsFacade->buildPaymentOrderCreateRequest([ 'project_id' => 'project-id', 'redirect_urls' => [ 'success_url' => 'https://example.com/success', 'failure_url' => 'https://example.com/failure', 'callback_url' => 'https://example.com/webhook', ], 'purchase' => [ 'reference' => 'ORDER-001', 'amount' => 2500, // €25.00 in cents 'currency' => 'EUR', ], ]); $linkRequest = $paymentsFacade->buildPaymentLinkCreateRequest([ 'name' => 'Order #001', 'lifetime' => 3600, 'experience' => ['language' => 'en'], ]); $response = $paymentsFacade->initiatePayment($orderRequest, $linkRequest); $paymentUrl = $response->getPaymentUrl(); ``` ### Webhook Handling ```php $callbacksFacade = $sdk->getCallbacksFacade(); $callback = $callbacksFacade->processPaymentCallback($request); $status = $callback->getOrder()->getStatus(); $reference = $callback->getOrder()->getReference(); if ($status === 'paid') { // Order fully paid - fulfill the order } ``` ## Supported Currencies EUR, USD, GBP, PLN, CZK, HUF, RON, BGN, CHF, DKK, SEK, NOK, AUD, CAD, JPY **Note**: JPY has 0 minor units (no cents). ## Quick Start Flow 1. **Authenticate**: POST to token endpoint with client credentials 2. **Create Order**: POST to /merchant-order/integration/v1/orders with amount in minor units 3. **Create Payment Link**: POST to /checkout-payment-link/integration/v1/payment-links 4. **Redirect Customer**: Send customer to `link.url` 5. **Handle Webhook**: Verify signature, check order status for `paid` 6. **Fulfill Order**: When status is `paid`, process the order ## Documentation URLs - Overview: /checkout/v3/ - Getting Started: /checkout/v3/getting-started/ - Quickstart: /checkout/v3/getting-started/quickstart - Obtaining Credentials: /checkout/v3/getting-started/obtaining-credentials - Authentication: /checkout/v3/getting-started/authentication - API Integration: /checkout/v3/api-integration/ - Payment Orders: /checkout/v3/api-integration/payment-orders - Payment Links: /checkout/v3/api-integration/payment-links - Webhooks: /checkout/v3/api-integration/webhooks - Status Reference: /checkout/v3/reference/payment-statuses - Error Codes: /checkout/v3/reference/error-codes - PHP SDK: /checkout/v3/sdk/