Μετάβαση στο περιεχόμενο
Τεκμηρίωση

Direct API

Με το Direct API, η φόρμα κάρτας αποτελεί μέρος του ιστότοπού σας και ο διακομιστής σας υποβάλλει τα στοιχεία της κάρτας στο Payniko. Το πρόγραμμα περιήγησης του πληρωτή ανακατευθύνεται στο Payniko μόνο για το 3-D Secure και για BIN τύπου hosted. Χρησιμοποιήστε το Direct API όταν η φόρμα κάρτας πρέπει να βρίσκεται στη δική σας σελίδα.

Βήματα ενσωμάτωσης

  1. Έλεγχος BIN

    Μόλις ο πληρωτής εισαγάγει έξι ψηφία, καλέστε το GET /api/payments/bin/{bin6}. Το payment_mode υποδεικνύει αν πρέπει να συλλέξετε τα πλήρη στοιχεία της κάρτας στη φόρμα σας ή να παραπέμψετε τον πληρωτή στη σελίδα πληρωμής.

  2. Δημιουργία της πληρωμής

    Καλέστε το POST /api/payments/direct με τα στοιχεία της κάρτας ή, για BIN τύπου hosted, μόνο με bin6.

  3. Ολοκλήρωση του 3-D Secure

    Αν η κατάσταση είναι requires_action, ανακατευθύνετε το πρόγραμμα περιήγησης στο next_action.url. Στη συνέχεια, το πρόγραμμα περιήγησης επιστρέφει στο success_url ή στο fail_url σας με υπογεγραμμένες παραμέτρους.

  4. Επιβεβαίωση του αποτελέσματος

    Περιμένετε την ειδοποίηση webhook payment.succeeded ή payment.failed ή καλέστε το GET /api/payments/{payment_id}. Εκτελέστε την παραγγελία μόνο σε κατάσταση succeeded.

Ροή πληρωμής

Your server                          Payniko                        Payer's browser
 1  GET /api/payments/bin/{bin6} ───►  payment_mode: direct | hosted
 2  POST /api/payments/direct  ─────►  200  requires_action + next_action.url
                                            (or processing / succeeded / failed)
 3  redirect to next_action.url ──────────────────────────────────►  3-D Secure page
                                       ───────────────────────────►  success_url / fail_url
 4  webhook  ◄───────────────────────  payment.succeeded / payment.failed
    GET /api/payments/{payment_id} ──►  current status

Προαπαιτούμενα

GET/api/payments/bin/{bin6}

1. Έλεγχος BIN

Πριν δημιουργήσετε την πληρωμή, ο έλεγχος BIN υποδεικνύει αν η πληρωμή με την κάρτα μπορεί να γίνει στη φόρμα σας (direct) ή πρέπει να ολοκληρωθεί στη σελίδα πληρωμής του Payniko (hosted). Ο έλεγχος δεν συνεπάγεται καμία χρέωση.

Παράμετροι

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφήΠαράδειγμα
bin6string · pathΥποχρεωτικόΤα πρώτα έξι ψηφία της κάρτας.540061
amountstring · queryΥποχρεωτικόΠοσό με δύο δεκαδικά ψηφία, για παράδειγμα 100.00. Ελέγχεται έναντι των ορίων του λογαριασμού σας.100.00
currencystring · queryΠροαιρετικόUSD, EUR, AED ή TRY. Προεπιλογή είναι το κύριο νόμισμα του συστήματος. Χρησιμοποιήστε το ίδιο νόμισμα κατά τη δημιουργία της πληρωμής.USD

Οι λοιπές παράμετροι ερωτήματος απορρίπτονται. Η συμβολοσειρά ερωτήματος δεν αποτελεί μέρος της υπογραφής.

./payniko.sh GET '/api/payments/bin/540061?amount=100.00&currency=USD'
import {api} from './payniko.mjs';

const lookup = await api('GET', '/api/payments/bin/540061?amount=100.00&currency=USD');
console.log(lookup);
<?php
require __DIR__ . '/payniko.php';

$lookup = payniko_api('GET', '/api/payments/bin/540061?amount=100.00&currency=USD');
print_r($lookup);
from payniko import api

lookup = api("GET", "/api/payments/bin/540061?amount=100.00&currency=USD")
print(lookup)

Απάντηση · Παράδειγμα

{
  "data": {
    "bin6": "540061",
    "bank": "Test Bank",
    "network": "mastercard",
    "card_type": "credit",
    "card_program": null,
    "country": "TR",
    "domestic": true,
    "payment_mode": "hosted"
  }
}

Απάντηση · 200

Επιστρέφει { "data": ... } με τα ακόλουθα πεδία:

ΠεδίοΤύποςΠεριγραφή
bin6stringΤα έξι ψηφία που υποβλήθηκαν.
bankstring | nullΗ εκδότρια τράπεζα, αν είναι γνωστή.
networkstring | nullΤο δίκτυο της κάρτας, αν είναι γνωστό.
visamastercardamextroy
card_typestring | nullΟ τύπος της κάρτας, αν είναι γνωστός.
creditdebitprepaid
card_programstring | nullΤο πρόγραμμα της κάρτας. Προς το παρόν είναι πάντα null.
countrystring | nullΗ χώρα έκδοσης (ISO 3166-1 alpha-2), αν είναι γνωστή.
domesticbooleantrue για εγχώρια κάρτα· false σε κάθε άλλη περίπτωση ή αν δεν είναι γνωστό.
payment_modestring | nulldirect: συλλέξτε τα πλήρη στοιχεία της κάρτας. hosted: παραπέμψτε τον πληρωτή στη σελίδα πληρωμής. Οποιαδήποτε άλλη τιμή, συμπεριλαμβανομένου του null: μη δημιουργήσετε πληρωμή.
directhosted

Χειρισμός της απάντησης

  • direct: συλλέξτε τα πλήρη στοιχεία της κάρτας και δημιουργήστε την πληρωμή με card.
  • hosted: δημιουργήστε την πληρωμή μόνο με bin6. Ο πληρωτής εισάγει τα στοιχεία της κάρτας στη σελίδα πληρωμής του Payniko.
  • Οποιοδήποτε άλλο payment_mode ή σφάλμα κάρτας 409 (0055230, 0055231, 0055233): μη δημιουργήσετε πληρωμή και ζητήστε από τον πληρωτή άλλη κάρτα με ουδέτερο μήνυμα, καθώς δεν πρόκειται για απόρριψη από την τράπεζα. Το 422 0055235 υποδηλώνει πρόβλημα με το ποσό. Σε περίπτωση 429 ή 5xx, επαναλάβετε τον ίδιο έλεγχο αργότερα.

Παράδειγμα

import {api} from './payniko.mjs';

let mode = null;
try {
  const lookup = await api('GET', '/api/payments/bin/411111?amount=100.00&currency=USD');
  mode = lookup.data.payment_mode;
} catch (error) {
  // No answer, 429 or 5xx: temporary. Try the same lookup again later.
  if (error.status === undefined || error.status === 429 || error.status >= 500) throw error;
  // Other 4xx: error.problem.code says why, for example 0055233.
}
if (mode !== 'direct' && mode !== 'hosted') {
  // Also null: do not create a payment. Ask for another card with a neutral message.
}

Πιθανά σφάλματα

POST/api/payments/directΑπαιτείται Idempotency-Key

2. Δημιουργία πληρωμής

