MacellanMacellan SuperApp
Tag QR

Dönüş İşlemleri

Tag-QR Ping Callback entegrasyonu

Macellan SuperApp, Tag-QR ile ödemelerde Ping Callback servisine ihtiyaç duyar. Kullanıcı Tag-QR'ı mobil uygulamadan okuttuğunda, Macellan SuperApp gerekli tüm kontrolleri yapar ve son adım olarak Ping Callback servisine istek atar.

Ping Callback servisi, entegre olacak firma tarafından bu dokümanda anlatıldığı gibi hazırlanmalıdır.

Macellan SuperApp Paneli üzerinden Tag-QR oluşturulurken doldurulan formda Ping URL alanına hazırladığınız servisin URL adresini girebilirsiniz.

Örnek Form

URL adresi yazdığınız inputun yanındaki check işaretini tıklayarak servisin doğru çalışıp çalışmadığını test edebilirsiniz.

Akış

İstek

Hazırlanan servise istek, Macellan SuperApp tarafından Tag-QR okutup gerekli kontrolleri yaptıktan sonra tablodaki değerlerle POST olarak gönderir.

{
  "price": "0.02",
  "point": "0.00",
  "order_id": "3307333742",
  "user_id": "3b43544b-10b4-45e2-ab81-2b2b3f1917e8",
  "user_phone": "905555555555",
  "ref_code": "0781534070",
  "callback_success_url": "https://api.altpay.dev/tag-qr/3307333742/success",
  "callback_fail_url": "https://api.altpay.dev/tag-qr/3307333742/fail",
  "hash": "9fe2ea5ad3f1f5b0289b151521ed1ed2d772dae0"
}
DeğerTipAçıklama
pricestringKullanıcının bakiyesinden düşülecek tutar.
pointstringKullanıcının puanından düşülecek tutar.
order_idstringMacellan SuperApp'in ödemeye atadığı sipariş numarası.
user_idstringİşlem yapan müşterinin tekil kullanıcı IDsi.
user_phonestringİşlem yapan müşterinin tekil kullanıcı telefon numarası.
ref_codestringMüşteri tarafından mobil uygulamadan okutulan Tag-QR'ın referans kodu.
callback_success_urlstringİşlem sonunda işlemin başarılı olduğunu bildirebileceğiniz adres.
callback_fail_urlstringİşlem sonunda işlemin başarısız olduğunu bildirebileceğiniz adres.
hashstringHash doğrulamasında kullanılacak değer.

Tekil kullanıcı telefon numarası firmanın ORTAK VERİ SORUMLUSU olduğunu kabul etmesi durumunda yukarıda yer olan örnekteki gibi gönderilmektedir. Aksi halde telefon numarası KVKK mevzuatı gereği maskelenmiş olarak gönderilmektedir ve kullanıcı telefon numarası tekil bir değer olarak kabul edilmemelidir.

İsteğin Macellan SuperApp'den geldiğini doğrulayabilmek için Hash Doğrulaması yapabilirsiniz.

Eğer isteği doğru bir şekilde aldıysanız yanıt olarak status kodunu 200 olarak göndermelisiniz.

İşlemin sonucu, isteği doğru alıp almadığınızı belirtir. Örneğin o işlemde bir kapı açılacaksa, kapı açma işlemini bu isteğe cevap verdikten sonra yapmalısınız.

Gelen İsteği Doğrulama

Hash doğrulamanın amacı gelen isteğin Macellan SuperApp tarafından gönderildiğine emin olmaktır.

Doğrulama, istek ile beraber gelen bellirli değerleri aşağıdaki sıra ile birleştirilip sonucun sha1 hashi alınarak yapılır.

salt değişkeni Macellan SuperApp panelinden Tag-QR oluşturulurken formdaki Salt Key değeridir.

Eğer hash değeri doğru değilse response status kodunu 403 ile yanıt verebilirsiniz.

salt + callback_fail_url + callback_success_url + price
package main

import (
	"crypto/sha1"
	"encoding/hex"
	"strings"
)

type OpenGateRequest struct {
	Price              string `json:"price"`
	Point              string `json:"point"`
	RefCode            string `json:"ref_code"`
	UserId             string `json:"user_id"`
	UserPhone          string `json:"user_phone"`
	OrderId            string `json:"order_id"`
	CallbackSuccessUrl string `json:"callback_success_url"`
	CallbackFailUrl    string `json:"callback_fail_url"`
	Hash               string `json:"hash"`
}

func requestHashValidator(request *OpenGateRequest) bool {
    sb := []string{
		os.Getenv("SALT"),
		r.CallbackFailUrl,
		r.CallbackSuccessUrl,
		r.Price,
	}

	s := strings.Join(sb, "")

	hasher := sha1.New()
	hasher.Write([]byte(s))

	cHash := hex.EncodeToString(hasher.Sum(nil))

    return request.Hash == cHash
}
function requestHashValidator(): bool
{
    $request = json_decode(file_get_contents('php://input'), true);
    $salt = 'test';

    $cHash = sha1(sprintf(
            '%s%s%s%s',
            $salt,
            $request['callback_fail_url'],
            $request['callback_success_url'],
            $request['price'],
        ));

    return $request['hash'] === $cHash;
}
import { createHash } from "crypto";

interface openGateRequest {
    price: string;
    point: string;
    ref_code: string;
    user_id: string;
    user_phone: string;
    order_id: string;
    callback_success_url: string;
    callback_fail_url: string;
    hash: string;
}

function requestHashValidator(request: openGateRequest): boolean
{
    const string: Array<string> = [
        process.env.salt,
        request.callback_fail_url,
        request.callback_success_url,
        request.price,
    ]

    const cHash: string = createHash('sha1').update(string.join('')).digest('hex')

    return request.hash == cHash
}

