{"id":20629924,"url":"https://github.com/academe/omnipay-payone","last_synced_at":"2026-04-02T02:03:08.339Z","repository":{"id":55954118,"uuid":"64026147","full_name":"academe/OmniPay-Payone","owner":"academe","description":"A PAYONE gateway driver for the OmniPay framework","archived":false,"fork":false,"pushed_at":"2024-04-08T11:28:58.000Z","size":240,"stargazers_count":15,"open_issues_count":9,"forks_count":16,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-17T20:50:38.226Z","etag":null,"topics":["omnipay","payment-gateway","payone","payone-api","php"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/academe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-07-23T16:53:53.000Z","updated_at":"2024-02-13T16:05:05.000Z","dependencies_parsed_at":"2025-04-15T18:19:36.645Z","dependency_job_id":"cbbaee25-307f-4b45-ac52-02bd9f02476f","html_url":"https://github.com/academe/OmniPay-Payone","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/academe/OmniPay-Payone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/academe%2FOmniPay-Payone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/academe%2FOmniPay-Payone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/academe%2FOmniPay-Payone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/academe%2FOmniPay-Payone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/academe","download_url":"https://codeload.github.com/academe/OmniPay-Payone/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/academe%2FOmniPay-Payone/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260269429,"owners_count":22983645,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["omnipay","payment-gateway","payone","payone-api","php"],"created_at":"2024-11-16T14:06:26.163Z","updated_at":"2026-04-02T02:03:08.254Z","avatar_url":"https://github.com/academe.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![GitHub license](https://img.shields.io/badge/license-GPL-blue.svg)](https://raw.githubusercontent.com/academe/OmniPay-Payone/master/LICENSE.md)\n[![Packagist](https://img.shields.io/packagist/v/academe/omnipay-payone.svg?maxAge=2592000)](https://packagist.org/packages/academe/omnipay-payone)\n[![GitHub issues](https://img.shields.io/github/issues/academe/OmniPay-Payone.svg)](https://github.com/academe/OmniPay-Payone/issues)\n[![Build Status](https://travis-ci.org/academe/OmniPay-Payone.svg?branch=issue29)](https://travis-ci.org/academe/OmniPay-Payone)\n\nTable of Contents\n=================\n\n  * [Table of Contents](#table-of-contents)\n  * [Omnipay: \u003ca href=\"https://www.payone.de/\"\u003ePAYONE\u003c/a\u003e](#omnipay-payone)\n    * [Installation](#installation)\n    * [Basic Usage](#basic-usage)\n      * [Gateway Background](#gateway-background)\n      * [Shop and Access API Versions](#shop-and-access-api-versions)\n      * [Extended Items (Order Lines)](#extended-items-order-lines)\n    * [The Shop Server API Gateway](#the-shop-server-api-gateway)\n      * [Server API Authorize Payment](#server-api-authorize-payment)\n      * [Server API Purchase](#server-api-purchase)\n      * [Server API Capture](#server-api-capture)\n      * [Server API Void](#server-api-void)\n      * [Server API Credit Card Check](#server-api-credit-card-check)\n    * [The Shop Front End API Gateway](#the-shop-front-end-api-gateway)\n      * [Front End Authorize](#front-end-authorize)\n      * [Front End Purchase](#front-end-purchase)\n      * [Front End Credit Card Check](#front-end-credit-card-check)\n    * [The Shop Client API Gateway](#the-shop-client-api-gateway)\n      * [Client API Credit Card Check](#client-api-credit-card-check)\n      * [Client API Authorize](#client-api-authorize)\n        * [Client completeAuthorize](#client-completeauthorize)\n      * [Client API Purchase](#client-api-purchase)\n    * [Notification Callback](#notification-callback)\n      * [completeAuthorize and completePurchase Methods](#completeauthorize-and-completepurchase-methods)\n  * [References](#references)\n\n# Omnipay: [PAYONE](https://www.payone.de/)\n\n**PAYONE driver for the Omnipay PHP payment processing library**\n\nWritten to specication:\n\n* *TECHNICAL REFERENCE PAYONE Platform Channel Client API* 1.28 (2016-05-09)\n* *TECHNICAL REFERENCE PAYONE Platform Channel Server API* 2.84 (2016-05-09)\n* *TECHNICAL REFERENCE PAYONE Platform Frontend* 2.40 (2016-05-09)\n\n[Omnipay 3.x](https://github.com/thephpleague/omnipay) is a framework agnostic, multi-gateway payment\nprocessing library for PHP 7.1+.\nThis package implements PAYONE support for [OmniPay](https://github.com/thephpleague/omnipay).\n\n![Alt text](docs/PAYONE_Logo_480.png?raw=true \"PAYONE\")\n\n## Installation\n\n**This is the `master` branch for the current Omnipay 3.x branch (tested against 3.0-beta.1).**\n**The older [2.x branch can be found here](https://github.com/academe/OmniPay-Payone/tree/2.x)**\n\nOmnipay is installed via [Composer](http://getcomposer.org/). To install, add it\nto your `composer.json` file:\n\n```json\n{\n    \"require\": {\n        \"academe/omnipay-payone\": \"~3.0\"\n    }\n}\n```\n\nor direct from [packagist](https://packagist.org/packages/academe/omnipay-payone)\n\n    composer require \"academe/omnipay-payone: ~3.0\"\n\nAnd run composer to update your dependencies:\n\n    $ curl -s http://getcomposer.org/installer | php\n    $ php composer.phar update\n\n## Basic Usage\n\nThe following gateways are provided by this package:\n\n* Payone_ShopServer\n* Payone_ShopFrontend\n* Payone_ShopClient\n\nFor general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay)\nrepository. You will find more specific details can be found below.\n\n### Gateway Background\n\nThe [PAYONE API](https://www.payone.de/en/platform-integration/interfaces/) has three main access points\nof interest to e-commerce:\n\n* **Server API** - for interacting directly with server without user intervention.\n* **Frontend API** - for delivering hosted credit card (CC) forms to the user (iframe or redirect).\n* **Client API** - for interacting with a JavaScript front end.\n\nThe Server API is mainly for capturing authorized payments and the Front end\nis for setting up CC forms. The Client side is for supporting AJAX in the browser.\nYou can also do authorisations and make payments using the Server API, so long as\nyou are fully aware of the PCI implications.\n\nThe Server API also has a notification handler for receiving the payment results and captured user information\nfrom the PAYONE servers.\n\nYou will most likely be using a mix of Server, Frontend and Client functions as they complement each other.\n\n### Shop and Access API Versions\n\nA payment portal is set up on PAYONE as one of two versions:\n\n* Shop\n* Access\n\nThe `Shop` portal version is used for one-off payments. The `Access` portal version is used for subscriptions,\ninvoicing, continuous renewals and services. Some of the payment methods are available just to the `Shop` version\nand some are available just to the `Access` version. Some methods are available to both versions, but accept\nslightly different sets of parameters.\n\nFor now, this package will deal with the `Shop` version only. However, the naming of classes and services will\nallow for `Access` version methods to be added later if required.\n\n### Extended Items (Order Lines)\n\nThe PAYONE API supports two additional cart item properties that must be completed (`id` and `vat`). Since the core OmniPay v2\n`Item` object cannot accept custom property values, this has been extended. The extended `Item` class can be found here:\n\n    \\Omnipay\\Payone\\Extend\\Item\n\nCreating an `Item` uses these fields:\n\n```php\n$lines[] = new \\Omnipay\\Payone\\Extend\\Item([\n    'id' =\u003e '{merchant-site-stock-ID}',\n    'name' =\u003e '{product-name}',\n    'quantity' =\u003e 2,\n    'price' =\u003e 123,\n    'vat' =\u003e 20, // Optional\n    // Used but optional for clearingType = \\Omnipay\\Payone\\AbstractShopGateway::CLEARING_TYPE_WLT\n    // and walletType = \\Omnipay\\Payone\\AbstractShopGateway::WALLET_TYPE_PPE\n    'itemType' =\u003e \\Omnipay\\Payone\\Extend\\ItemInterface::ITEM_TYPE_GOODS,\n]);\n```\n\nThe `price` can be supplied in *minor currency units* or *major currency units*.\nThe following `Item` prices are equivalent in dollars or Euros (currencies with\ntwo decimal places):\n\n* 123\n* 1.23\n* \"123\"\n* \"1.23\"\n\nThe `vat` value is the VAT rate, expressed as a percentage (%)\nor as a [basis point](https://en.wikipedia.org/wiki/Basis_point) (‱).\nThe rules are as follows:\n\n* Any integer up to 99 will be interpreted as a percentage.\n* Any integer 100 to 9999 will be interpreted as a basis point.\n\nThe items are then added to the `ItemBag` in the normal way as an array of objects:\n\n```php\n$items = new \\Omnipay\\Common\\ItemBag($lines);\n```\n\nThe total price of the `ItemBag` does not appear to need to add up to the order total\nfor the `Shop Server API` methods when clearing by credit card.\nIt MUST however sum to the order total for the `Shop Frontend`\nmethods, and it must sum correctly when using the CLEARING_TYPE_WLT clearing type.\n\nIf you do not use the extended `Item` then default values will be substituted (`\"000000\"` for the `id` and `null` for the\n`vat` figure). If you do not supply any items at all for the `Shop Frontend` methods, then a\ndefault item for the full price will be created automatically.\nThe `Shop Frontend` *must* have a basket of at least one item, which is why this driver\nwill create a default item if you do not supply a basket.\n\n## The Shop Server API Gateway\n\nCreate a gateway object to access the Server API Shop version methods:\n\n```php\n$gateway = Omnipay\\Omnipay::create('Payone_ShopServer');\n\n// Merchant Account ID\n$gateway-\u003esetMerchantId(12345);\n// Merchant Portal ID\n$gateway-\u003esetPortalId(1234567);\n// Sub-Account ID\n$gateway-\u003esetSubAccountId(56789);\n// True to use test mode.\n$gateway-\u003esetTestMode(true);\n// Default language is \"en\" and determines the language of forms and error messages.\n$gateway-\u003esetLanguage(\"de\");\n// Currency as ISO 4217 three-character code\n$gateway-\u003esetCurrency('EUR');\n```\n\n### Server API Authorize Payment\n\nPAYONE calls this \"pre-authorization\". It authorizes a payment to be captured later.\n\nTo create an authorization request:\n\n```php\n$request = $gateway-\u003eauthorize([\n    // Unique merchant site transaction ID\n    'transactionId' =\u003e 'ABC123',\n    // Amount as decimal.\n    'amount' =\u003e 0.00,\n    // Pre-shared secret key used for hashing and authentication.\n    'portalKey' =\u003e 'Ab12Cd34Ef56Gh78',\n    // Card and personal details.\n    'card' =\u003e $card,\n    // Optional card type override.\n    //'cardType' =\u003e 'V',\n    // The ItemBag/Cart\n    'items' =\u003e $items,\n    // Optional ecommerce mode declares risk\n    'ecommerceMode' =\u003e '3dsecure',\n]);\n```\n\nThe driver will attempt to work out the card type from the card number, but if it fails or\nyou are using a card type not yet supported by the driver or by OmniPay, then you can supply\nyour own card type letter.\n\nThe `$card` details are populated like any other standard OmniPay card, with one exception detailed\nbelow. You can supply the details as an array or as a `\\Omnipay\\Common\\CreditCard` object.\n\nThe `ecommerceMode` overrides the 3D Secure configuration set in the portal. Values include `internet`\nto turn off 3D Secure, `3dsecure` to turn on 3D Secure and `moto` for telephone and email payments.\nNote: when capturing an authorized payment, the *same ecommerceMode must be used* or the capture\nwill be rejected. However, PAYONE will wrap the bank's 3D Secure form on its\nown site, because it provides no additional POST data to send.\n\nThese four fields normally define the details for a credit card:\n\n```php\n[\n    ...\n    'number' =\u003e '4111111111111111',\n    'expiryYear' =\u003e '2020',\n    'expiryMonth' =\u003e '12',\n    'cvv' =\u003e '123',\n];\n```\n\nPAYONE will also accept a \"pseudo-card\" number. This is a temporary token supplied by another\nprocess (e.g. a \"creditcardcheck\") and used in place of a card. If supplying a pseudo-card number,\nleave the remaining card fields blank or null. The gateway driver will then treat the card number\nas a pseudo-card:\n\n```php\n[\n    ...\n    // A pseudo-card number.\n    'number' =\u003e '4111111111111111',\n    // Other card details left as null.\n    'expiryYear' =\u003e null,\n    'expiryMonth' =\u003e null,\n    'cvv' =\u003e null,\n];\n```\n\nIt is strongly recommended to only work with pseudo card numbers through the `Server` API channel,\nto reduce potential PCI DSS issues. A pseudo card number should be obtained through the `Client` API\nchannel using the \"hosted iFrame\" functionality.\n\nAlso to note about the card data is that countries must be supplied as ISO 3166 two-letter codes:\n\n```php\n    'billingCountry' =\u003e 'US',\n```\n\nand states must be supplied as ISO 3166-2 sub-division codes (various formats, depending on the country):\n\n```php\n    'billingCountry' =\u003e 'US',\n    'billingState' =\u003e 'AL',\n```\n\nThe return URL and cancel URL (when using 3D Secure) are normally set in the account settings,\nbut can be overridden here:\n\n```php\n    // Return URL on successful authorisation.\n    'returnUrl' =\u003e '...',\n    // Return URL on failure to authorise the payment.\n    'errorUrl' =\u003e '...',\n    // Return URL if the user choses to cancel the authorisation.\n    'cancelUrl' =\u003e '...',\n```\n\nSend this request to PAYONE to get the response:\n\n```php\n$response = $request-\u003esend();\n```\n\nThe standard OmniPay documentation shows how to handle the response. In addition, in the event\nof an error, there will be the normal loggable error message, and a separate error message that is safe\nto put in front of an end user:\n\n```php\nif (!$response-\u003eisSuccessful()) {\n    echo $response-\u003egetMessage();\n    // e.g. \"Expiry date invalid, incorrect or in the past\"\n    echo $response-\u003egetCustomerMessage();\n    // e.g. \"Invalid card expiry date. Please verify your card data.\"\n}\n```\n\n### Server API Purchase\n\nPAYONE calls this \"authorization\". It authorizes and captures a payment immediately.\n\nIt is used and responds in the same way as `authorize`. The request message is created like this:\n\n```php\n$request = $gateway-\u003epurchase([...]);\n```\n\n### Server API Capture\n\nOnce a payment has been authorised, it may be captured. This is done using this minimal message:\n\n```php\n$request = $gateway-\u003ecapture([\n    // The reference for the original authorize transaction.\n    'transactionReference' =\u003e '123456789',\n    // Amount as decimal.\n    'amount' =\u003e 1.23,\n    // Pre-shared secret key used for authentication, if not already set on $gateway.\n    'portalKey' =\u003e 'Ab12Cd34Ef56Gh78',\n]);\n```\n\nThat will capture the amount specified and settle the account. If you want to leave the\naccount open for capturing the total in multiple stages, then specify for the account to\nbe left unsettled:\n\n```php\n    'sequenceNumber' =\u003e $sequence,\n    'settleAccount' =\u003e false,\n```\n\nThe sequence number starts at 1 for the first capture, and must be incremented for each\nsubsequent capture. It should be taken from the [Notification Callback](#notification-callback),\nsee below.\n\nFor invoicing module some additional parameters have to be provided:\n\n```php\n$lines[] = new \\Omnipay\\Payone\\Extend\\Item([\n    'id' =\u003e '{merchant-site-stock-ID}',\n    'name' =\u003e '{product-name}',\n    'itemType' =\u003e 'goods', // Available types: goods, shipping etc.\n    'quantity' =\u003e 2,\n    'price' =\u003e 123,\n    'vat' =\u003e 20, // Optional\n]);\n\n$items = new ItemBag($lines);\n```\n\nAnd in capture request:\n\n```php\n    'items' =\u003e $items,\n    'sequenceNumber' =\u003e 1,\n    'settleAccount' =\u003e false,\n    'invoiceid' =\u003e 1,\n    'invoiceDeliveryMode' =\u003e 'P', // PDF, for others look into documentation\n    'invoiceDeliveryDate' =\u003e date('Ymd'),\n    'invoiceAppendix' =\u003e 'This is your invoice appendix'\n```\nNote that the email field in card details has to be passed to authorize method in pre-authorization step since it's\nthe email that will be used by Payone to send invoice to customer.\n\n### Server API Void\n\nTo void an authorized payment:\n\n```php\n$request = $gateway-\u003evoid([\n    // The reference for the original authorize transaction.\n    'transactionReference' =\u003e '123456789',\n    // Amount as decimal.\n    'amount' =\u003e 1.23,\n    // Pre-shared secret key used for authentication, if not already set on $gateway.\n    'portalKey' =\u003e 'Ab12Cd34Ef56Gh78',\n]);\n$response = $request-\u003esend();\n```\n\nThe `void` method will response with a `ShopCaptureResponse` response when sent to PAYONE.\n\n### Server API Credit Card Check\n\nThis method will check that the details of a credit card are *plausible* and optionally\ntokenize the card details for use in other methods. The Credit Card Check method is\navailable both for Server direct requests, and for AJAX calls on the Client side.\n\nThe request is set up like this:\n\n```php\n$gateway = Omnipay\\Omnipay::create('Payone_ShopServer');\n$gateway-\u003esetSubAccountId(12345);\n$gateway-\u003esetTestMode(true); // Or false for production.\n$gateway-\u003esetMerchantId(67890);\n$gateway-\u003esetPortalId(3456789);\n$gateway-\u003esetPortalKey('Ab12Cd34Ef56Gh78');\n\n$request = $gateway-\u003ecreditCardCheck([\n    'card' =\u003e [\n        'number' =\u003e '4012001037141112',\n        'expiryYear' =\u003e '2020',\n        'expiryMonth' =\u003e '12',\n        'cvv' =\u003e '123',\n    ],\n    'storeCard' =\u003e true,\n]);\n\n$response = $request-\u003esend();\n```\n\nIf the credit card details are plausible, then the response will be successful:\n\n```php\n$response-\u003eisSuccessful();\n// true\n```\n\nIf the response is not successful, then details will be available in `getCode()`,\n`getMessage()` and `getCustomerMessage()`.\n\nIf the response is successful and `storeCard` is `TRUE` then two additional items\nof data will be available:\n\n```php\n// The tokenised card:\n$token = $response-\u003egetToken();\n// e.g. 4100000227987220\n\n// The truncated card number:\n$response-\u003egetCardNumber()\n// e.g. 401200XXXXXX1112\n```\n\nIn any API that requires credit card details, you can substitute the details with\nthe token, for example:\n\n```php\n$request = $gateway-\u003eauthorize([\n    'card' =\u003e [\n        'number' =\u003e $token\n    ],\n    ...\n```\n\nNormally the token will come from the web client (AJAX in the browser) but this\nServer API can be used during development and testing with test cards.\n\n## The Shop Front End API Gateway\n\nThe Front End gateway supports hosted payment forms, taking either just credit card or\nbank details, or full personal details too. The forms are hosted on the PAYONE site,\ncan be customised, and can be either presented to the end user in an iframe, or\nthe end user can be fully redirected to the remote form.\n\n```php\n// Set up the Front End gateway.\n$gateway = Omnipay\\Omnipay::create('Payone_ShopFrontend');\n```\n\n### Front End Authorize\n\nThe Front End API methods are encapsulated into a separate gateway class:\n\n```php\n$gateway = Omnipay\\Omnipay::create('Payone_ShopFrontend');\n\n// Merchant Portal ID\n$gateway-\u003esetPortalId(1234567);\n// Sub-Account ID\n$gateway-\u003esetSubAccountId(56789);\n// True to use test mode.\n$gateway-\u003esetTestMode(true);\n// Default language is \"en\" and determines the language of forms and error messages.\n$gateway-\u003esetLanguage(\"de\");\n// Currency as ISO 4217 three-character code\n$gateway-\u003esetCurrency('EUR');\n// The pre-shared secret, used for hashing.\n$gateway-\u003esetPortalKey('Ab12Cd34Ef56Gh78');\n// The default for this gateway is HASH_MD5 for legacy applications, but the hash\n// method recommended by PAYONE is HASH_SHA2_384,\n$gateway-\u003esetHashMethod($gateway::HASH_SHA2_384);\n```\n\nSending an authorization involves setting up the request message:\n\n```php\n$transactionId = {merchant-site-transaction-ID}\n\n$request = $gateway-\u003eauthorize([\n    'transactionId' =\u003e $transactionId,\n    'amount' =\u003e 3.99,\n    'accessMethod' =\u003e 'iframe',\n    'redirectMethod' =\u003e 'POST',\n    'items' =\u003e $items,\n    'card' =\u003e [\n        'firstName' =\u003e 'Firstname',\n        'billingAddress1' =\u003e 'Street Name',\n        ...\n    ],\n    // Any of these optional URLs can override those set in the account settings:\n    'returnUrl' =\u003e '...',\n    'errorUrl' =\u003e '...',\n    'cancelUrl' =\u003e '...',\n]);\n```\n\nThe `accessMethod` will be `\"classic\"` or `\"iframe\"`; default is `ShopFrontendAuthorizeRequest::ACCESS_METHOD_CLASSIC`\nThe `redirectMethod` will be `\"GET\"` or `\"POST\"`; default is `ShopFrontendAuthorizeRequest::REDIRECT_METHOD_GET`\n\nThe `items` are optional, but if you\ndo not supply at least one item, then a default item will be created for you; the cart is\nmandatory for the Frontend API, unlike the Server API.\n\nThe `card` billing details can be used to pre-populate the payment form.\nIf the personal details have been checked and known to be valid (another API is able to\ndo that) then the name and address fields can be hidden on the payment form using\n`'showName' =\u003e false` and `'showAddress' =\u003e false`.\n\nNote that it may not be possible to override the URLs as shown above. It may be\npossible to set these URLs *only* if not defined in the account settings. The\ndocumentation is not entirely clear on this.\n\nThe response message (from OmniPay) for performing the next action is:\n\n```php\n$response = $request-\u003esend();\n```\n\nThe response will be a redirect response, either GET or POST, according to the `redirectMethod`\nparameter.\n\nYou can retrieve the GET URL and redirect in your application, or leave OmniPay to do the redirect:\n\n```php\n// Get the URL.\n$url = $response-\u003egetRedirectUrl();\n\n// Just do the redirect using the methods in OmniPay core.\n$response-\u003eredirect();\n```\n\nFor the `POST` redirectMethod, again, you can just let OmniPay do the redirect,\nbut you will probably want to build your own form and `target` it at an iframe\nin the page. The two things you need to build the form is the target URL, and the form items.\nThe form items are supplied as name/value pairs.\n\n```php\n// This form needs JavaScript to auto-submit on page load.\necho '\u003cform action=\"' . $response-\u003egetRedirectUrl() . '\" method=\"POST\" target=\"target-iframe\"\u003e';\nforeach($response-\u003egetRedirectData() as $name =\u003e $value) {\n    echo '\u003cinput type=\"hidden\" name=\"'.$name.'\" value=\"'.htmlspecialchars($value).'\" /\u003e';\n}\necho '\u003c/form\u003e';\n\n// The autp-submitted form, tagetting at this iframe, will generate the\n// remote credit card payment form within this iframe.\necho '\u003ciframe name=\"target-iframe\" width=\"400\" height=\"650\"\u003e\u003c/iframe\u003e';\n```\n\nOn return from the remote gateway, if using the iframe, you will need to break out\nof the iframe to get to the final page in your merchant site. The PAYONE API does have\niframe-busting functionality built in. Set the `setTargetWindow()` on your authorize request\nto tell the gateway where to take the user.\nAccepted values are given in `ShopFrontendAuthorizeRequest::TARGET_WINDOW_*`.\n\nNote that this driver does not attempt to generate HTML forms. It will instead give you the\ndata for creating your own HTML forms.\n\nAfter the user has completed their details on the PAYONE site, a notification of the result\nwill be sent back to your merchant site, and then the user will be returned to either the\n\"success\" page or the \"failure\" page. No data will be carried with that redirect, so the\ntransaction details must be retained in the session to match up with the results in\nthe notification back-channel.\n\n### Front End Purchase\n\nWorks the same as Front End Authorize, but will require a separate `Server` API Capture.\n\n### Front End Credit Card Check\n\nSet this up the same way as the Client API Credit Card Check.\nThe response is then used to generate the data you will need for the JSON\nto configure the form you will use to tokenise the card:\n\n    $jsonForJavaScript = json_encode($request-\u003esend()-\u003egetData());\n\nSetting up the card tokenisation form and JavaScript to process it, is out of scope\nfor this guide. The official documentation provides good examples. Just replace the\nsample request config data with the contents of `$jsonForJavaScript`.\n\n## The Shop Client API Gateway\n\nThe Shop Client gateway handles payments using client AJAX calls or forms on the merchant\nsite that are POSTed direct to the PAYONE gateway.\n\n```php\n// Set up the Client gateway.\n$gateway = Omnipay\\Omnipay::create('Payone_ShopClient');\n```\n\n### Client API Credit Card Check\n\nThis is similar to the Server API Credit Card Check, and is set up in a similar way.\nNo credit card details are passed to it however, as that is handled on the client.\n\n```php\n$gateway = Omnipay\\Omnipay::create('Payone_ShopClient');\n$gateway-\u003esetSubAccountId(12345);\n$gateway-\u003esetTestMode(true); // Or false for production.\n$gateway-\u003esetMerchantId(67890);\n$gateway-\u003esetPortalId(3456789);\n$gateway-\u003esetPortalKey('Ab12Cd34Ef56Gh78');\n$gateway-\u003esetHashMethod($gateway::HASH_SHA2_384);\n\n$request = $gateway-\u003ecreditCardCheck();\n$response = $request-\u003esend();\n```\n\nThis provides the following data to feed into your client:\n\n```php\n// The endpoint used to check the card details - GET or POST can be used.\n$endpoint = $response-\u003egetRedirectUrl();\n\n// The additional data that must be included with the card data.\n// This will be an array that can be JSON encoded for the client JavaScript to use:\n$data = $response-\u003egetRedirectData();\n```\n\nThen on the client you need to provide the credit card fields in a non-submitting\nform (form items with no `name` attributes):\n\n* cardpan - credit card number\n* cardexpiredate - YYMM\n* cardtype - e.g. V for Visa\n* cardcvc2\n* cardissuenumber - for UK Maestro only\n\nThese values will be constructed by your client code, then submitted to the end point.\nThe `cardexpiredate` for example, could be two drop-down lists concatenated.\nThe `cardtype` could be a drop-down list, or a client library could set it automatically\nby matching card number patterns.\n\nThe result will be a JSON response something like this:\n\n```json\n{\n    \"status\" : \"VALID\",\n    \"pseudocardpan\" : \"4100000228091881\",\n    \"truncatedcardpan\" : \"401200XXXXXX1112\",\n    \"cardtype\" : \"V\",\n    \"cardexpiredate\" : \"2012\"\n}\n```\n\nHandling that data is out of scope for OmniPay, but the most important value here is\nthe `pseudocardpan` which can be used in any server API call in place of the real credit card\nnumber (e.g. the Shop Server Authorize method).\n\nThe official PAYONE documentation explains further how this works, and provides\nsample client code fragments.\n\nIt is recommended to use the \"hosted iFrame\" mode of capturing credit card data. It is out\nof the scope of OmniPay and described in more detail [here](https://github.com/fjbender/simple-php-integration#credit-card-payments).\n\n### Client API Authorize\n\nThere are two main modes the client authorize operates in:\n\n* **REDIRECT** - The user POSTs directly to the PAYONE gateway, enters 3D Secure details\n  there if necessary, then is sent back to your site.\n* **JSON** - The user stays on your site initially while the authorisation is requested via\n  AJAX. The client may then send the user to PAYONE to enter their 3D Secure password if\n  required, but if not, then results can be posted directly back to the merchant site\n  without the user leaving.\n\nThe REDIRECT mode supports the building of a complete payment form on the merchant site that\nPOSTs `direct` to the PAYONE gateway. The result of the authorisation will be POSTed by\nPAYONE to the Notification handler. The gateway will also return the success status\nto the merchant site with the user when they are directed back **so long as 3D Secure is\nnot being used**. It is important to note that if 3D Secure is used and the end user is\nredirected to enter their 3D Secure password, then they will be returned to your site's\nsuccess/failure/cancel URL with *no* data, so the merchant site must save enough details\nin the session to pick up the authorisation results sent via the `Notification` back-channel handler.\n\nThe AJAX mode is set up the same way, but all the details are POSTed via AJAX rather then\nas a standard browser form. The result comes back as a JSON response, which may include a\n3D Secure redirect, or may just contain the authorisation result.\n\nSetting up the message is much the same as other methods. It is the same for\nboth the REDIRECT and the JSON response types:\n\n```php\n$gateway = Omnipay\\Omnipay::create('Payone_ShopClient');\n$gateway-\u003esetSubAccountId(12345);\n$gateway-\u003esetTestMode(true); // Or false for production.\n$gateway-\u003esetMerchantId(67890);\n$gateway-\u003esetPortalId(3456789);\n$gateway-\u003esetPortalKey('Ab12Cd34Ef56Gh78');\n// The default for this gateway is HASH_MD5 for legacy applications, but the hash\n// method recommended gby PAYONE is HASH_SHA2_384,\n$gateway-\u003esetHashMethod($gateway::HASH_SHA2_384);\n// Set up the response type - redirect the user or do an AJAX call.\n$gateway-\u003esetResponseType($gateway::RETURN_TYPE_REDIRECT);\n//$gateway-\u003esetResponseType($gateway::RETURN_TYPE_JSON);\n\n$request = $gateway-\u003eauthorize([\n    'transactionId' =\u003e $transactionId, // Merchant site ID (or a nonce for it)\n    'amount' =\u003e 9.99, // Major units\n    'currency' =\u003e 'EUR',\n    '3dSecure' =\u003e false, // or true\n    'items' =\u003e $items, // Array or ItemBag of Items or Exten\\Items\n    // Where to send the user in authorisation suucess or falure.\n    'returnUrl' =\u003e $returnUrl,\n    'errorUrl' =\u003e $errorUrl,\n    // Where to send the user on cancellation in 3D Secure form.\n    'cancelUrl' =\u003e $cancelUrl,\n]);\n$response = $request-\u003esend();\n```\n\nThe `$response` now contains the details needed for either hidden fields\nin the client-side direct POST form, or for the AJAX call. These details are:\n\n```php\n// Array of name/value pairs\n$params = $response-\u003egetRedirectData();\n\n// The destination endpoint.\n$endpoint = $response-\u003egetRedirectUrl();\n```\n\nIn addition to `$params` you need to include the following data provided by\nthe end user:\n\n* lastname - mandatory\n* country - ISO3166 e.g. GB\n* cardpan\n* cardexpiredate YYMM\n* cardtype - e.g. V\n* cardcvc2\n* cardissuenumber - UK Maestro only\n* cardholder - optional\n\nIf your redirectMethod was REDIRECT, then all this information will be put into a form that\nthe user submits. The form will POST directly to PAYONE. What happens next will depend on\nwhether 3D Secure has been turned on and is availa to the card used.\n\n* If 3D Secure is available, PAYONE will present the end user with a 3D Secure password form.\n  The user will then be returned to the site with **no results**. The results will be send to\n  the `Notification` handler where the merchant site must fetch them using the merchant site\n  `transactionId`.\n* If 3D Secure is NOT available, then the card will be validated and the user returned to the\n  merchant site **with the results** as GET parameters. The result cannot be trusted as it is\n  not signed, but can be useful in the flow. The result can be captured using the\n  `completeAuthorize` message (see below).\n\nIf your `responseType` was JSON (`ShopClientGateway::RETURN_TYPE_REDIRECT`), then the merchant site client page is expected to POST the data\nusing AJAX. The return will be a JSON message detailing the result, which can be a success, failure,\nor a redirect for 3D Secure. Handling that response is out of scope for OmniPay, but the PAYONE\ndocumentation provides some examples and some handy scripts.\n\n#### Client completeAuthorize\n\nThis can be used to parse the resturn data from the server request (i.e. the data the user brings\nback with them):\n\n```php\n$gateway = Omnipay\\Omnipay::create('Payone_ShopClient');\n\n$server_request = $gateway-\u003ecompleteAuthorize();\n$server_response = $server_request-\u003esend();\n```\n\nThe `$server_response` can give you a number of standardised items:\n\n```php\n// The raw data\n$server_response-\u003egetData();\n\n// The authorisation success state:\n$server_response-\u003eisSuccessful();\n\n// The redirect status and URL (we would not expect to see this for a REDIRECT response\n// type as the redirect has already been processed on the client side:\n$server_response-\u003eisRedirect();\n$server_response-\u003egetRedirectUrl()\n\n// If there are errors, then there will be a system message and a user-safe message:\n$server_response-\u003egetMessage();\n$server_response-\u003egetCustomerMessage();\n```\n\n### Client API Purchase\n\nThis works the same way as *Client API Authorize* but uses the `purchase` method instead.\n\nYou would still use `completeAuthorize` with the purchase API.\n\n\n\n## Notification Callback\n\nFor most - if not all - transactions, PAYONE will send details of that transaction to your\nnotification URL. This URL is specified in the PAYONE account configuration. For most of the\nServer API methods it is a convenience. For the Frontend methods it is essential, being the\nonly way of getting a notification that a transaction has completed.\n\nThe notification comes from IP address 185.60.20.0/24 (185.60.20.1 to 185.60.20.254).\nThis driver does not make any attempt to validate that.\n\nYour application must respond to the notification within ten seconds, because when a Frontend\nhosted form is used, the user will be waiting on the PAYONE site for the acknowledgement - just\nsave the data to storage and end.\n\nThe notification Server Request (i.e. *incoming* request to your server) is captured/handled by the\n`completeStatus` class created using the standard OmniPay `acceptNotification()` gateway method.\n\n```php\n$gateway = Omnipay\\Omnipay::create('Payone_ShopServer');\n\n// The portal key must be provided.\n// This will be used to verify the hash sent with the transaction status notification.\n// PAYONE will send an MD5 hash at all times. This is subject to change and will support\n// the option to use a SHA2-384 hash eventually.\n$gateway-\u003esetPortalKey('Ab12Cd34Ef56Gh78');\n\n$server_request = $gateway-\u003eacceptNotification();\n\n// The raw data sent is available:\n$data = $server_request-\u003egetData();\n\n// Provides the result of the hash verification.\n// If the hash is not verified then the data cannot be trusted.\n$server_request-\u003eisValid();\n```\n\nSo long as the notification is valid, you can also get the status of the transaction.\nThe following table lists the way this driver maps the status and and the event (the `txaction`)\nto Omnipay's overall status values (\"-\" neans \"anything\"):\n\n| transaction_status | txaction | Overall transaction status | Notes |\n| ------------------ | -------- | -------------------------- | ----- |\n| completed | - | STATUS_COMPLETED | |\n| - | appointed | STATUS_COMPLETED | |\n| - | paid | STATUS_COMPLETED | |\n| - | invoice | STATUS_COMPLETED | |\n| - | capture | STATUS_PENDING | |\n| - | underpaid | STATUS_PENDING | |\n| - | refund | STATUS_PENDING | |\n| - | debit | STATUS_PENDING | |\n| - | reminder | STATUS_PENDING | |\n| - | vauthorization | STATUS_PENDING | |\n| - | vsettlement | STATUS_PENDING | |\n| - | transfer | STATUS_PENDING | |\n| - | cancelation | STATUS_FAILED | |\n| - | failed | STATUS_FAILED | |\n| - | - | STATUS_FAILED | |\n\nIndividual data items can also be extracted from the server request (see list below).\n\nOnce the data is saved to the local application, respond to the remote gateway to\nindicate that you have received the notification:\n\n```php\n$server_response = $server_request-\u003esend();\n// Your application will exit on the next command by default.\n// You can prevent that by passiong in `false` as a single parameter, but\n// do make sure no further stdout is issued.\n$server_response-\u003eacknowledge(); // or $server_response-\u003esend()\n```\n\nList of $server_request data methods:\n\n* getPaymentPortalKey() - MD5 or SHA2 384, depending on portal account configuration\n* getPaymentPortalId()\n* getSubAccountId()\n* getEvent() - the name of the reason the notification was sent.\n  Includes \"appointed\", \"capture\", \"paid\", \"underpaid\", \"cancelation\", \"refund\", \"debit\", \"reminder\", \"vauthorization\", \"vsettlement\", \"transfer\", \"invoice\", \"failed\"\n* getAccessName()\n* getAccessCode()\n* getTxStatus() - the raw status code\n* getTransactionStatus() - OmniPay transaction status codes\n* getTransactionId()\n* getTransactionReference()\n* getNotifyVersion()\n* getParam()\n* getMode() - test or live\n* getSequenceNumber()\n* getClearingType() - 'cc' for credit card; 'wlt' and walletType = 'PPE' for PayPal Express\n* getWalletType() - 'PPE' for PayPal Express\n* getTxTimestamp() - raw unix timestamp\n* getTxTime() - timestamp as a \\DateTime object\n* getCompany()\n* getCurrency() -  ISO three-letter code\n* getCurrencyObject() - as an OmniPay `Currency` object\n* getDebtorId()\n* getCustomerId()\n* getNumber() - the CC number with hidden middle digits e.g. 411111xxxxxx1111\"\n* getNumberLastFour() - e.g. \"1111\"\n* getCardType() - PAYONE single-letter code, e.g. \"V\", \"M\", \"D\".\n* getBrand() - OmniPay name for the card type, e.g. \"visa\", \"mastercard\", \"diners\".\n* getExpireDate() - YYMM format, as supplied\n* getExpireDateObject() - expiry date returned as a \\DateTime object\n* getCardholder() - documented, but seems to be blank most of the time\n* getFirstName()\n* getLastName()\n* getName()\n* getStreet()\n* getAddress1() - alias of getStreet()\n* getCity()\n* getPostcode()\n* getCountry() - ISO code\n* getShippingFirstName()\n* getShippingLastName()\n* getShippingName()\n* getShippingStreet()\n* getShippingAddress1() - alias of getShippingStreet()\n* getShippingCity()\n* getShippingPostcode()\n* getShippingCountry() - ISO code\n* getEmail()\n* getPrice() - decimal in major currency units\n* getPriceInteger() - integer in minor currency units\n* getBalance() - decimal in major currency units\n* getBalanceInteger() - integer in minor currency units\n* getReceivable() - decimal in major currency units\n* getReceivableInteger() - integer in minor currency units\n\n### completeAuthorize and completePurchase Methods\n\nAlthough the Frontend purchase and authorize take the user offsite (either in full screen\nmode or in an iframe), no data is returned with the user coming back to the site.\nas a consequence, the `completeAuthorize` and `completePurchase` methods are not needed.\n\n3D Secure involves a visit to the authorising bank. However, PAYONE will wrap that visit\nup into a page that it hosts (the page will contain an iframe). This means the result,\nif a 3D Secure password is needed, will still be sent to the merchant site through the\nsame notification URL as any non-3D Secure transaction. One advantage is that your merchant\nsite does not need to mess around with `PAReq`/`PARes` parameters and suchlike from the end banks.\n\n# References\n\n* https://github.com/fjbender/simple-php-integration  \n  A write-up showing how the PAYONE integration works.\n  Some great background information.\n* https://github.com/ekalinin/github-markdown-toc  \n  Tool to generate the Table of Contents in this README.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facademe%2Fomnipay-payone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facademe%2Fomnipay-payone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facademe%2Fomnipay-payone/lists"}