Επιστρέφει πάντα 200 με την τρέχουσα πληρωμή, ακόμη και όταν το ίδιο αίτημα αποστέλλεται ξανά. Η απόρριψη κάρτας δεν αποτελεί σφάλμα HTTP· η απάντηση είναι 200 με status: failed.

Σώμα αιτήματος

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφήΠαράδειγμα
merchant_order_idstringΥποχρεωτικόΟ κωδικός της παραγγελίας σας: 1–64 χαρακτήρες από το σύνολο A-Z a-z 0-9 . _ -. Μία πληρωμή ανά κωδικό και περιβάλλον· η μοναδικότητα ελέγχεται χωρίς διάκριση πεζών-κεφαλαίων.ORDER-2026-002
amountstringΥποχρεωτικόΠοσό με δύο δεκαδικά ψηφία, για παράδειγμα "100.00", εντός των ορίων του λογαριασμού σας."100.00"
currencystringΠροαιρετικόΠροεπιλογή είναι το κύριο νόμισμα του συστήματος. Χρησιμοποιήστε το ίδιο νόμισμα με τον έλεγχο BIN.
USDEURAEDTRY
USD
webhook_urlstring · uriΥποχρεωτικόΔημόσιο URL HTTPS στη θύρα 443 που λαμβάνει τα webhooks αυτής της πληρωμής, έως 500 χαρακτήρες. Τοπικές διευθύνσεις δεν γίνονται δεκτές, ούτε στο sandbox· το όνομα κεντρικού υπολογιστή πρέπει να επιλύεται σε δημόσια διεύθυνση IP τη στιγμή του αιτήματος, αλλιώς 422 9000008.https://merchant.example/webhooks/payments
success_urlstring · uriΥποχρεωτικόΠροορισμός ανακατεύθυνσης του προγράμματος περιήγησης όταν η πληρωμή έχει ολοκληρωθεί επιτυχώς. HTTPS, έως 2048 χαρακτήρες, χωρίς στοιχεία χρήστη (userinfo) ή αναγνωριστικό τμήματος (fragment). Το sandbox δέχεται επίσης http://localhost, 127.0.0.1 και [::1].https://merchant.example/payment/success
fail_urlstring · uriΥποχρεωτικόΠροορισμός ανακατεύθυνσης του προγράμματος περιήγησης σε κάθε άλλη περίπτωση. Ισχύουν οι ίδιοι κανόνες με το success_url.https://merchant.example/payment/failure
customerobjectΥποχρεωτικόΤα στοιχεία επικοινωνίας του πληρωτή· χρησιμοποιούνται για το αποτέλεσμα της πληρωμής, την απόδειξη και τα βήματα επαλήθευσης της τράπεζας. Γίνονται δεκτά μόνο τα email και phone· κάθε άλλο πεδίο μέσα στο customer απορρίπτεται με 422 1000001.{ … }
customer.emailstringΥποχρεωτικόΗ πραγματική διεύθυνση e-mail του πληρωτή: RFC 5322, έως 254 χαρακτήρες, με τομέα που περιέχει τελεία. Αποθηκεύεται με πεζά γράμματα.[email protected]
customer.phonestringΥποχρεωτικόΟ πραγματικός αριθμός τηλεφώνου του πληρωτή σε διεθνή μορφή (+ κωδικός χώρας, E.164), για παράδειγμα +37061234567. Κανόνας για την Τουρκία: +90 και ο 10ψήφιος εθνικός αριθμός (5xx κινητό, 2xx, 3xx, 4xx σταθερό, 8xx ειδικοί αριθμοί). Αριθμός που στέλνεται χωρίς κωδικό χώρας αντιμετωπίζεται ως τουρκικός (+90).+37061234567
cardobjectΥπό προϋποθέσειςΤα στοιχεία κάρτας που εισήγαγε ο πληρωτής (δείτε τον πίνακα παρακάτω). Στείλτε είτε card είτε bin6, όχι και τα δύο.{ … }
bin6stringΥπό προϋποθέσειςΜόνο για BIN τύπου hosted: τα πρώτα έξι ψηφία. Ο πληρωτής εισάγει τα στοιχεία της κάρτας στη σελίδα πληρωμής. Αίτημα για BIN τύπου direct μόνο με bin6 επιστρέφει 409 0055230.540061
card.numberstringΥποχρεωτικό13–19 ψηφία χωρίς κενά, με έγκυρο ψηφίο ελέγχου (15 ψηφία για American Express).4355090000044242
card.holder_namestringΥποχρεωτικόΤο ονοματεπώνυμο όπως αναγράφεται στην κάρτα, 2–120 χαρακτήρες.JONAS KAZLAUSKAS
card.expiry_monthstringΥποχρεωτικόΔύο ψηφία, από 01 έως 12.12
card.expiry_yearstringΥποχρεωτικόΔύο ψηφία, για παράδειγμα 30. Η κάρτα δεν πρέπει να έχει λήξει και το έτος μπορεί να είναι το πολύ 30 χρόνια στο μέλλον.30
card.cvvstringΥποχρεωτικόΑκριβώς 3 ψηφία, ή 4 ψηφία για American Express. Ποτέ μην το αποθηκεύετε ούτε να το καταγράφετε.123

Όλες οι τιμές της κάρτας είναι συμβολοσειρές. Τα άγνωστα πεδία μέσα στο card απορρίπτονται.

Για hosted BIN, η σελίδα πληρωμής δεν ζητά ξανά από τον πληρωτή τη διεύθυνση e-mail και τον αριθμό τηλεφώνου. Για λόγους απορρήτου, το customer δεν επιστρέφεται στο αντικείμενο πληρωμής ούτε στα webhooks.

ΠεδίοΑιτίαΜήνυμα στο errors
customer.emailΜη έγκυρη μορφή ή περισσότεροι από 254 χαρακτήρες.customer.email must be a valid e-mail address (max 254 characters).
customer.emailΔιεύθυνση-δείγμα, παράδειγμα ή προσωρινή διεύθυνση.customer.email must be the payer's real address; placeholder, example or disposable addresses (example.com, test@…, mailinator…) are not accepted.
customer.phoneΜη έγκυρος αριθμός σε διεθνή μορφή.customer.phone must be a valid phone number in international format (e.g. +37061234567).
customer.phoneΜοτίβο επαναλαμβανόμενων ή διαδοχικών ψηφίων.customer.phone must be the payer's real number; repeated or sequential digit patterns (5555555555, 1234567890) are not accepted.
customer.phoneΤουρκικός αριθμός που δεν έχει τη μορφή +90 και 10 ψηφία που αρχίζουν από 2, 3, 4, 5 ή 8.customer.phone for Türkiye must be +90 followed by a 10-digit number starting with 2, 3, 4, 5 or 8 (e.g. +905321234567).

HTTP 422 · 1000001

{
  "type": "https://payniko.com/problems/1000001",
  "title": "Validation failed",
  "status": 422,
  "detail": "The submitted fields are not valid.",
  "code": "1000001",
  "correlation_id": "4c7a1e9d-2b3f-4d85-9a6e-0f1b2c3d4e5f",
  "errors": {
    "customer.email": [
      "customer.email must be the payer's real address; placeholder, example or disposable addresses (example.com, test@…, mailinator…) are not accepted."
    ],
    "customer.phone": [
      "customer.phone must be the payer's real number; repeated or sequential digit patterns (5555555555, 1234567890) are not accepted."
    ]
  }
}

