Accept payments with the Basalt Dynamics API
The Basalt Dynamics API is simple to integrate into your company's software. Our API takes cURL requests, has well-formatted URLs, and produces JSON responses.
The API can be used in test mode without affecting your real data. Use the test endpoint while integrating, then switch to the live endpoint when you are ready.
Reference
Supported Currencies
The supported currencies by Basalt Dynamics are given below.
| Currency | Currency Symbol |
|---|---|
| No supported currencies are currently available. | |
Authentication
Get the API key
To access your Basalt Dynamics merchant account, please log in. In case you don't have an account, you can create one here.
Open the merchant panel and go to Account > Settings > API Key.
Rotate the environment-specific key. The secret is displayed once and stored encrypted.
Register each HTTPS webhook hostname before using it, and sign every initiation request with the matching environment secret.
Do not share your API keys with anyone. Generate new keys from the merchant panel whenever needed.
Payments
Initiate Payment
Send the exact JSON bytes you sign. Requests require a five-minute timestamp, a unique nonce, an idempotency key, and an HMAC made with the matching environment secret. Never reuse live credentials for test mode.
https://payments.basaltdynamics.com/test/payment/initiateTest mode does not affect your real data.
Request parameters
| Parameter | Type | Requirement | Description |
|---|---|---|---|
public_key | string (255) | Required | Your Public API key |
identifier | string (20) | Required | Identifier is basically for identify payment at your end |
currency | string (20) | Required | Currency Code, Must be in Upper Case. e.g. USD,EUR |
amount | decimal | Required | Payment amount |
gateway_methods | array | Optional | The gateway methods you want to make available |
details | string (100) | Required | Details of your payment or transaction |
ipn_url | string / URL | Required | The url of instant payment notification |
success_url | string / URL | Required | Payment success redirect url |
cancel_url | string / URL | Required | Payment cancel redirect url |
site_name | string (255) | Required | Your business site name |
site_logo | string / URL | Optional | Your business site logo |
checkout_theme | string | Optional | Checkout form theme dark/light. Default theme is light |
| Customer | |||
customer[] | array | Required | customer must be an array |
customer.first_name | string | Required | Customer's first name |
customer.last_name | string | Required | Customer's last name |
customer.email | string | Required | Customer's valid email |
customer.mobile | string | Required | Customer's valid mobile |
| Shipping info | |||
shipping_info[] | array | Optional | shipping_info must be an array |
shipping_info.address_one | string | Optional | Customer's address one |
shipping_info.address_two | string | Optional | Customer's address two |
shipping_info.area | string | Optional | Shipping area of customer |
shipping_info.city | string | Optional | Shipping city of customer |
shipping_info.sub_city | string | Optional | Shipping sub city of customer |
shipping_info.state | string | Optional | Shipping state |
shipping_info.postcode | string | Optional | Shipping postcode |
shipping_info.country | string | Optional | Shipping country |
shipping_info.others | string | Optional | Others info |
| Billing info | |||
billing_info[] | array | Optional | billing_info must be an array |
billing_info.address_one | string | Optional | Customer's address one |
billing_info.address_two | string | Optional | Customer's address two |
billing_info.area | string | Optional | Billing area of customer |
billing_info.city | string | Optional | Billing city of customer |
billing_info.sub_city | string | Optional | Billing sub city of customer |
billing_info.state | string | Optional | Billing state |
billing_info.postcode | string | Optional | Billing postcode |
billing_info.country | string | Optional | Billing country |
billing_info.others | string | Optional | Others info |
<?php
$parameters = [
'identifier' => 'YOUR_IDENTIFIER',
'currency' => 'USD',
'amount' => 11.00,
'gateway_methods' => [],
'details' => 'Purchase T-shirt',
'ipn_url' => 'https://example.com/ipn',
'cancel_url' => 'https://example.com/cancel',
'success_url' => 'https://example.com/success',
'public_key' => 'YOUR_PUBLIC_KEY',
'site_name' => 'Your site name',
'site_logo' => 'https://example.com/logo.png',
'checkout_theme' => 'light',
'customer' => ['first_name' => 'John', 'last_name' => 'Doe', 'email' => 'john@example.com', 'mobile' => '12345789'],
'shipping_info' => [],
'billing_info' => [],
];
$url = 'https://payments.basaltdynamics.com/test/payment/initiate';
$secret = 'YOUR_TEST_SECRET_KEY';
$body = json_encode($parameters, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
$timestamp = (string) time();
$nonce = bin2hex(random_bytes(16));
$signature = hash_hmac('sha256', $timestamp."\n".$nonce."\n".$body, $secret);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Idempotency-Key: '.bin2hex(random_bytes(16)),
'X-Basalt-Timestamp: '.$timestamp,
'X-Basalt-Nonce: '.$nonce,
'X-Basalt-Signature: v1='.$signature,
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
$result = curl_exec($ch);
curl_close($ch);Example responses
{
"status": "error",
"message": ["Invalid api key"]
}{
"status": "success",
"message": ["Payment initiated"],
"redirect_url": "https://example.com/payment/checkout?payment_trx=..."
}Payments
Validate the Payment and IPN
Basalt Dynamics sends canonical JSON to your registered HTTPS endpoint. Verify the raw request body before decoding it, reject timestamps older than five minutes, and store every event ID with a unique constraint before fulfilling an order.
IPN parameters
| Header / field | Description |
|---|---|
X-Basalt-Timestamp | Unix timestamp included in the signed message. |
X-Basalt-Signature | v1=HMAC_SHA256(timestamp + "." + raw_body) |
X-Basalt-Event | Stable event identifier. Store it uniquely to reject replay. |
environment | Explicit live or test environment marker. |
identifier | Your original order identifier. |
data | Payment transaction, amount, currency and timestamp. |
<?php
$rawBody = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_BASALT_TIMESTAMP'] ?? '';
$eventId = $_SERVER['HTTP_X_BASALT_EVENT'] ?? '';
$provided = preg_replace('/^v1=/', '', $_SERVER['HTTP_X_BASALT_SIGNATURE'] ?? '');
$secret = 'YOUR_ENVIRONMENT_SECRET_KEY';
if (!ctype_digit($timestamp) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401); exit;
}
$expected = hash_hmac('sha256', $timestamp.'.'.$rawBody, $secret);
if (!preg_match('/^[a-f0-9]{64}$/', $provided) || !hash_equals($expected, $provided)) {
http_response_code(401); exit;
}
$event = json_decode($rawBody, true, 32, JSON_THROW_ON_ERROR);
// In one DB transaction: insert $eventId into a UNIQUE column, verify the
// environment/identifier/amount/currency, then fulfill the order exactly once.
http_response_code(204);Use the raw body and constant-time comparison. Never fulfill from a browser redirect, and never acknowledge a duplicate event as new work.