API Documentation
A simple, predictable REST API for accepting payments and issuing refunds. JSON in, JSON out, over HTTPS.
The API is organized around REST. Requests use standard HTTP verbs, return JSON, and use conventional status codes. Every object has a unique, unguessable id with a type prefix.
Base URL
https://onhere.net/api/v1
Every request runs in either test or live mode, decided by the API key you use. Test mode never touches real money and is available immediately; live mode unlocks once your account is approved.
Authentication
Authenticate with your secret API key in the Authorization header.
Find your keys in your dashboard under Developers → API keys. Each account has a publishable key (pk_) and a secret key (sk_), in a test and a live variant.
Send the secret key as a Bearer token on every request. Keep it private — treat it like a password and never expose it in client-side code.
The key prefix decides the mode: sk_test_ hits test mode, sk_live_ hits live mode. Live keys work only after your account is approved.
curl https://onhere.net/api/v1/account \
-H "Authorization: Bearer sk_test_..."
<?php
$ch = curl_init('https://onhere.net/api/v1/account');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_test_...'],
]);
$response = curl_exec($ch);
const res = await fetch('https://onhere.net/api/v1/account', {
headers: { Authorization: 'Bearer sk_test_...' }
});
const account = await res.json();
Errors
onHere uses conventional HTTP status codes and a consistent error body.
Codes in the 2xx range mean success, 4xx means the request failed given the information provided, and 5xx means something went wrong on our side. Failed requests return an error object:
{
"error": {
"type": "invalid_request_error",
"message": "The amount must be a positive integer in the smallest currency unit."
}
}
| Status | Meaning |
|---|---|
| 400 | Bad request — a parameter was missing or invalid. |
| 401 | Unauthorized — no or invalid API key. |
| 403 | Forbidden — live mode used by an unapproved account. |
| 404 | Not found — the resource does not exist. |
| 429 | Too many requests — you hit the rate limit. |
Rate limits
Requests are limited per API key, per minute.
Every response includes RateLimit-Limit and RateLimit-Remaining headers. When you exceed the limit you receive a 429 response — back off and retry after a short delay.
RateLimit-Limit: 60
RateLimit-Remaining: 59
Object IDs
Every object has a unique, random id with a type prefix.
IDs are never sequential and never guessable. Use the full string as the identifier; do not parse it.
| usr_ | account |
| txn_ | payment |
| re_ | refund |
| key_ | API key |
| whe_ | webhook endpoint |
| evt_ | event |
The account
Information about the authenticated account.
Retrieve the account
Returns the account associated with the API key.
curl https://onhere.net/api/v1/account \
-H "Authorization: Bearer sk_test_..."
<?php
$ch = curl_init('https://onhere.net/api/v1/account');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_test_...'],
]);
$account = json_decode(curl_exec($ch), true);
const res = await fetch('https://onhere.net/api/v1/account', {
headers: { Authorization: 'Bearer sk_test_...' }
});
const account = await res.json();
{
"id": "usr_x7Kp9fQ2mL4tR8wZ1cVb",
"object": "account",
"type": "individual",
"email": "jane@example.com",
"approved": true,
"livemode": false,
"created": 1783723601
}
Payments
A payment represents money moving through your account.
Create a payment
Creates a payment for the given amount and currency.
Parameters
| Parameter | Type | Description |
|---|---|---|
| amount | integer | Amount in the smallest currency unit (e.g. cents). Required. |
| currency | string | Three-letter ISO currency code. Defaults to EUR. |
| description | string | An arbitrary description shown in the dashboard. |
| reference | string | Your own reference (e.g. an order id) echoed back on the payment and in webhooks. Optional. |
| card_number | string | Card number for the internal card scheme. Optional. |
| card_expiry | string | Card expiry as MM/YYYY. Optional. |
| card_cvc | string | Card verification code. Optional. |
Payments start as pending and are confirmed by review; transaction.succeeded (or transaction.failed) fires when the outcome is decided.
Response includes reference and payment_link (the pl_ id the payment came from, if any).
curl https://onhere.net/api/v1/payments \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"amount": 2500, "currency": "eur", "description": "Order #1001"}'
<?php
$ch = curl_init('https://onhere.net/api/v1/payments');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer sk_test_...',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 2500,
'currency' => 'eur',
'description' => 'Order #1001',
]),
]);
$payment = json_decode(curl_exec($ch), true);
const res = await fetch('https://onhere.net/api/v1/payments', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_test_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount: 2500, currency: 'eur', description: 'Order #1001' }),
});
const payment = await res.json();
{
"id": "txn_w2UlYqe9ZMoIhvofDhyj",
"object": "payment",
"amount": 2500,
"currency": "EUR",
"description": "Order #1001",
"reference": "wc_order_1057",
"payment_link": "pl_jLdWvwZU5Wj8P1HvgE4F",
"status": "pending",
"livemode": false,
"amount_refunded": 0,
"refunded": false,
"created": 1783724733
}
List payments
Returns your payments, most recent first.
Retrieve a payment
Retrieves a payment by its id.
curl https://onhere.net/api/v1/payments/txn_w2UlYqe9ZMoIhvofDhyj \
-H "Authorization: Bearer sk_test_..."
Payment links
A payment link points a customer at a hosted checkout page — ideal for integrations (e.g. a webshop) that redirect the shopper to pay.
Create a payment link
Creates a hosted checkout link and returns its url. Links are single-use by default.
Parameters
| Parameter | Type | Description |
|---|---|---|
| amount | integer | Amount in the smallest currency unit (e.g. cents). Required. |
| currency | string | Three-letter ISO currency code. Defaults to EUR. |
| description | string | An arbitrary description shown at checkout and in the dashboard. |
| reference | string | Your own reference (e.g. an order id) copied onto the payment and included in webhooks so you can match the payment to your order. |
| reusable | boolean | Whether the link can be paid more than once. Defaults to false (single-use). |
| customer_email | string | Prefills the payer's e-mail on the checkout page. |
| card_name | string | Prefills the cardholder name on the checkout page. |
| return_url | string | URL the payer is redirected to after paying (with ?status=pending&ref=<txn>). Must be a valid URL. |
| expires_at | integer | Unix timestamp (or date string) after which the link can no longer be paid. Optional. |
| max_uses | integer | Maximum number of successful payments the link accepts before it deactivates. Optional. |
curl https://onhere.net/api/v1/payment_links \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 4999,
"currency": "eur",
"description": "Order #1057",
"reference": "wc_order_1057",
"customer_email": "buyer@example.com",
"card_name": "John Buyer",
"return_url": "https://shop.example.com/checkout/order-received"
}'
<?php
$ch = curl_init('https://onhere.net/api/v1/payment_links');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer sk_test_...',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 4999,
'currency' => 'eur',
'reference' => 'wc_order_1057',
'customer_email' => 'buyer@example.com',
'card_name' => 'John Buyer',
'return_url' => 'https://shop.example.com/checkout/order-received',
]),
]);
$link = json_decode(curl_exec($ch), true);
header('Location: ' . $link['url']); // send the shopper to pay
const res = await fetch('https://onhere.net/api/v1/payment_links', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_test_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 4999,
currency: 'eur',
reference: 'wc_order_1057',
customer_email: 'buyer@example.com',
card_name: 'John Buyer',
return_url: 'https://shop.example.com/checkout/order-received',
}),
});
const link = await res.json();
window.location = link.url; // send the shopper to pay
The response contains a url — redirect the customer there to pay.
{
"id": "pl_jLdWvwZU5Wj8P1HvgE4F",
"object": "payment_link",
"amount": 4999,
"currency": "EUR",
"reusable": false,
"description": "Order #1057",
"reference": "wc_order_1057",
"customer_email": "buyer@example.com",
"card_name": "John Buyer",
"return_url": "https://shop.example.com/checkout/order-received",
"expires_at": 1786316733,
"max_uses": 1,
"uses": 0,
"status": "active",
"url": "https://onhere.net/start/?l=pl_jLdWvwZU5Wj8P1HvgE4F",
"mode": "test",
"created": 1783724733
}
List payment links
Returns your payment links, most recent first.
Retrieve a payment link
Retrieves a payment link by its id.
Subscriptions
Recurring billing. Create a reusable plan, then subscribe a customer to it with a card. The subscription charges immediately and then on the plan schedule; each charge is a payment you approve like any other.
Create a plan
A plan holds the amount, interval, optional total duration and minimum term. Subscriptions are created against a plan.
| Parameter | Type | Description |
|---|---|---|
| name | string | Plan name (required). |
| amount | integer | Amount in the smallest currency unit (e.g. 1999 = 19.99). |
| currency | string | Three-letter ISO currency code. Defaults to EUR. |
| interval | string | Billing interval: day, week, month or year. |
| interval_count | integer | Number of intervals between charges. Defaults to 1. |
| total_cycles | integer | Total number of charges before the subscription completes. Omit or 0 to run until canceled. |
| min_cycles | integer | Charges a customer must keep the subscription before they may cancel it themselves. Defaults to 0. |
| description | string | Optional description. |
curl https://onhere.net/api/v1/subscription_plans \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Pro monthly",
"amount": 1999,
"currency": "eur",
"interval": "month",
"total_cycles": 12,
"min_cycles": 3
}'
<?php
$ch = curl_init('https://onhere.net/api/v1/subscription_plans');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer sk_test_...',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Pro monthly',
'amount' => 1999,
'currency' => 'eur',
'interval' => 'month',
'total_cycles' => 12,
'min_cycles' => 3,
]),
]);
$plan = json_decode(curl_exec($ch), true);
const res = await fetch('https://onhere.net/api/v1/subscription_plans', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_test_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Pro monthly',
amount: 1999,
currency: 'eur',
interval: 'month',
total_cycles: 12,
min_cycles: 3,
}),
});
const plan = await res.json();
{
"id": "plan_9Kd2mZ0pQ7rLtV3xW1cB",
"object": "subscription_plan",
"name": "Pro monthly",
"description": null,
"amount": 1999,
"currency": "EUR",
"interval": "month",
"interval_count": 1,
"total_cycles": 12,
"min_cycles": 3,
"status": "active",
"created": 1783724733
}
List plans
Returns your plans, newest first.
Retrieve a plan
Archive a plan
Archiving stops new subscriptions on the plan; existing subscriptions keep running.
Create a subscription
Subscribe a customer to a plan with a card. The first charge is taken immediately, then on the plan schedule. The customer is e-mailed on signup, on every charge and on cancellation.
| Parameter | Type | Description |
|---|---|---|
| plan | string | The plan public id to subscribe to (required). |
| customer_email | string | Customer e-mail; subscription notifications are sent here (required). |
| customer_name | string | Optional customer name. |
| coupon | string | Optional coupon code (a percentage discount) to apply to the subscription. |
| card_number | string | Card number (required). |
| card_expiry | string | Card expiry as MM/YY or MM/YYYY (required). |
| card_cvc | string | Card security code (required). |
curl https://onhere.net/api/v1/subscriptions \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"plan": "plan_9Kd2mZ0pQ7rLtV3xW1cB",
"customer_email": "buyer@example.com",
"card_number": "4242424242424242",
"card_expiry": "12/2030",
"card_cvc": "123"
}'
<?php
$ch = curl_init('https://onhere.net/api/v1/subscriptions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer sk_test_...',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'plan' => 'plan_9Kd2mZ0pQ7rLtV3xW1cB',
'customer_email' => 'buyer@example.com',
'card_number' => '4242424242424242',
'card_expiry' => '12/2030',
'card_cvc' => '123',
]),
]);
$sub = json_decode(curl_exec($ch), true);
const res = await fetch('https://onhere.net/api/v1/subscriptions', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_test_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
plan: 'plan_9Kd2mZ0pQ7rLtV3xW1cB',
customer_email: 'buyer@example.com',
card_number: '4242424242424242',
card_expiry: '12/2030',
card_cvc: '123',
}),
});
const sub = await res.json();
The subscription is returned with its status, charge count and next charge date.
{
"id": "sub_2pQ7rLtV3xW1cB9Kd2mZ",
"object": "subscription",
"plan": "plan_9Kd2mZ0pQ7rLtV3xW1cB",
"amount": 1999,
"currency": "EUR",
"description": "Pro monthly",
"customer_email": "buyer@example.com",
"interval": "month",
"interval_count": 1,
"total_cycles": 12,
"min_cycles": 3,
"status": "active",
"livemode": false,
"charge_count": 1,
"next_charge": 1786316733,
"created": 1783724733
}
List subscriptions
Returns your subscriptions for the current mode, newest first.
Retrieve a subscription
Pause, resume or cancel
Pause suspends charging; resume continues it; cancel stops it for good. Canceling from the API is immediate and ignores the plan minimum term (which only restricts the customer self-cancel link).
Refunds
Refund a payment, fully or partially.
Create a refund
Refunds a payment. Without an amount the remaining balance is refunded.
Parameters
| Parameter | Type | Description |
|---|---|---|
| payment | string | The id of the payment to refund. Required. |
| amount | integer | Amount to refund in the smallest currency unit. Defaults to the full remaining amount. |
| reason | string | An optional reason stored with the refund. |
curl https://onhere.net/api/v1/refunds \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"payment": "txn_w2UlYqe9ZMoIhvofDhyj", "amount": 1000}'
<?php
$ch = curl_init('https://onhere.net/api/v1/refunds');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer sk_test_...',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'payment' => 'txn_w2UlYqe9ZMoIhvofDhyj',
'amount' => 1000,
]),
]);
$refund = json_decode(curl_exec($ch), true);
const res = await fetch('https://onhere.net/api/v1/refunds', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_test_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({ payment: 'txn_w2UlYqe9ZMoIhvofDhyj', amount: 1000 }),
});
const refund = await res.json();
{
"id": "re_wfWPRqfVIuGAAtiY4Nup",
"object": "refund",
"payment": "txn_w2UlYqe9ZMoIhvofDhyj",
"amount": 1000,
"reason": "",
"status": "succeeded",
"created": 1783725100
}
List refunds
Returns your refunds, most recent first.
Refund rules
Only succeeded incoming payments can be refunded. Bonus credits (source "bonus") and payouts are ledger entries, not customer payments — refunding one returns a refund_not_allowed error. The total refunded can never exceed the original payment.
A refund is never blocked by the merchant's balance. If there are no funds, the refund still succeeds and the balance goes negative; the deficit is covered automatically by future payments, and nothing can be paid out until the balance is positive again.
Every refund fires refund.created and refund.succeeded to your webhook endpoints, and notifies the merchant in the dashboard.
Webhooks
Receive events when things happen in your account.
Add an endpoint in your dashboard under Developers → Webhooks, or register one via the API (below), and choose which events to receive. We POST a JSON event to your URL for each subscribed event.
Event types
| transaction.created | A payment was created. |
| transaction.succeeded | A payment succeeded. |
| transaction.failed | A payment failed. |
| refund.created | A refund was created. |
| refund.succeeded | A refund succeeded. |
| refund.failed | A refund failed. |
| subscription.created | A subscription was created. |
| subscription.activated | A subscription first charge was approved and it became active. |
| subscription.charged | A recurring charge was created for a subscription. |
| subscription.payment_failed | A subscription charge was declined; the subscription entered dunning (retries). |
| subscription.paused | A subscription was paused. |
| subscription.resumed | A paused subscription was resumed. |
| subscription.canceled | A subscription was canceled. |
| subscription.completed | A subscription reached its total payments and completed. |
Event payload
{
"id": "evt_LiDAyYvbbNlr2vluuIpY",
"type": "transaction.succeeded",
"created": 1783724733,
"data": {
"id": "txn_w2UlYqe9ZMoIhvofDhyj",
"object": "payment",
"amount": 2500,
"currency": "EUR",
"reference": "wc_order_1057",
"payment_link": "pl_jLdWvwZU5Wj8P1HvgE4F",
"status": "succeeded"
}
}
Verifying signatures
Every request carries an Onhere-Signature header: t is the timestamp and v1 is an HMAC-SHA256 of "{t}.{body}" using your endpoint signing secret (whsec_). Recompute it and compare before trusting the event.
<?php
$payload = file_get_contents('php://input');
$header = $_SERVER['HTTP_ONHERE_SIGNATURE'] ?? '';
$secret = 'whsec_...'; // your endpoint signing secret
parse_str(str_replace(',', '&', $header), $parts);
$expected = hash_hmac('sha256', $parts['t'] . '.' . $payload, $secret);
if (hash_equals($expected, $parts['v1'])) {
$event = json_decode($payload, true);
// handle $event['type']
}
import crypto from 'node:crypto';
function verify(payload, header, secret) {
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
const expected = crypto
.createHmac('sha256', secret)
.update(parts.t + '.' + payload)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
Retries
If your endpoint does not return a 2xx status, we retry with increasing delays. After too many failures the endpoint is disabled and we notify you; you can re-enable it and resend deliveries from the dashboard.
Managing endpoints via the API
Create and remove endpoints programmatically — a plugin can self-register its callback URL on setup, with no manual dashboard step.
Create an endpoint
Registers an endpoint and returns its whsec_ signing secret.
Parameters
| Parameter | Type | Description |
|---|---|---|
| url | string | The https URL that receives events. Required. |
| events | array | Array of event types to subscribe to. Defaults to all events. |
| description | string | An optional label for the endpoint. |
curl https://onhere.net/api/v1/webhooks \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://shop.example.com/?wc-api=upnow",
"events": ["transaction.succeeded", "transaction.failed", "refund.succeeded"]
}'
const res = await fetch('https://onhere.net/api/v1/webhooks', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_test_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://shop.example.com/?wc-api=upnow',
events: ['transaction.succeeded', 'transaction.failed', 'refund.succeeded'],
}),
});
const endpoint = await res.json();
// endpoint.secret is returned ONLY here — store it to verify signatures.
{
"id": "whe_SX5TaMkJL7SQE62q1h9c",
"object": "webhook_endpoint",
"url": "https://shop.example.com/?wc-api=upnow",
"description": null,
"events": ["transaction.succeeded", "transaction.failed", "refund.succeeded"],
"status": "enabled",
"secret": "whsec_...",
"created": 1783724733
}
The signing secret is returned only once, in this create response — store it securely.
List endpoints
Returns your endpoints (without the signing secret).
Delete an endpoint
Removes an endpoint by its id.
WooCommerce
Add Here as a payment method in your WooCommerce store. Setup is a single field — paste your API key and the plugin does the rest.
Download the plugin WordPress 5.8+ · WooCommerce 6.0+ · PHP 7.4+
1. Install
- Download the plugin ZIP above.
- In WordPress admin open Plugins → Add New → Upload Plugin, choose the ZIP, and click Install Now.
- Click Activate.
Prefer a manual install? Unzip the folder into wp-content/plugins/ and activate it from the Plugins screen.
2. Connect your key
- Open WooCommerce → Settings → Payments and enable Here (or click Manage).
- Paste your API secret key (sk_live_… or sk_test_…) and click Save changes.
That is the only field you need. On save the plugin validates your key and registers its webhook automatically — test or live mode is detected from the key prefix.
Where is my key? Sign in to your account and open Developers → API keys to copy your secret key.
3. How payments flow
Once connected, every order runs through Here:
- At checkout the shopper is redirected to the secure Here page to pay by card, then returned to your store.
- The order is held as pending until the outcome is confirmed.
- A signed webhook finalizes it: transaction.succeeded marks the order paid, transaction.failed marks it failed.
- Refunds started from the order screen are sent back through the API.
Every webhook is verified with an HMAC-SHA256 signature, so only genuine Here events change your orders.
OpenCart
Add Here as a payment extension in your OpenCart store. Paste your API key and the extension registers its own webhook.
Download the extension OpenCart 3.0.x · PHP with cURL
1. Install
- Download the extension ZIP above and install it under Extensions → Installer (or copy the folders into your store root).
- Open Extensions → Extensions, choose Payments, find Here and click Install (+).
- Click Edit (the pencil) to open its settings.
Manual install? Copy the admin/, catalog/ and system/ folders into your OpenCart root.
2. Connect your key
- Set Status to Enabled (optionally pick the order statuses used for paid and failed orders).
- Paste your API secret key (sk_live_… or sk_test_…) and click Save.
That is the only required field. On save the extension validates your key and registers its webhook automatically. Your store must be reachable over public HTTPS with cURL enabled.
Where is my key? Sign in to your account and open Developers → API keys to copy your secret key.
3. How payments flow
Once connected, every order runs through Here:
- At checkout the shopper is redirected to the secure Here page to pay by card, then returned to your store.
- The order is held as pending until the outcome is confirmed.
- A signed webhook finalizes it: transaction.succeeded marks the order paid, transaction.failed marks it failed.
- Refunds started from the order screen are sent back through the API.
Every webhook is verified with an HMAC-SHA256 signature, so only genuine Here events change your orders.
PrestaShop
Add Here as a payment module in your PrestaShop store. One API key — the module registers its webhook and manages order states for you.
Download the module PrestaShop 1.7 / 8 · PHP with cURL
1. Install
- In the Module Manager click Upload a module and select the module ZIP (or copy the upnow folder into /modules).
- Install the Here module.
- Click Configure.
Manual install? Copy the upnow folder into your shop's /modules directory, then install it from the Module Manager.
2. Connect your key
- Paste your API secret key (sk_live_… or sk_test_…) and click Save.
That is the only field you need. On save the module validates your key, registers its webhook, and creates the “Awaiting Here payment” order state automatically.
Where is my key? Sign in to your account and open Developers → API keys to copy your secret key.
3. How payments flow
Once connected, every order runs through Here:
- At checkout the shopper is redirected to the secure Here page to pay by card, then returned to your store.
- The order is held as pending until the outcome is confirmed.
- A signed webhook finalizes it: transaction.succeeded marks the order paid, transaction.failed marks it failed.
- Refunds started from the order screen are sent back through the API.
Every webhook is verified with an HMAC-SHA256 signature, so only genuine Here events change your orders.
Magento 2
Add Here as a payment method in your Magento 2 store. Paste your API key and the module self-registers its webhook.
Download the module Magento 2.4.x · PHP with cURL
1. Install
- Copy the module to app/code/Here/Payments in your Magento root.
- From the Magento root run: bin/magento module:enable Here_Payments && bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush
- In production mode also run bin/magento setup:static-content:deploy.
Hosting the module in your own repository? Require it with Composer and run the same setup commands.
2. Connect your key
- Open Stores → Configuration → Sales → Payment Methods → Here and set Enabled to Yes.
- Paste your API secret key (sk_live_… or sk_test_…) and click Save config.
That is the only required field. Saving validates your key and registers the webhook automatically; the signing secret is stored for you.
Where is my key? Sign in to your account and open Developers → API keys to copy your secret key.
3. How payments flow
Once connected, every order runs through Here:
- At checkout the shopper is redirected to the secure Here page to pay by card, then returned to your store.
- The order is held as pending until the outcome is confirmed.
- A signed webhook finalizes it: transaction.succeeded marks the order paid, transaction.failed marks it failed.
- Refunds started from the order screen are sent back through the API.
Every webhook is verified with an HMAC-SHA256 signature, so only genuine Here events change your orders.