Αν ένα αίτημα απορριφθεί λόγω του customer, δείξτε στον πληρωτή την αιτία με σαφήνεια (για παράδειγμα: εισαγάγετε τη δική σας διεύθυνση e-mail ή τον αριθμό τηλεφώνου σας) και αφήστε τον να διορθώσει το πεδίο πριν δημιουργήσετε ξανά την πληρωμή. Το Direct API επιστρέφει τα μηνύματα του errors μεταφρασμένα· ο πίνακας δείχνει το αγγλικό κείμενο.

Οι σελίδες συνδέσμων πληρωμής της Payniko εφαρμόζουν τους ίδιους κανόνες στη διεύθυνση e-mail και στον αριθμό τηλεφώνου που εισάγει εκεί ο πληρωτής και του δείχνουν την αιτία της απόρριψης.

Με στοιχεία κάρτας · Παράδειγμα

{
  "merchant_order_id": "ORDER-2026-002",
  "amount": "100.00",
  "currency": "USD",
  "webhook_url": "https://merchant.example/webhooks/payments",
  "success_url": "https://merchant.example/payment/success",
  "fail_url": "https://merchant.example/payment/failure",
  "customer": {
    "email": "[email protected]",
    "phone": "+37061234567"
  },
  "card": {
    "number": "4355090000044242",
    "holder_name": "JONAS KAZLAUSKAS",
    "expiry_month": "12",
    "expiry_year": "30",
    "cvv": "123"
  }
}
KEY="$(openssl rand -hex 16)"  # store with the order before sending; reuse it after network errors
./payniko.sh POST '/api/payments/direct' '{
  "merchant_order_id": "ORDER-2026-002",
  "amount": "100.00",
  "currency": "USD",
  "webhook_url": "https://merchant.example/webhooks/payments",
  "success_url": "https://merchant.example/payment/success",
  "fail_url": "https://merchant.example/payment/failure",
  "customer": {
    "email": "[email protected]",
    "phone": "+37061234567"
  },
  "card": {
    "number": "4355090000044242",
    "holder_name": "JONAS KAZLAUSKAS",
    "expiry_month": "12",
    "expiry_year": "30",
    "cvv": "123"
  }
}' "$KEY"
import {api, randomUUID} from './payniko.mjs';

const key = randomUUID(); // Store this key with the order before sending; reuse it after network errors.
const payment = await api('POST', '/api/payments/direct', {
  "merchant_order_id": "ORDER-2026-002",
  "amount": "100.00",
  "currency": "USD",
  "webhook_url": "https://merchant.example/webhooks/payments",
  "success_url": "https://merchant.example/payment/success",
  "fail_url": "https://merchant.example/payment/failure",
  "customer": {
    "email": "[email protected]",
    "phone": "+37061234567"
  },
  "card": {
    "number": "4355090000044242",
    "holder_name": "JONAS KAZLAUSKAS",
    "expiry_month": "12",
    "expiry_year": "30",
    "cvv": "123"
  }
}, key);
console.log(payment);
<?php
require __DIR__ . '/payniko.php';

$key = bin2hex(random_bytes(16)); // store with the order; reuse it after network errors
$payment = payniko_api('POST', '/api/payments/direct', [
    "merchant_order_id" => 'ORDER-2026-002',
    "amount" => '100.00',
    "currency" => 'USD',
    "webhook_url" => 'https://merchant.example/webhooks/payments',
    "success_url" => 'https://merchant.example/payment/success',
    "fail_url" => 'https://merchant.example/payment/failure',
    "customer" => [
        "email" => '[email protected]',
        "phone" => '+37061234567',
    ],
    "card" => [
        "number" => '4355090000044242',
        "holder_name" => 'JONAS KAZLAUSKAS',
        "expiry_month" => '12',
        "expiry_year" => '30',
        "cvv" => '123',
    ],
], $key);
print_r($payment);
from payniko import api
import uuid

key = str(uuid.uuid4())  # store with the order; reuse it after network errors
payment = api("POST", "/api/payments/direct", {
    "merchant_order_id": "ORDER-2026-002",
    "amount": "100.00",
    "currency": "USD",
    "webhook_url": "https://merchant.example/webhooks/payments",
    "success_url": "https://merchant.example/payment/success",
    "fail_url": "https://merchant.example/payment/failure",
    "customer": {
        "email": "[email protected]",
        "phone": "+37061234567"
    },
    "card": {
        "number": "4355090000044242",
        "holder_name": "JONAS KAZLAUSKAS",
        "expiry_month": "12",
        "expiry_year": "30",
        "cvv": "123"
    }
}, key)
print(payment)

Απάντηση · Παράδειγμα

{
  "data": {
    "payment_id": "3c2d7a4e-5b1f-4e8a-9d06-7f2b1c9e4a35",
    "merchant_order_id": "ORDER-2026-002",
    "flow": "direct",
    "status": "requires_action",
    "amount": "100.00",
    "currency": "USD",
    "environment": "sandbox",
    "next_action": {
      "type": "redirect",
      "url": "https://payniko.com/example-authentication-step",
      "expires_at": "2026-11-01T12:30:00.000Z"
    },
    "card": {
      "bin6": "435509",
      "last_four": "4242",
      "network": "visa",
      "bank": "Test Bank"
    },
    "failure": null,
    "created_at": "2026-11-01T12:00:00.000Z",
    "expires_at": "2026-11-01T12:30:00.000Z",
    "completed_at": null
  }
}

Με bin6 για BIN τύπου hosted · Παράδειγμα

{
  "merchant_order_id": "ORDER-2026-003",
  "amount": "100.00",
  "currency": "USD",
  "webhook_url": "https://merchant.example/webhooks/payments",
  "success_url": "https://merchant.example/payment/success",
  "fail_url": "https://merchant.example/payment/failure",
  "customer": {
    "email": "[email protected]",
    "phone": "+37061234567"
  },
  "bin6": "540061"
}

Ερμηνεία της απάντησης

ΚατάστασηΣυνιστώμενη ενέργεια
requires_actionΑνακατευθύνετε το πρόγραμμα περιήγησης στο next_action.url (3-D Secure ή σελίδα πληρωμής για BIN τύπου hosted).
processingΠεριμένετε την ειδοποίηση webhook και μη δημιουργήσετε νέα πληρωμή.
succeededΕκτελέστε την παραγγελία.
failedΕμφανίστε το failure.message και ζητήστε από τον πληρωτή άλλη κάρτα.
  • Η κλήση μπορεί να διαρκέσει αρκετά δευτερόλεπτα όσο η Payniko επικοινωνεί με την τράπεζα. Χρησιμοποιήστε χρονικό όριο τουλάχιστον 60 δευτερολέπτων και, μετά από λήξη του, στείλτε ξανά το αίτημα με το ίδιο Idempotency-Key και σώμα. Όσο το πρώτο αίτημα εκτελείται ακόμη (έως 3 λεπτά), η επανάληψη επιστρέφει 409 0055503 με metadata.retry_class: retry_same_request: περιμένετε λίγα δευτερόλεπτα και στείλτε ξανά το ίδιο αίτημα.
  • Για BIN τύπου hosted, τυχόν card που αποστέλλεται αγνοείται και ο πληρωτής συνεχίζει στη σελίδα πληρωμής.
  • Αν υπάρχει ήδη πληρωμή για το merchant_order_id ή αν το ίδιο Idempotency-Key αποσταλεί με διαφορετικό σώμα, το αίτημα απορρίπτεται με 409 0055503.
  • Τα μη έγκυρα στοιχεία κάρτας απορρίπτονται με 409 0055234. Το metadata.developer_detail προσδιορίζει το πεδίο: card_number_invalid, card_expiry_invalid ή card_cvv_invalid. Ζητήστε από τον πληρωτή να εισαγάγει ξανά τα στοιχεία της κάρτας.
  • Στοιχεία επικοινωνίας που λείπουν ή δεν είναι έγκυρα απορρίπτονται με 422 1000001· το errors αναφέρει customer, customer.email ή customer.phone.

