Direct Pay API
Skip the hosted product-selection page. Your server posts
product_id, quantity, and payment_gateway
together with the usual buyer fields. The returned redirect URL
opens the selected payment gateway immediately.
Credentials
Integration Flow
-
1
Create direct session — POST buyer data +
product_id+quantity+payment_gateway+ HMAC hash to/checkout/token_direct.php. -
2
Redirect user — Forward the browser to the returned
redirectURL. It auto-starts the chosen gateway payment page. -
3
Receive webhook — Same IPN format as
hosted checkout. Respond with
OK.
api_secret in front-end JavaScript or mobile apps.
vs Hosted Checkout
Use Direct Pay when you already know the product, quantity, and payment method. Use hosted checkout (v1) when the customer should pick those on the Dodopin store page.
/checkout/token_direct.php (v2) vs
/checkout/token.php (v1). Hash string for v2 includes
product, quantity, and gateway.
Authentication
Sign every Direct Session request with HMAC-SHA256. The hash string is longer than v1 — it includes product and gateway fields.
Request Hash (Direct Session)
PHP
$hash_string =
$API_KEY . '|' .
$store_id . '|' .
$user_id . '|' .
$username . '|' .
$user_email . '|' .
$product_id . '|' .
$quantity . '|' .
$payment_gateway;
$hash = base64_encode(
hash_hmac('sha256', $hash_string, $API_SECRET, true)
);
Create Direct Session
POST credentials, buyer context, product, quantity, and gateway.
On success you receive a signed redirect URL that opens payment immediately.
Required fields
| Field | Description |
|---|---|
api_key | Store API key |
hash | HMAC signature (see Authentication) |
store_id | Numeric store ID |
user_id | Your end-user identifier |
username | Letters, digits, _, - only |
user_email | Valid email |
user_ip | Buyer IPv4/IPv6 |
user_fullname | Buyer full name |
user_phone | E.g. +13125550100 |
product_id | Approved product ID for this store |
quantity | 1–99999 (1 if product disallows quantity) |
payment_gateway | Gateway key (see Payment Gateways) |
Optional
| Field | Description |
|---|---|
lang | UI language. Default: tr. Allowed: tr, en, de, fr, es, it, pt, nl, pl, ro, cs |
currency | Display currency, e.g. TRY |
Code Examples
<?php
$API_KEY = 'YOUR_API_KEY';
$API_SECRET = 'YOUR_API_SECRET';
$store_id = 12345;
$user_id = 678;
$username = 'username';
$user_email = '[email protected]';
$product_id = 104;
$quantity = 1;
$payment_gateway = 'lidio';
$hash_string = $API_KEY . '|' . $store_id . '|' . $user_id . '|' . $username . '|' . $user_email
. '|' . $product_id . '|' . $quantity . '|' . $payment_gateway;
$hash = base64_encode(hash_hmac('sha256', $hash_string, $API_SECRET, true));
$post_data = [
'api_key' => $API_KEY,
'hash' => $hash,
'store_id' => $store_id,
'user_id' => $user_id,
'username' => $username,
'user_email' => $user_email,
'user_ip' => $_SERVER['REMOTE_ADDR'] ?? '',
'user_fullname' => 'John Doe',
'user_phone' => '+13125550100',
'product_id' => $product_id,
'quantity' => $quantity,
'payment_gateway' => $payment_gateway,
'lang' => 'tr',
'currency' => 'TRY',
];
$ch = curl_init('https://dodopin.com/checkout/token_direct.php');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post_data,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_TIMEOUT => 30,
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
if (!empty($response['success'])) {
header('Location: ' . $response['redirect']);
exit;
}
echo $response['message'] ?? 'error';
const crypto = require('crypto');
const API_KEY = 'YOUR_API_KEY';
const API_SECRET = 'YOUR_API_SECRET';
const store_id = 12345;
const user_id = 678;
const username = 'username';
const user_email = '[email protected]';
const product_id = 104;
const quantity = 1;
const payment_gateway = 'lidio';
const hashString = [API_KEY, store_id, user_id, username, user_email, product_id, quantity, payment_gateway].join('|');
const hash = Buffer.from(
crypto.createHmac('sha256', API_SECRET).update(hashString).digest()
).toString('base64');
const body = new URLSearchParams({
api_key: API_KEY,
hash,
store_id: String(store_id),
user_id: String(user_id),
username,
user_email,
user_ip: '203.0.113.10',
user_fullname: 'John Doe',
user_phone: '+13125550100',
product_id: String(product_id),
quantity: String(quantity),
payment_gateway,
lang: 'tr',
currency: 'TRY',
});
const res = await fetch('https://dodopin.com/checkout/token_direct.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
});
const data = await res.json();
// redirect user to data.redirect
import base64, hashlib, hmac, urllib.parse, urllib.request
API_KEY = 'YOUR_API_KEY'
API_SECRET = 'YOUR_API_SECRET'
store_id = 12345
user_id = 678
username = 'username'
user_email = '[email protected]'
product_id = 104
quantity = 1
payment_gateway = 'lidio'
hash_string = '|'.join(map(str, [
API_KEY, store_id, user_id, username, user_email, product_id, quantity, payment_gateway
]))
digest = hmac.new(API_SECRET.encode(), hash_string.encode(), hashlib.sha256).digest()
hash_b64 = base64.b64encode(digest).decode()
post = urllib.parse.urlencode({
'api_key': API_KEY,
'hash': hash_b64,
'store_id': store_id,
'user_id': user_id,
'username': username,
'user_email': user_email,
'user_ip': '203.0.113.10',
'user_fullname': 'John Doe',
'user_phone': '+13125550100',
'product_id': product_id,
'quantity': quantity,
'payment_gateway': payment_gateway,
'lang': 'tr',
'currency': 'TRY',
}).encode()
req = urllib.request.Request(
'https://dodopin.com/checkout/token_direct.php',
data=post,
method='POST',
)
with urllib.request.urlopen(req) as resp:
print(resp.read().decode())
# Compute hash server-side first, then:
curl -X POST 'https://dodopin.com/checkout/token_direct.php' \
-d 'api_key=YOUR_API_KEY' \
-d 'hash=BASE64_HMAC' \
-d 'store_id=12345' \
-d 'user_id=678' \
-d 'username=username' \
-d '[email protected]' \
-d 'user_ip=203.0.113.10' \
-d 'user_fullname=John+Doe' \
-d 'user_phone=%2B13125550100' \
-d 'product_id=104' \
-d 'quantity=1' \
-d 'payment_gateway=lidio' \
-d 'lang=tr' \
-d 'currency=TRY'
Success response
{
"success": true,
"token": "…",
"redirect": "https://…/checkout/direct_pay.php?token=…&product_id=104&quantity=1&payment_gateway=lidio&lang=tr&sig=…",
"product_id": 104,
"quantity": 1,
"payment_gateway": "lidio"
}
Payment Gateways
Pass one of these keys as payment_gateway. The method must be
enabled globally and not disabled for your store.
| Key | Type |
|---|---|
lidio | Card (Lidio) |
tiko | Card (Tiko) |
tazapay | Card (Tazapay) |
stripe / stripe_card | Stripe Cards |
stripe_ideal, stripe_p24, stripe_apple_pay, … | Stripe surfaces |
bank_transfer | Turkey IBAN transfer |
payop_fawry, payop_… | Local PayOp methods |
stripe_google_pay).
PayOp keys use the payop_ prefix of the method slug shown in admin.
Webhooks
Direct Pay uses the same webhook (IPN) format, signing rules, and retry policy as hosted checkout. See the v1 Webhooks section for field lists and verification examples. Max delivery attempts: 100.
Error Codes
Failures return JSON { "success": false, "message": "…" }.
Common messages include invalid hash, missing fields, product not found,
insufficient pin stock, or payment gateway unavailable for the store.
token.php). HTTP 429 means retry after a short wait.