EveryPay (every-pay.com, Estonia) is the LHV Paytech e-commerce platform used by the Baltic partner banks SEB, LHV and Swedbank. Not to be confused with everypay.gr (a Greek company).
- API reference (ReDoc): https://support.every-pay.com/apidoc/main/
- Help center: https://support.every-pay.com/en/ (collections: Custom Integration, Plugin Integration, SDKs)
- Merchant portal (live): https://portal.every-pay.eu/ - API username/secret under Merchant settings -> General
- EveryPay support: support@every-pay.com
- SEB e-commerce docs hub (test cards etc.): https://support.ecommerce.sebgroup.com/
| Base URL | |
|---|---|
| Demo | https://igw-demo.every-pay.com/api |
| Production | https://pay.every-pay.eu/api |
Bank-branded demo portals (e.g. SEB's) share the demo backend: the same
credentials authenticate on both the generic and the bank-branded host, and
the payment_link returned by the API may point at the bank-branded skin -
the base URL above keeps working either way.
Authentication: HTTP Basic (api_username : api_secret). The
api_username (16 chars) must also be repeated inside every request body /
status query string.
-
POST /v4/payments/oneoffwith a JSON body. Required:api_username,account_name(processing account, e.g.EUR3D1- determines currency + available methods),amount(decimal, 2 digits; Sylius stores cents -> divide by 100),order_reference(unique per shop by default; multiple attempts allowed until one settles),nonce(unique random string per request - replay protection),timestamp(ISO 8601, must be within +/-5 min of EveryPay server time),customer_url(absolute return URL; FQDN required - no dotless host, no IP).
Useful optional:
locale(lt,en,lv,et,ru, ...),emailandphone_number {country_code, number}(both flagged by the spec as "soon mandatory for all card payment requests" - upcoming Visa/Mastercard requirements),customer_ip,preferred_country(EE/LV/LT- pre-selects the Open Banking country tab),billing_*/shipping_*address fields (improve card fraud scoring; omitting them for card payments "may result in higher decline rates, degraded fraud screening, or limited dispute resolution"; from 2026-10-01 the character limits shrink - city/line1 50, postcode 16, country strict ISO alpha-2,billing_stateISO 3166-2),payment_description(Open Banking statement text, ~65 chars, charset[a-zA-Z0-9/-?:().,'+]-order_referenceshares the same charset and caps at 255 chars for cards / 120 for Open Banking),structured_reference(Open Banking structured payment reference, country-specific formats),integration_details {integration, software, version}. -
Response
201:payment_reference(64-char hex, the EveryPay payment id),payment_link(hosted payment page),payment_state: initial,currency,payment_methods[]. -
Redirect the customer to
payment_link. They pick card / bank link / wallet / PayPal there (Apple Pay & Google Pay come free with the hosted page). -
The customer returns to
customer_url- EveryPay appends?payment_reference=...&order_reference=.... Treat the return exactly like a callback: verify server-side, never trust query params. -
A server-to-server callback (see below) arrives in parallel - whichever comes first wins; both paths converge on the status query.
-
GET /v4/payments/{payment_reference}?api_username=...-> authoritativepayment_state. Optionaldetailed=trueaddsdetailed_fraud_check_results(the portal's "Fraud Check Results" panel).
- The callback URL is static, configured in the merchant portal under
E-shop settings (one per e-shop / processing account). For this plugin:
https://<shop-host>/payment-methods/<PAYMENT_METHOD_CODE>(the Sylius notify endpoint). - EveryPay calls it with query parameters:
payment_reference,order_reference(deprecated - scheduled for removal, do not rely on it),event_name. event_namevalues:status_updated,abandoned,voided,refunded,refund_failed,chargebacked,marked_for_capture,issuer_reported_fraudulent,merchant_reported_fraudulent,dispute_opened/dispute_updated/dispute_reversed/dispute_charged_back/dispute_reopened,card_art_updated,token_updated, and - easy to confuse withstatus_updated-status_update: acquiring completed, funds received on the merchant account (pairs with theacquiring_completed_atstatus field; only sent when the acquiring bank supports it).- Callbacks are not signed/authenticated. The only safe reaction is to
re-query
GET /v4/payments/{payment_reference}over authenticated TLS and act on that. This plugin does exactly that. - Delivery retries: up to 6 attempts at 1 s, 5 min, 1 h, 24 h, 48 h, 72 h -> then permanent failure. The handler must be idempotent (the same state may be reported repeatedly).
payment_state |
Meaning | Plugin mapping |
|---|---|---|
initial |
created, method not chosen yet | no-op (payment stays retryable) |
waiting_for_3ds_response / waiting_for_sca / 3ds_confirmed |
customer mid-authentication | processing |
sent_for_processing |
confirmed by customer, bank confirmation pending | processing |
settled |
final success (card settled / OB passed bank checks) | completed |
authorised |
card authorised, not yet captured (manual-capture accounts only) | authorized |
failed |
technical failure or issuer decline - final | failed |
abandoned |
customer walked away (15 min 3DS window) - final failure | failed |
voided |
authorisation cancelled - final | cancelled |
refunded |
fully/partially reimbursed | refunded |
charged_back |
cardholder dispute -> chargeback | left as-is; handled manually |
Default account setup is auto-capture -> success arrives directly as settled.
POST /v4/payments/refund - required: api_username, payment_reference,
amount (decimal, <= standing amount; partial allowed), nonce, timestamp.
Notes:
- Card payments: real money movement back to the customer.
- Open Banking: only marks the status refunded (no transaction) - unless the merchant is an LHV customer, where the OB refund is actually executed. For other banks, refund OB payments manually from the bank and use the API call to keep statuses in sync.
Payer-visible statement texts (not in the API docs; confirmed 2026-08 on both the merchant's and the payer's statements - both carry the same texts):
- OB payment: the description line is
payment_description; the counterparty is the merchant name transliterated to the SEPA restricted charset by the payment-initiation rails (uppercased, diacritics and quotation marks reduced). - LHV-executed OB refund: the description is the original
payment_descriptionprefixed withRefund -. The refund API has no text field - the text is composed on the EveryPay/LHV side and is not integrator-controllable. This record's counterparty is the account-holder name as registered at LHV (full diacritics), so the payer can see the same merchant under two spellings across the pair. - Card payments/refunds never carry
payment_description; card statements show the shopdescriptor(+ MCC) set at onboarding (see/v4/shops).
/v4/payments/cit|mit|charge (token payments), /v4/agreements
(recurring/subscription), /v4/tokens/*, /v4/payments/capture + /void
(manual-capture accounts), /v4/shops, /v4/processing_accounts,
/v4/mobile_payments/card_details (in-app payments).
Token-related oneoff extras: request_token + token_agreement
(unscheduled/recurring - the agreement of a follow-up CIT/MIT must match
the one used at tokenization), token_consent_agreed (merchant carries the
token consent in its own T&C - hides the save-card checkbox on the hosted
page), amount: 0 saves a card without any purchase.
EveryPay also has an embedded web checkout - the Payment Elements JS SDK
its own platform plugins (WooCommerce 2.x, Magento, PrestaShop) mount in-page:
{base host}/payment_elements/everypay-sdk-v1-0-0.umd.js (global EveryPay;
secureElements(...) -> build({element: 'payment'}) -> mount() / submit() /
confirm()). It rides on a oneoff created with mobile_payment: true, whose
response adds a mobile_access_token consumed by the element's hosted iframe -
the card form itself stays on EveryPay's servers, and EveryPay's
PCI DSS SAQ article
classifies the "Payment Elements" integration type as SAQ A (their
"SDK(s) -> SAQ A-EP" row refers to the mobile app SDKs).
Status 2026-07: no public integration documentation exists - the help
center's Custom Integration / SDKs / Plugin Integration collections contain
none (the SDKs collection is mobile-app only) - and the SDK contents changed
under the same v1-0-0 URL within days. Do not build on it before
support@every-pay.com confirms availability for custom integrations; until
then the documented custom-web patterns are the hosted redirect and the
method_source method selection this plugin already implements.
- Get demo credentials first; portal -> Merchant settings -> General: note
api_username,api_secret. - Note the processing account name (e.g.
EUR3D1) - it fixes the currency. - E-shop settings: set the callback URL (see above), keep "Additional
notifications via callback" checked, and leave
order_referenceuniqueness validation enabled (default) - the plugin's{orderNumber}-{paymentId}format satisfies it. - In the Sylius admin: Payment methods -> Create -> gateway "EveryPay", fill in the credentials, pick the demo environment, enable for the channel.
- Run a test payment (bank demo portals provide test cards / bank simulators; the 3DS challenge in demo is a simulator page - click Yes).
- Onboarding: after a successful demo payment, report it to support@every-pay.com - they verify before issuing live credentials.
- CDN/WAF (e.g. Cloudflare): ensure
/payment-methods/*is not cached and not challenged (a bot challenge would eat the server-to-server callback).
customer_urlvalidation rejects dotless hosts (localhost) but accepts plain http and.localhostsubdomains -> set the dev channel hostname to something likemyshop.localhost.- Callbacks:
ngrok http 80 --host-header=myshop.localhostand point the portal callback URL athttps://<tunnel>/payment-methods/<code>.