3. 3-D Secure και πρόγραμμα περιήγησης

Όταν η κατάσταση είναι requires_action, το πρόγραμμα περιήγησης του πληρωτή πρέπει να ανοίξει το next_action.url, όπου η τράπεζα εκτελεί τον έλεγχο 3-D Secure ή ο πληρωτής συνεχίζει στη σελίδα πληρωμής.

  • Ανακατευθύνετε ολόκληρη τη σελίδα στο next_action.url ή ανοίξτε το σε νέα καρτέλα· και οι δύο μέθοδοι υποστηρίζονται πάντα.
  • Η σελίδα δεν ζητά ξανά τα στοιχεία της κάρτας· συλλέγει μόνο τα δεδομένα του προγράμματος περιήγησης που απαιτεί η τράπεζα.
  • Χρησιμοποιείτε πάντα το πιο πρόσφατο next_action.url πριν από το next_action.expires_at του (το τέλος του βήματος 3-D Secure). Μην ανοίγετε ποτέ ξανά προηγούμενο URL.
  • Στη συνέχεια, το πρόγραμμα περιήγησης ανακατευθύνεται στο success_url (μόνο σε succeeded) ή στο fail_url με υπογεγραμμένες παραμέτρους (δείτε URL επιστροφής). Έπειτα, ανακτήστε την πληρωμή.

Ενσωμάτωση σε πλαίσιο

Η σελίδα 3-D Secure δεν μπορεί να εμφανιστεί μέσα σε πλαίσιο· ανακατευθύνετε ολόκληρη τη σελίδα ή ανοίξτε νέα καρτέλα. Μόνο η σελίδα πληρωμής ενός BIN τύπου hosted επιτρέπεται να ενσωματωθεί σε πλαίσιο, μόνο με κλειδιά παραγωγής και μόνο στην ακριβή προέλευση (origin) του success_url της πληρωμής. Η σελίδα πληρωμής του Hosted API δεν μπορεί ποτέ να ενσωματωθεί σε πλαίσιο.

Η σελίδα πληρωμής ενός BIN τύπου hosted ενσωματώνει την ασφαλή οθόνη πληρωμής και 3-D Secure του ίδιου του παρόχου πληρωμών και μπορεί να εμφανιστεί ως iframe μέσα στη δική σας φόρμα πληρωμής.

Αν ενσωματώσετε σε πλαίσιο τη σελίδα πληρωμής ενός BIN τύπου hosted, τα μηνύματα που αποστέλλει στο παράθυρό σας χρησιμεύουν μόνο ως σήμα για να ελέγξετε την πληρωμή. Αποδεχτείτε τα μόνο από την προέλευση του next_action.url και από το δικό σας πλαίσιο, αγνοήστε το περιεχόμενό τους και αναθέστε την ανάκτηση της πληρωμής στον διακομιστή σας.

Πρόγραμμα περιήγησης

// Only if you show the payment page of a hosted BIN in a frame on the exact origin of success_url.
// nextActionUrl: next_action.url from your server.
const pageOrigin = new URL(nextActionUrl).origin;
window.addEventListener('message', (event) => {
  if (event.origin !== pageOrigin || event.source !== frame.contentWindow) return;
  // A wake-up call only: ignore event.data. Ask your server to read the payment.
  fetch('/checkout/ORDER-2026-002/refresh', {method: 'POST', credentials: 'same-origin'});
});

Αντικείμενο πληρωμής

Οι κλήσεις δημιουργίας και ανάκτησης επιστρέφουν αυτό το αντικείμενο μέσα στο data, και κάθε ειδοποίηση webhook πληρωμής το περιέχει. Η δομή του είναι ίδια στο Hosted API και στο Direct API.

ΠεδίοΤύποςΠεριγραφή
payment_idstring · LUVEI-ABCD-123456Το αναγνωριστικό της πληρωμής στο Payniko . Αποθηκεύστε το μαζί με την παραγγελία σας.
merchant_order_idstringΟ κωδικός της παραγγελίας σας, ακριβώς όπως υποβλήθηκε.
flowstringhosted για το Hosted API, direct για το Direct API.
hosteddirect
statusstringΗ τρέχουσα κατάσταση της πληρωμής· δείτε τον πίνακα καταστάσεων παρακάτω.
requires_actionprocessingsucceededfailedexpiredcancelled
amountstringΠοσό με δύο δεκαδικά ψηφία.
currencystringΤο νόμισμα του ποσού· το κύριο νόμισμα του συστήματος, αν δεν ορίστηκε νόμισμα.
environmentstringΤο περιβάλλον του κλειδιού με το οποίο δημιουργήθηκε η πληρωμή.
sandboxlive
next_actionobject | nullΗ επόμενη ενέργεια που απαιτείται από τον πληρωτή. Ορίζεται μόνο όσο το status είναι requires_action.
next_action.typestringΠάντα redirect.
next_action.urlstring · uriΑνοίξτε αυτό το URL στο πρόγραμμα περιήγησης του πληρωτή ακριβώς όπως επιστρέφεται. Μην το κατασκευάζετε και μην το τροποποιείτε ποτέ.
next_action.expires_atstring · date-timeΠροθεσμία χρήσης του URL. Στο Direct API, αντιστοιχεί στο τέλος του βήματος 3-D Secure και μπορεί να είναι νωρίτερα από το expires_at της ίδιας της πληρωμής· στο Hosted API, είναι η προθεσμία της πληρωμής. Μόλις παρέλθει, η πληρωμή μεταβαίνει στην επόμενη κατάστασή της και το next_action γίνεται null.
cardobject | nullΣτοιχεία κάρτας με απόκρυψη, μόλις γίνουν γνωστά.
card.bin6string | nullΤα πρώτα έξι ψηφία.
card.last_fourstring | nullΤα τελευταία τέσσερα ψηφία.
card.networkstring | nullΤο δίκτυο της κάρτας.
visamastercardamextroyunionpaydiscoverjcbdinersmaestro
card.bankstring | nullΗ εκδότρια τράπεζα, αν είναι γνωστή.
failureobject | nullΗ αιτία της αποτυχίας. Ορίζεται μόνο όταν το status είναι failed.
failure.codestringΚωδικός αιτίας για χρήση στη λογική της εφαρμογής σας· δείτε τη λίστα παρακάτω.
failure.messagestringΣύντομο μήνυμα κατάλληλο για εμφάνιση στον πληρωτή ως απλό κείμενο.
created_atstring · date-timeΧρόνος δημιουργίας της πληρωμής.
expires_atstring · date-timeΠροθεσμία ολοκλήρωσης της πληρωμής.
completed_atstring · date-time | nullΧρόνος κατά τον οποίο η πληρωμή περιήλθε σε τελική κατάσταση.