İşlem Sonucunu Bildirme

İsteği aldıktan sonra kendi tarafınızdaki yapmanız gereken tüm işlemleri yapınız, daha sonra işlemin durumunu Macellan SuperApp'e bildirmeniz gerekmektedir.

İşlem başarılı ise ilk gelen istekteki callback_success_url değerindeki adrese POST isteği atmalısınız.

İşlem başarısız olmuşsa callback_fail_url değerindeki adrese POST isteği atılmalıdır.

Dönüş İstekleri İçin Hash Hesaplama

Dönüş isteği atılırken Macellan SuperApp'in istekte bulunanın siz olduğunuzu anlayabilmesi için hash değerine ihtiyaç duyar.

Dönüş isteklerinde göndereceğiniz hash değerinin hesaplama sırası, size gelen istek doğrulamasından farklıdır. Hash hesaplayabilmek için ilk istekte gönderilen değerleri aşağıdaki sırayla birleştirip sha1 hashını almalısınız.

price + callback_success_url + callback_fail_url + salt
package main

import (
	"crypto/sha1"
	"encoding/hex"
	"strings"
)

type OpenGateRequest struct {
	Price              string `json:"price"`
	Point              string `json:"point"`
	RefCode            string `json:"ref_code"`
	UserId             string `json:"user_id"`
	UserPhone          string `json:"user_id"`
	OrderId            string `json:"order_id"`
	CallbackSuccessUrl string `json:"callback_success_url"`
	CallbackFailUrl    string `json:"callback_fail_url"`
	Hash               string `json:"hash"`
}

func getCallbackHash(request *OpenGateRequest) string {
    sb := []string{
		r.Price,
		r.CallbackSuccessUrl,
		r.CallbackFailUrl,
		os.Getenv("SALT"),
	}

	s := strings.Join(sb, "")

	hasher := sha1.New()
	hasher.Write([]byte(s))

	cHash := hex.EncodeToString(hasher.Sum(nil))

    return cHash
}
function getCallbackHash(): string
{
    $request = json_decode(file_get_contents('php://input'), true);
    $salt = 'test';

    return sha1(sprintf(
            '%s%s%s%s',
            $request['price'],
            $request['callback_success_url'],
            $request['callback_fail_url'],
            $salt,
        ));
}
import { createHash } from "crypto";

interface openGateRequest {
    price: string;
    point: string;
    ref_code: string;
    user_id: string;
    user_phone: string;
    order_id: string;
    callback_success_url: string;
    callback_fail_url: string;
    hash: string;
}

function getCallbackHash(request: openGateRequest): string
{
    const string: Array<string> = [
        request.price,
        request.callback_success_url,
        request.callback_fail_url,
        process.env.salt,
    ]

    return createHash('sha1').update(string.join('')).digest('hex')
}

Dönüş İstekleri

Kendi tarafınızdaki kontrolleri ve gerçekleşmesi gereken tüm işlemleri yaptıktan sonra, işlemin durumunu Macellan SuperApp'e bildirmelisiniz.

Sonucu bildirebilmek için ilk gelen istekteki callback_succes_url veya callback_fail_url adreslerini kullanabilirsiniz.

Eğer işlem sizin tarafınızda başarısız olmuş, örneğin işlem sonunda kapı açmak istiyorsanız, kapıyı açacak olan cihaz ile iletişim kuramamış olabilirsiniz veya cihaz size hata ile dönmüşse bu durumu bildirmek için callback_fail_url deki adrese istek göndermelisiniz.

İşlemin kesin olarak başarılı olduğuna eminseniz, örneğin kapı açılacaksa cihazınızdan kapı açıldı komutu size ulaştıktan sonra callback_succes_url e istek göndermelisiniz.

Macellan SuperApp ilk istek gönderdikten sonraki ilk 30 sn içerisinde herhangi bir dönüş yapılmayan işlemleri başarısız olarak kabul eder ve ödeme işlemini sonlandırır.

Eğer durum başarılı olarak bildirildiyse, tutar bakiyeden düşülür ve ödeme tamamlanmış olur.

package main

import (
    "bytes"
	"encoding/json"
	"net/http"
)

type CallbackRequest struct {
	Hash string `json:"hash"`
}

func callback(r *OpenGateRequest, cHash string, isSuccess bool) {
    jsonData, _ := json.Marshal(CallbackRequest{
		Hash: cHash,
	})

	var callbackUrl = r.CallbackSuccessUrl

	if ! isSuccess {
		callbackUrl = r.CallbackFailUrl
	}

	_, _ = http.Post(callbackUrl, "application/json", bytes.NewBuffer(jsonData))
}
function callback(array $request, string $hash, bool $isSuccess): void
{
    $callbackUrl = $isSuccess ? $request['callback_success_url'] : $request['callback_fail_url'];

    $options = [
        'http' => [
            'header'  => 'Content-type: application/json',
            'method'  => 'POST',
            'content' => json_encode([
                'hash' => $hash,
            ]),
        ],
    ];

    $context  = stream_context_create($options);
    $result = file_get_contents($callbackUrl, false, $context);
}
function callback(request: openGateRequest, hash: string, isSuccess: boolean): void
{
    const callbackUrl: string = isSuccess ? request.callback_success_url : request.callback_fail_url

    fetch(callbackUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ hash: hash })
    })
    .then(() => console.log('successful'))
}
curl -X "POST" "https://api.altpay.dev/tag-qr/3307333742/success" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d $'{
  "hash": "5e7dfd7bc753dbe7a6a62ce0557db88fef305b78"
}'

Bu sayfada