Το next_action μπορεί για σύντομο διάστημα να είναι null ακόμη και σε requires_action· σε αυτή την περίπτωση, ανακτήστε ξανά την πληρωμή. Ο πλήρης αριθμός κάρτας, το CVV, η ημερομηνία λήξης και το όνομα του κατόχου δεν επιστρέφονται ποτέ. Τα card.network και card.bank μπορεί να είναι null όταν δεν είναι γνωστά.

Τα στοιχεία customer που στάλθηκαν κατά τη δημιουργία της πληρωμής δεν αποτελούν μέρος αυτού του αντικειμένου και δεν εμφανίζονται στα webhooks.

Πληρωμή · Παράδειγμα

{
  "data": {
    "payment_id": "3c2d7a4e-5b1f-4e8a-9d06-7f2b1c9e4a35",
    "merchant_order_id": "ORDER-2026-002",
    "flow": "direct",
    "status": "requires_action",
    "amount": "100.00",
    "currency": "USD",
    "environment": "sandbox",
    "next_action": {
      "type": "redirect",
      "url": "https://payniko.com/example-authentication-step",
      "expires_at": "2026-11-01T12:30:00.000Z"
    },
    "card": {
      "bin6": "435509",
      "last_four": "4242",
      "network": "visa",
      "bank": "Test Bank"
    },
    "failure": null,
    "created_at": "2026-11-01T12:00:00.000Z",
    "expires_at": "2026-11-01T12:30:00.000Z",
    "completed_at": null
  }
}

Καταστάσεις πληρωμής Direct API

ΚατάστασηΣημασίαΣυνιστώμενη ενέργεια
requires_actionΤο πρόγραμμα περιήγησης πρέπει να ανοίξει το next_action.url για το 3-D Secure ή για τη σελίδα πληρωμής ενός BIN τύπου hosted.Ανακατευθύνετε τον πληρωτή στο next_action.url.
processingΗ απάντηση της τράπεζας εκκρεμεί. Αυτή η κατάσταση μπορεί επίσης να επιστραφεί απευθείας στην απάντηση δημιουργίας.Περιμένετε το webhook και μη δημιουργήσετε νέα πληρωμή. Αν η τράπεζα δεν απαντήσει ποτέ, η πληρωμή μπορεί να παραμείνει σε processing μέχρι τη συμφωνία και στη συνέχεια καταλήγει σε failed ή expired.
succeededΤα κεφάλαια έχουν εισπραχθεί.Εκτελέστε την παραγγελία.
failedΗ πληρωμή δεν ολοκληρώθηκε. Το failure περιέχει την αιτία.Εμφανίστε το failure.message. Για νέα προσπάθεια, δημιουργήστε νέα πληρωμή με νέο merchant_order_id.
expiredΟ πληρωτής δεν ολοκλήρωσε την πληρωμή πριν από το expires_at.Αν ο πληρωτής εξακολουθεί να επιθυμεί να πληρώσει, δημιουργήστε νέα πληρωμή.
cancelledΗ πληρωμή ακυρώθηκε.Μην εκτελέσετε την παραγγελία.
ΣενάριοΚατάστασηΣυμβάν
Έγκριση μετά από 3-D Securerequires_action → succeededpayment.succeeded
Απόρριψηfailedpayment.failed
Εκκρεμεί η απάντηση της τράπεζαςprocessingΚανένα έως το τελικό αποτέλεσμα
Καμία απάντηση από την τράπεζα· λήξη χρονικού ορίου της προσπάθειαςprocessing → failed / expiredpayment.failed
Ο πληρωτής δεν ξεκίνησε την πληρωμή και η προθεσμία παρήλθε (αν ο πληρωτής εγκαταλείψει την πληρωμή στο μέσο της διαδικασίας, μπορεί να καταλήξει σε failed)expiredpayment.failed

Αντιμετωπίστε κάθε κατάσταση που δεν αναφέρεται εδώ ως processing και ανακτήστε ξανά την πληρωμή.

Κωδικοί αποτυχίας

Μια πληρωμή σε failed περιέχει τα failure.code και failure.message. Χρησιμοποιήστε τον κωδικό στη λογική της εφαρμογής σας και εμφανίστε το μήνυμα στον πληρωτή ως απλό κείμενο.

ΚωδικόςΣημασία
payment_declinedΗ τράπεζα απέρριψε την πληρωμή.
do_not_honorΗ τράπεζα απέρριψε την πληρωμή χωρίς να αναφέρει αιτιολογία.
insufficient_fundsΗ κάρτα δεν διαθέτει επαρκή κεφάλαια.
card_limit_reachedΈχει συμπληρωθεί ένα όριο της κάρτας.
card_details_invalidΤα στοιχεία της κάρτας δεν είναι έγκυρα.
card_expiry_invalidΗ ημερομηνία λήξης δεν είναι έγκυρη ή η κάρτα έχει λήξει.
card_security_code_invalidΤο CVV δεν είναι έγκυρο.
card_not_activeΗ κάρτα είναι αποκλεισμένη ή ανενεργή.
card_brand_not_supportedΑυτό το δίκτυο καρτών δεν υποστηρίζεται.
three_ds_failedΟ έλεγχος ταυτότητας 3-D Secure απέτυχε ή δεν ολοκληρώθηκε.
payment_not_permittedΗ κάρτα δεν επιτρέπεται για αυτό το είδος πληρωμής.
amount_not_allowedΤο ποσό δεν επιτρέπεται για αυτή την κάρτα.
currency_not_supportedΤο νόμισμα δεν υποστηρίζεται για αυτή την κάρτα.
payment_details_rejectedΗ τράπεζα απέρριψε τα στοιχεία της πληρωμής.
duplicate_paymentΗ τράπεζα αναγνώρισε την πληρωμή ως διπλότυπη.
payment_timed_outΗ πληρωμή δεν ολοκληρώθηκε εγκαίρως.
bank_unavailableΔεν ήταν δυνατή η επικοινωνία με την τράπεζα.
bank_requested_retryΗ τράπεζα ζήτησε επανάληψη της προσπάθειας σε μεταγενέστερο χρόνο.
service_unavailableΔεν ήταν δυνατή η επεξεργασία της πληρωμής αυτή τη στιγμή.

Ενδέχεται να προστεθούν νέοι κωδικοί· χειριστείτε κάθε άγνωστο κωδικό ως payment_declined. Το failure.message μπορεί να περιέχει το κείμενο της ίδιας της τράπεζας· διαφορετικά, είναι στα αγγλικά στις ειδοποιήσεις webhook και ακολουθεί το Accept-Language στο GET.

URL επιστροφής

Κατά την επιστροφή του πληρωτή, το πρόγραμμα περιήγησης ανακατευθύνεται στο success_url μόνο αν η πληρωμή είναι succeeded και στο fail_url σε κάθε άλλη περίπτωση. Στο URL προστίθενται υπογεγραμμένες παράμετροι. Επαληθεύστε τις για να εμφανίσετε τη σωστή σελίδα και εκτελέστε την παραγγελία μόνο αφού η ειδοποίηση webhook ή ένα GET επιβεβαιώσει την κατάσταση succeeded.

Direct API: αν το αποτέλεσμα δεν είναι ακόμη τελικό όταν ο πληρωτής επιστρέφει από το 3-D Secure, το πρόγραμμα περιήγησης δεν ανακατευθύνεται στο fail_url· ο πληρωτής παραμένει σε μια ουδέτερη σελίδα αποτελέσματος της Payniko. Βασιστείτε στο webhook ή σε ένα GET για το αποτέλεσμα.

ΠεδίοΠεριγραφή
payment_idΤο αναγνωριστικό της πληρωμής .
merchant_order_idΟ κωδικός της παραγγελίας σας. Δεν υπογράφεται: χρησιμοποιήστε τον μόνο για τον εντοπισμό της παραγγελίας και κάντε την αντιστοίχιση με βάση το payment_id.
statusΚατάσταση της πληρωμής τη στιγμή της ανακατεύθυνσης, με τις ίδιες τιμές όπως στο GET. Πάντα succeeded στο success_url. Στο fail_url, συνήθως failed, expired ή cancelled· με το Hosted API μπορεί να είναι requires_action ή processing αν ο πληρωτής έφυγε πριν η πληρωμή φτάσει σε τελική κατάσταση, για παράδειγμα μέσω του "Επιστροφή στο κατάστημα".
failure_codeΥπάρχει μόνο όταν το status είναι failed· ταυτίζεται με το failure.code.
tsΏρα Unix δημιουργίας του συνδέσμου επιστροφής. Ο πληρωτής μπορεί να ανοίξει τον σύνδεσμο αργότερα, επομένως ένα παλαιό ts από μόνο του δεν υποδηλώνει πλαστογράφηση.
key_versionΠροσδιορίζει το κλειδί που υπέγραψε τον σύνδεσμο: 1 για το πρώτο κλειδί που δημιουργήθηκε στο συγκεκριμένο περιβάλλον, 2 για το επόμενο κ.ο.κ. Η τιμή δεν αλλάζει ποτέ για μια δεδομένη πληρωμή.
sigHMAC-SHA256 σε δεκαεξαδική μορφή με πεζά, 64 χαρακτήρες.

Συμβολοσειρά προς υπογραφή

ts + "." + payment_id + "." + status + "." + failure_code   // failure_code empty: keep the last dot
  1. Επιλέξτε το μυστικό κλειδί που αντιστοιχεί στο κλειδί το οποίο προσδιορίζει το key_version. Πρόκειται για το κλειδί με το οποίο δημιουργήθηκε η πληρωμή, ακόμη και αν τα κλειδιά έχουν αντικατασταθεί στο μεταξύ.

  2. Συνθέστε τη συμβολοσειρά από τις τιμές μετά την αποκωδικοποίηση URL. Αν δεν υπάρχει failure_code, διατηρήστε την τελική τελεία.

  3. Υπολογίστε το HMAC-SHA256 και συγκρίνετέ το με το sig σε σταθερό χρόνο. Βεβαιωθείτε ότι το payment_id αντιστοιχεί σε μία από τις πληρωμές σας.

  4. Ανακτήστε την πληρωμή με GET /api/payments/{payment_id} (ή περιμένετε την ειδοποίηση webhook) πριν εκτελέσετε την παραγγελία.

  • Οι δικές σας παράμετροι ερωτήματος διατηρούνται. Αν το URL περιέχει ήδη παράμετρο με ένα από τα παραπάνω ονόματα, αυτή αντικαθίσταται.
  • Αν ο σύνδεσμος δεν ήταν δυνατό να υπογραφεί λόγω προσωρινού σφάλματος, το URL δεν περιέχει καμία από αυτές τις παραμέτρους. Θεωρήστε το αποτέλεσμα άγνωστο και ανακτήστε την πληρωμή.
// Node.js 20+: check the signed parameters on success_url / fail_url.
import {createHmac, timingSafeEqual} from 'node:crypto';

// query: URLSearchParams of the return URL.
// secretFor(keyVersion): the API secret of that key, or undefined if you do not know it.
export function verifyReturn(query, secretFor) {
  const sig = query.get('sig') ?? '';
  const secret = secretFor(query.get('key_version'));
  if (!secret || !/^[0-9a-f]{64}$/.test(sig)) return false;
  const signed = [query.get('ts') ?? '', query.get('payment_id') ?? '',
    query.get('status') ?? '', query.get('failure_code') ?? ''].join('.');
  const expected = createHmac('sha256', secret).update(signed, 'utf8').digest();
  return timingSafeEqual(expected, Buffer.from(sig, 'hex'));
}
// Even a valid return is not proof of payment: read GET /api/payments/{payment_id} before you deliver.
<?php
// PHP 8.1+: check the signed parameters on success_url / fail_url.
// $secretFor(string $keyVersion): the API secret of that key, or null if you do not know it.
function payniko_verify_return(array $query, callable $secretFor): bool
{
    $sig = (string) ($query['sig'] ?? '');
    $secret = $secretFor((string) ($query['key_version'] ?? ''));
    if (!$secret || !preg_match('/^[0-9a-f]{64}$/', $sig)) return false;
    $signed = implode('.', [(string) ($query['ts'] ?? ''), (string) ($query['payment_id'] ?? ''),
        (string) ($query['status'] ?? ''), (string) ($query['failure_code'] ?? '')]);
    return hash_equals(hash_hmac('sha256', $signed, $secret), $sig);
}

// $ok = payniko_verify_return($_GET, fn (string $v) => $secretsByKeyVersion[$v] ?? null);
// Even a valid return is not proof of payment: read GET /api/payments/{payment_id} before you deliver.
# Python 3.9+: check the signed parameters on success_url / fail_url.
import hashlib, hmac, re


def verify_return(query, secret_for) -> bool:
    # query: dict-like (for example Flask request.args); secret_for(key_version) -> secret or None
    sig = query.get("sig", "")
    secret = secret_for(query.get("key_version"))
    if not secret or not re.fullmatch(r"[0-9a-f]{64}", sig):
        return False
    signed = ".".join([query.get("ts", ""), query.get("payment_id", ""),
                       query.get("status", ""), query.get("failure_code", "")])
    expected = hmac.new(secret.encode(), signed.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

# Even a valid return is not proof of payment: read GET /api/payments/{payment_id} before you deliver.

URL επιστροφής · Παράδειγμα

https://merchant.example/payment/success?payment_id=LUVEI-PAYN-654321&merchant_order_id=ORDER-2026-001&status=succeeded&ts=1793001234&key_version=1&sig=200e8a5d4a7a03ead362a2c076408f9d8764f8f636f58bd4c17d78a50d59eb8a
string to sign: 1793001234.LUVEI-PAYN-654321.succeeded.

https://merchant.example/payment/failure?payment_id=LUVEI-PAYN-654321&merchant_order_id=ORDER-2026-001&status=failed&failure_code=insufficient_funds&ts=1793001234&key_version=1&sig=1cd0a104ec4ec4f5b2933d48d14c0eb33d949dd7f27936a067ab8f68b413b70d
string to sign: 1793001234.LUVEI-PAYN-654321.failed.insufficient_funds

secret used in this example (fake): example_secret_not_real
GET/api/payments/{payment_id}

Ανάκτηση πληρωμής

Επιστρέφει { "data": Payment } με την τρέχουσα κατάσταση. Η ανάκτηση δεν τροποποιεί ποτέ την πληρωμή, επομένως μπορείτε να καλείτε αυτό το endpoint όσο συχνά απαιτείται: μετά την επιστροφή του πληρωτή, όταν μια ειδοποίηση webhook φαίνεται ασυνεπής ή μετά από λήξη χρονικού ορίου.

Παράμετροι

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
payment_idstring · pathΥποχρεωτικόΤο payment_id που επιστράφηκε κατά τη δημιουργία της πληρωμής. Οποιοδήποτε κλειδί του ίδιου περιβάλλοντος μπορεί να την ανακτήσει.
./payniko.sh GET '/api/payments/3c2d7a4e-5b1f-4e8a-9d06-7f2b1c9e4a35'
import {api} from './payniko.mjs';

const payment = await api('GET', '/api/payments/3c2d7a4e-5b1f-4e8a-9d06-7f2b1c9e4a35');
console.log(payment);
<?php
require __DIR__ . '/payniko.php';

$payment = payniko_api('GET', '/api/payments/3c2d7a4e-5b1f-4e8a-9d06-7f2b1c9e4a35');
print_r($payment);
from payniko import api

payment = api("GET", "/api/payments/3c2d7a4e-5b1f-4e8a-9d06-7f2b1c9e4a35")
print(payment)

Πιθανά σφάλματα

Ειδοποιήσεις webhook πληρωμής

Τα παρακάτω συμβάντα αποστέλλονται στο webhook_url της πληρωμής. Κάθε συμβάν πληρωμής αποστέλλεται το πολύ μία φορά ανά πληρωμή.

ΣυμβάνΣημασία
payment.succeededΗ κατάσταση της πληρωμής είναι succeeded. Εκτελέστε την παραγγελία.
payment.failedΗ πληρωμή ολοκληρώθηκε ανεπιτυχώς: failed, expired ή cancelled. Δείτε το data.status.
payment.updatedΑπαιτείται ακόμη ενέργεια από τον πληρωτή (requires_action), για παράδειγμα μετά από ενδιάμεση απόρριψη. Δεν πρόκειται για τελικό αποτέλεσμα.
refund.* · payment.voided · dispute.*Μεταγενέστερα συμβάντα για αυτή την πληρωμή (επιστροφές χρημάτων, ακυρώσεις, αμφισβητήσεις). Δείτε Ειδοποιήσεις webhook.

payment.succeeded

{
  "event_id": "e0743f4c-a297-4bf0-8085-ceb7d9d5e181",
  "event_type": "payment.succeeded",
  "environment": "sandbox",
  "occurred_at": "2026-11-01T12:02:00.000Z",
  "data": {
    "payment_id": "LUVEI-PAYN-123456",
    "merchant_order_id": "ORDER-2026-001",
    "flow": "hosted",
    "status": "succeeded",
    "amount": "100.00",
    "currency": "USD",
    "environment": "sandbox",
    "next_action": null,
    "card": {
      "bin6": "400000",
      "last_four": "0002",
      "network": "visa",
      "bank": null
    },
    "failure": null,
    "created_at": "2026-11-01T12:00:00.000Z",
    "expires_at": "2026-11-02T12:00:00.000Z",
    "completed_at": "2026-11-01T12:02:00.000Z"
  }
}

Επαληθεύετε κάθε ειδοποίηση webhook: το HMAC-SHA256 του X-Timestamp + "." + raw body, υπολογισμένο με το μυστικό κλειδί που αντιστοιχεί στο κλειδί API με το οποίο δημιουργήθηκε η πληρωμή, πρέπει να ισούται με το X-Signature και το X-Timestamp πρέπει να βρίσκεται εντός 300 δευτερολέπτων. Αποθηκεύστε κάθε event_id μία φορά και απαντήστε άμεσα με 2xx. Για παραδείγματα κώδικα και τη συμπεριφορά των επαναλήψεων, δείτε Ειδοποιήσεις webhook.

Σφάλματα

ΚωδικόςHTTPΣημασίαΣυνιστώμενη ενέργεια
1000001422Το αίτημα δεν είναι έγκυρο: άγνωστο πεδίο, μη έγκυρη μορφή, συμβολοσειρά ερωτήματος σε POST, παράμετρος ερωτήματος που δεν υποστηρίζεται ή σώμα που δεν είναι αντικείμενο JSON. Το errors παραθέτει τα πεδία που αφορά το σφάλμα.Διορθώστε τα πεδία που αναφέρονται.
1000009422Η κεφαλίδα Idempotency-Key λείπει ή δεν είναι έγκυρη.Σε κάθε POST στείλτε κλειδί 8–128 χαρακτήρων από το σύνολο A-Z a-z 0-9 _ -.
0055502401 / 403Η πρόσβαση απορρίφθηκε. 401: λείπει η κεφαλίδα X-Api-Key ή X-Merchant-Code, μια κεφαλίδα έχει σταλεί δύο φορές ή έχει μη έγκυρη μορφή, το κλειδί είναι άγνωστο ή έχει ανακληθεί, ο κωδικός εμπόρου δεν αντιστοιχεί ή στάλθηκε X-Environment που δεν αντιστοιχεί στο κλειδί. 403: ο λογαριασμός ή η πρόσβαση στο Direct API δεν είναι ενεργή.Επαληθεύστε τις κεφαλίδες και το κλειδί API. Μην επαναλαμβάνετε το αίτημα αυτόματα.
0055503409Σύγκρουση στο Direct API: υπάρχει ήδη πληρωμή για αυτό το merchant_order_id, το Idempotency-Key χρησιμοποιήθηκε με διαφορετικό σώμα ή για πληρωμή Hosted API, ή το αρχικό αίτημα βρίσκεται ακόμη σε εξέλιξη.Ανακτήστε την πληρωμή με GET. Στείλτε ξανά μόνο πανομοιότυπο αίτημα.
0055210422Το BIN δεν αποτελείται από έξι ψηφία.Στείλτε τα πρώτα έξι ψηφία του αριθμού κάρτας.
0055234409Τα στοιχεία της κάρτας δεν είναι έγκυρα: αριθμός κάρτας, ημερομηνία λήξης ή CVV. Το metadata.developer_detail προσδιορίζει το πεδίο: card_number_invalid, card_expiry_invalid ή card_cvv_invalid.Ζητήστε από τον πληρωτή να εισαγάγει ξανά τα στοιχεία της κάρτας.
0055233409Το BIN δεν είναι γνωστό.Ζητήστε από τον πληρωτή άλλη κάρτα. Δεν πρόκειται για απόρριψη από την τράπεζα.
0055230409Αυτή η κάρτα δεν μπορεί να χρησιμοποιηθεί για αυτή την πληρωμή.Ζητήστε από τον πληρωτή άλλη κάρτα. Δεν πρόκειται για απόρριψη από την τράπεζα.
0055231409Αυτή η κάρτα δεν γίνεται δεκτή για αυτή την πληρωμή.Ζητήστε από τον πληρωτή άλλη κάρτα.
0055221409Έχει συμπληρωθεί ένα όριο αυτής της κάρτας.Χρησιμοποιήστε άλλη κάρτα ή επαναλάβετε το αίτημα αργότερα.
0055235422Το ποσό δεν γίνεται δεκτό (Direct API και έλεγχος BIN). Το amount_limit περιέχει τα min και max, όταν είναι διαθέσιμα.Προσαρμόστε το ποσό.
0055001409Ο λογαριασμός σας δεν είναι έτοιμος για αυτή την πληρωμή. Με κλειδί sandbox, αυτό σημαίνει επίσης ότι η προσομοίωση sandbox δεν είναι προσωρινά διαθέσιμη (developer_detail: sandbox_unavailable), ισοδύναμο με 9000013.Επικοινωνήστε με την υποστήριξη.
1000002404Δεν βρέθηκε: η διαδρομή είναι άγνωστη ή αυτό το προϊόν API δεν είναι ενεργοποιημένο στην πλατφόρμα. Ένα API απενεργοποιημένο για τον λογαριασμό σας επιστρέφει αντ' αυτού 403 (9000040 στο Hosted API, 0055502 στο Direct API).Επαληθεύστε τη διαδρομή· επικοινωνήστε με την υποστήριξη αν το API θα έπρεπε να είναι διαθέσιμο.
1000011503Η υπηρεσία δεν είναι προσωρινά διαθέσιμη.Επαναλάβετε το ίδιο αίτημα. Ανακτήστε τους υπάρχοντες πόρους πριν δημιουργήσετε νέους.

Τα σφάλματα του Direct API περιλαμβάνουν επίσης το metadata.retry_class (no_retry, retry_same_request, retry_after, read_order). Ένα κλειστό παράθυρο του προγράμματος περιήγησης ή μια λήξη χρονικού ορίου από την πλευρά σας δεν σημαίνει ότι η πληρωμή απέτυχε· ανακτήστε την πληρωμή. Για τον πλήρη κατάλογο, δείτε Κωδικοί σφαλμάτων.

Δοκιμές με κάρτες sandbox

Με κλειδί sandbox, ο έλεγχος BIN και η πληρωμή χρησιμοποιούν σταθερά δοκιμαστικά δεδομένα: τα 435509 και 400000 είναι BIN τύπου direct και το 540061 είναι BIN τύπου hosted. Χρησιμοποιήστε οποιαδήποτε μελλοντική ημερομηνία λήξης και οποιοδήποτε τριψήφιο CVV. Για λεπτομέρειες, δείτε Sandbox και δοκιμαστικές κάρτες.

Αριθμός κάρταςΑποτέλεσμα
4000000000000010Εγκρίνεται χωρίς 3-D Secure. Στο Direct API, η απάντηση δημιουργίας επιστρέφει ήδη succeeded.
4000000000000002 · 4355090000044242Δοκιμαστικό βήμα 3-D Secure και στη συνέχεια succeeded.
4000000000000051 · 4355090000040000Απορρίπτεται πριν από το 3-D Secure (do_not_honor). Hosted API: η πληρωμή μπορεί να παραμείνει σε requires_action για περίπου 5 λεπτά και να στείλει payment.updated πριν καταλήξει σε failed. Direct API: η απάντηση δημιουργίας επιστρέφει ήδη failed.
4000000000000093 · 4355090000005151Δοκιμαστικό βήμα 3-D Secure και στη συνέχεια failed με insufficient_funds.
4000000000000044Χωρίς απάντηση από την τράπεζα και χωρίς 3-D Secure· η πληρωμή παραμένει σε processing.
4355090000089999Hosted API: processing χωρίς βήμα 3-D Secure. Direct API: δοκιμαστικό βήμα 3-D Secure και στη συνέχεια processing.

Με το Direct API, μια απορριφθείσα δοκιμαστική κάρτα επιστρέφει failed απευθείας στην απάντηση δημιουργίας· ενδιάμεσο requires_action εμφανίζεται μόνο στη σελίδα πληρωμής ενός hosted BIN. Βασίστε τις αποφάσεις σας στο webhook ή σε ένα GET.

Ολοκληρωμένο παράδειγμα

Ένας ελάχιστος διακομιστής Node.js που καλύπτει τον έλεγχο BIN, τη δημιουργία πληρωμής, την ανακατεύθυνση για 3-D Secure, το URL επιστροφής και την ειδοποίηση webhook. Χρησιμοποιεί τη βοηθητική συνάρτηση αιτημάτων και τις συναρτήσεις επαλήθευσης από τις ενότητες Ειδοποιήσεις webhook και URL επιστροφής.

server.mjs

// server.mjs: Direct API from start to end (Node.js 20+, no dependencies).
import http from 'node:http';
import {randomUUID} from 'node:crypto';
import {api} from './payniko.mjs';                  // request helper (Authentication)
import {verifyWebhook} from './verify-webhook.mjs'; // webhook check (Webhooks)
import {verifyReturn} from './verify-return.mjs';   // return URL check (Return URL)

const site = 'https://merchant.example';
const orders = new Map();      // use your database
const seenEvents = new Set();  // use your database
const readBody = async (req) => { const parts = []; for await (const p of req) parts.push(p); return Buffer.concat(parts); };

const reply = (res, data) => {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify(data.status === 'requires_action' && data.next_action
    ? {redirect: data.next_action.url} : {status: data.status, failure: data.failure}));
};

http.createServer(async (req, res) => {
  const url = new URL(req.url, site);
  // 1. BIN check, 2. create the payment. Your own HTTPS form posts the card here.
  if (req.method === 'POST' && url.pathname === '/pay') {
    const form = JSON.parse((await readBody(req)).toString('utf8'));
    const bin6 = form.number.slice(0, 6);
    let mode = null;
    try {
      mode = (await api('GET', `/api/payments/bin/${bin6}?amount=100.00&currency=USD`)).data.payment_mode;
    } catch (error) {
      if (error.status === undefined || error.status >= 500 || error.status === 429) throw error;
    }
    if (mode !== 'direct' && mode !== 'hosted') { res.writeHead(422).end('Please use another card.'); return; }
    const orderId = 'ORDER-' + Date.now();
    const key = randomUUID();
    orders.set(orderId, {key, status: 'new'});
    const body = {
      merchant_order_id: orderId, amount: '100.00', currency: 'USD',
      customer: {email: form.email, phone: form.phone},
      webhook_url: `${site}/webhooks/payniko`,
      success_url: `${site}/payment/success`, fail_url: `${site}/payment/failure`,
    };
    if (mode === 'direct') {
      body.card = {number: form.number, holder_name: form.holder_name,
        expiry_month: form.expiry_month, expiry_year: form.expiry_year, cvv: form.cvv};
    } else {
      body.bin6 = bin6;                               // payer enters the card on the payment page
    }
    const {data} = await api('POST', '/api/payments/direct', body, key);
    Object.assign(orders.get(orderId), {paymentId: data.payment_id, status: data.status});
    reply(res, data);                                 // 3. browser goes to next_action.url
    return;
  }
  // Return URL: show a page, but trust only the webhook or a GET.
  if (req.method === 'GET' && (url.pathname === '/payment/success' || url.pathname === '/payment/failure')) {
    const signed = verifyReturn(url.searchParams, () => process.env.API_SECRET);
    let status = 'unknown';
    if (signed) status = (await api('GET', `/api/payments/${url.searchParams.get('payment_id')}`)).data.status;
    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
    res.end(status === 'succeeded' ? 'Thank you, payment received.' : 'Payment not completed.');
    return;
  }
  // Webhook: verify, store event_id once, answer 2xx fast.
  if (req.method === 'POST' && url.pathname === '/webhooks/payniko') {
    const raw = await readBody(req);
    if (!verifyWebhook(raw, req.headers, process.env.API_SECRET)) { res.writeHead(401).end(); return; }
    const event = JSON.parse(raw.toString('utf8'));
    if (!seenEvents.has(event.event_id)) {          // use a unique index in your database
      seenEvents.add(event.event_id);
      const order = orders.get(event.data.merchant_order_id);
      if (order && event.event_type.startsWith('payment.')) order.status = event.data.status;
    }
    res.writeHead(204).end();
    return;
  }
  res.writeHead(404).end();
}).listen(8080);