Skip to main content

GrineoPay

GrineoPay API Documentation

Accept cryptocurrency payments on your website or application. Create hosted crypto checkout sessions, monitor transaction state, and receive signed merchant webhook notifications — all through a simple REST API.

REST API v1 12+ Supported Cryptocurrencies 15 Fiat Currencies HMAC Merchant Webhooks Live & Sandbox Credentials

1. Getting Started

The GrineoPay API allows you to programmatically create cryptocurrency payment sessions for your customers. Each payment generates a unique hosted checkout URL where your customer can complete their payment using the cryptocurrency and network of your choice.

ℹ️ Prerequisites

To use the API, you need an active GrineoPay merchant account with at least one payout wallet configured for the asset/network combinations you want to accept. API credentials (Key and Secret) can be generated from your Merchant Dashboard → API Credentials tab.

Quick Start in 3 Steps

1

Generate API Credentials

Log in to your Merchant Dashboard and generate your Live or Sandbox API Key and Secret pair.

2

Create a Payment

Send a POST request to /payments/create with the fiat amount, fiat currency, and desired crypto asset/network. You will receive a hosted checkout URL in the response.

3

Redirect Your Customer

Redirect your customer to the returned payment_url. GrineoPay will handle the hosted crypto checkout flow and send you merchant webhook notifications on status changes.

2. Authentication

Public merchant API requests require authentication using your API Key and API Secret. These are passed as custom HTTP headers with every server-to-server request.

Header (Key)
X-Api-Key
Header (Secret)
X-Api-Secret
🔒 Keep Your API Secret Safe

Your API Secret is shown only once when generated. Store it securely and never expose it in client-side JavaScript, mobile apps, or public repositories. If compromised, regenerate your keys immediately from the Merchant Dashboard.

Authenticated Request Example

bash / curl
# Example: Fetch your active wallet-backed payment options
curl -X GET "https://app.grineopay.com/api/grineopay/v1/merchant/wallets/active" \
  -H "X-Api-Key: gp_live_your_api_key_here" \
  -H "X-Api-Secret: gp_secret_your_api_secret_here"

Live vs Sandbox

GrineoPay issues separate credentials for Live and Sandbox environments. The environment is determined automatically by the API key you use — you do not pass an environment field in public server-to-server requests.

Environment API Key Prefix API Secret Prefix Behaviour
Live gp_live_ gp_secret_ Creates real crypto payment sessions using the live provider flow.
Sandbox gp_test_ gp_test_secret_ Creates simulated crypto payment sessions with fake deposit addresses for testing.

3. Base URL

For hosted GrineoPay merchant integrations, use the GrineoPay production API base below:

Production Base URL
https://app.grineopay.com/api/grineopay/v1

Example health check URL:

Full URL Example
https://app.grineopay.com/api/grineopay/v1/health
🌐 Hosted vs Self-Hosted Note

This documentation assumes you are integrating with the hosted GrineoPay platform API. If you operate a self-hosted GrineoPay-connected instance, your actual API base may differ.

4. Supported Assets & Networks

GrineoPay supports the following cryptocurrencies and blockchain networks. When creating a payment, you specify both the crypto_currency and, where applicable, the crypto_network.

Cryptocurrencies

Symbol Name Supported Networks
BTCBitcoinBTC
ETHEthereumETH
SOLSolanaSOL
USDTTetherTRX, ETH, POLYGON, BSC
USDCUSD CoinPOLYGON, ETH, BSC, ARB, OP, SOL
LTCLitecoinLTC
XMRMoneroXMR
BNBBinance CoinBNB
XRPRippleXRP
DOGEDogecoinDOGE
ADACardanoADA
TRXTronTRX

Supported Fiat Currencies

The payment amount you send to GrineoPay is denominated in fiat. GrineoPay calculates the exact crypto amount required at the moment the payment session is created.

CodeCurrencyCodeCurrencyCodeCurrency
USDU.S. DollarEUREuroGBPPound Sterling
CADCanadian DollarAUDAustralian DollarJPYJapanese Yen
CNYChinese RenminbiCHFSwiss FrancHKDHong Kong Dollar
SGDSingapore DollarINRIndian RupeeKRWSouth Korean Won
NGNNigerian NairaZARSouth African RandAEDUAE Dirham

5. Endpoint Map

Not all GrineoPay endpoints are intended for the same use case. The table below distinguishes public merchant API endpoints from authenticated dashboard/session endpoints.

Endpoint Method Auth Type Use Case
/payments/create POST API Key + Secret Public merchant integration endpoint for creating payment sessions.
/merchant/wallets/active GET API Key + Secret Public merchant integration endpoint for checking wallet-backed asset availability.
/health GET Public Public health and environment check.
/merchant/transactions GET Logged-in Session Merchant Dashboard/internal browser endpoint.
/wallets/validate POST Logged-in Session Merchant Dashboard/internal wallet validation endpoint.
/webhooks/provider POST Provider → GrineoPay Internal provider callback endpoint, not for merchant integrations.
⚠️ Public Merchant API Scope

For external merchant integrations, the core public endpoints are /payments/create and /merchant/wallets/active. Endpoints like /merchant/transactions and /wallets/validate are intended for dashboard/session-authenticated use inside the GrineoPay merchant environment.

6. cURL Quick Start

If you want to test the GrineoPay API quickly from your terminal, the following cURL examples cover the most common merchant integration flows.

bash / curl
# 1) Check API health
curl -X GET "https://app.grineopay.com/api/grineopay/v1/health"

# 2) Check active wallet-backed assets
curl -X GET "https://app.grineopay.com/api/grineopay/v1/merchant/wallets/active" \
  -H "X-Api-Key: gp_live_your_api_key" \
  -H "X-Api-Secret: gp_secret_your_api_secret"

# 3) Create a payment session
curl -X POST "https://app.grineopay.com/api/grineopay/v1/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: gp_live_your_api_key" \
  -H "X-Api-Secret: gp_secret_your_api_secret" \
  -d '{
    "amount": 49.99,
    "currency": "USD",
    "crypto_currency": "BTC",
    "order_id": "ORD-2024-00123",
    "email": "[email protected]",
    "return_url": "https://shop.com/thank-you",
    "source": "api",
    "domain": "shop.com",
    "order_context": "checkout"
  }'

7. Create Payment

Create a new cryptocurrency payment session. This endpoint converts your fiat amount into the equivalent crypto amount at the current rate, validates the merchant’s payout wallet configuration, generates a deposit address, and returns a hosted checkout URL for the customer.

POST /payments/create 🔐 API Key + Secret

Request Body Parameters

Parameter Type Required Description
amount number Required The fiat amount to charge (example: 29.99). Must be greater than zero.
currency string Required Fiat currency code such as USD or EUR.
crypto_currency string Required The cryptocurrency to accept, such as BTC, ETH, or USDT.
crypto_network string Optional The blockchain network, such as TRX for USDT on Tron. If omitted, the default/native network is used where applicable.
order_id string Required Your unique order or reference identifier, for example ORD-2024-00123.
email string Optional Customer email address. Used for recovery reminders and customer-facing flows if supported.
return_url string Optional URL to redirect the customer after payment completion.
webhook_url string Optional Merchant webhook override URL for this specific transaction.
refund_address string Optional Customer refund wallet address if you want refund routing defined upfront.
refund_extra_id string Optional Extra memo/tag for refund destinations on chains that require it.
source string Optional Source identifier for analytics, such as woocommerce or api.
domain string Optional The originating domain, for example shop.com.
order_context string Optional Context label, such as woocommerce, donation, or dashboard.
⚠️ Wallet Requirement

You must have at least one active payout wallet configured for the requested crypto_currency and crypto_network combination in your Merchant Dashboard. Payment creation will fail if no matching wallet-backed payout route exists.

Example Request

bash
curl -X POST "https://app.grineopay.com/api/grineopay/v1/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: gp_live_your_api_key" \
  -H "X-Api-Secret: gp_secret_your_api_secret" \
  -d '{
    "amount": 49.99,
    "currency": "USD",
    "crypto_currency": "BTC",
    "order_id": "ORD-2024-00123",
    "email": "[email protected]",
    "return_url": "https://shop.com/thank-you",
    "source": "woocommerce",
    "domain": "shop.com",
    "order_context": "woocommerce"
  }'
php
<?php
$payload = [
    'amount'          => 49.99,
    'currency'        => 'USD',
    'crypto_currency' => 'BTC',
    'order_id'        => 'ORD-2024-00123',
    'email'           => '[email protected]',
    'return_url'      => 'https://shop.com/thank-you',
    'source'          => 'woocommerce',
    'domain'          => 'shop.com',
    'order_context'   => 'woocommerce',
];

$ch = curl_init('https://app.grineopay.com/api/grineopay/v1/payments/create');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'X-Api-Key: gp_live_your_api_key',
    'X-Api-Secret: gp_secret_your_api_secret',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($response, true);

if ($http_code === 200 && !empty($data['success'])) {
    header('Location: ' . $data['payment_url']);
    exit;
} else {
    error_log('Payment creation failed: ' . ($data['message'] ?? 'Unknown error'));
}
javascript
const response = await fetch('https://app.grineopay.com/api/grineopay/v1/payments/create', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'gp_live_your_api_key',
    'X-Api-Secret': 'gp_secret_your_api_secret'
  },
  body: JSON.stringify({
    amount: 49.99,
    currency: 'USD',
    crypto_currency: 'BTC',
    order_id: 'ORD-2024-00123',
    email: '[email protected]',
    return_url: 'https://shop.com/thank-you',
    source: 'woocommerce',
    domain: 'shop.com',
    order_context: 'woocommerce'
  })
});

const data = await response.json();

if (data.success) {
  window.location.href = data.payment_url;
} else {
  console.error('Payment failed:', data.message);
}
python
import requests

url = "https://app.grineopay.com/api/grineopay/v1/payments/create"

headers = {
    "Content-Type": "application/json",
    "X-Api-Key": "gp_live_your_api_key",
    "X-Api-Secret": "gp_secret_your_api_secret",
}

payload = {
    "amount": 49.99,
    "currency": "USD",
    "crypto_currency": "BTC",
    "order_id": "ORD-2024-00123",
    "email": "[email protected]",
    "return_url": "https://shop.com/thank-you",
    "source": "woocommerce",
    "domain": "shop.com",
    "order_context": "woocommerce",
}

response = requests.post(url, headers=headers, json=payload)
data = response.json()

if data.get("success"):
    print(f"Redirect to: {data['payment_url']}")
else:
    print(f"Error: {data.get('message', 'Unknown error')}")
javascript (node)
const axios = require('axios');

async function createPayment() {
  try {
    const { data } = await axios.post(
      'https://app.grineopay.com/api/grineopay/v1/payments/create',
      {
        amount: 49.99,
        currency: 'USD',
        crypto_currency: 'BTC',
        order_id: 'ORD-2024-00123',
        email: '[email protected]',
        return_url: 'https://shop.com/thank-you',
        source: 'woocommerce',
        domain: 'shop.com',
        order_context: 'woocommerce'
      },
      {
        headers: {
          'Content-Type': 'application/json',
          'X-Api-Key': 'gp_live_your_api_key',
          'X-Api-Secret': 'gp_secret_your_api_secret'
        }
      }
    );

    if (data.success) {
      console.log('Checkout URL:', data.payment_url);
      return data;
    } else {
      console.error('Error:', data.message);
    }
  } catch (error) {
    console.error('Request failed:', error.message);
  }
}

createPayment();

Success Response (Example)

json
{
  "success": true,
  "transaction_id": 1042,
  "provider_id": "a1b2c3d4e5f6g7h8",
  "payment_url": "https://grineopay.com/?grineopay_crypto_checkout=1&tx_id=1042&token=abc123...",
  "deposit_address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "payin_extra_id": "",
  "crypto_amount": 0.00081234,
  "crypto_currency": "BTC",
  "crypto_network": "BTC",
  "environment": "live"
}

8. Get Active Wallets

Retrieve the list of active wallet-backed payout configurations currently available for the API credentials you are using. This is the correct public way to determine which crypto/network combinations are actually available for checkout.

GET /merchant/wallets/active 🔐 API Key + Secret

cURL Example

bash
curl -X GET "https://app.grineopay.com/api/grineopay/v1/merchant/wallets/active" \
  -H "X-Api-Key: gp_live_your_api_key" \
  -H "X-Api-Secret: gp_secret_your_api_secret"

Success Response (Example)

json
{
  "success": true,
  "wallets": [
    {
      "currency": "BTC",
      "network": "BTC",
      "is_active": true
    },
    {
      "currency": "USDT",
      "network": "TRX",
      "is_active": true
    },
    {
      "currency": "ETH",
      "network": "ETH",
      "is_active": true
    }
  ]
}

9. Dashboard Session Endpoints

The following endpoints exist in the GrineoPay merchant environment but are primarily intended for authenticated Merchant Dashboard use rather than external server-to-server integrations.

GET /merchant/transactions 🔐 Logged-in Session

Returns the authenticated merchant’s transaction list. Supports pagination and filtering by status/environment. This endpoint is intended for use inside the Merchant Dashboard session context.

Example cURL (session-based, browser cookies required)

bash
# Example only — requires a valid authenticated session cookie
curl -X GET "https://app.grineopay.com/api/grineopay/v1/merchant/transactions?limit=20&offset=0&status=completed&environment=live" \
  -H "Cookie: wordpress_logged_in_your_session_cookie_here"
POST /wallets/validate 🔐 Logged-in Session

Validates a wallet address for a given currency/network combination. This endpoint is primarily used inside the merchant environment and dashboard flows.

Request Body

ParameterTypeRequiredDescription
currencystringRequiredCryptocurrency symbol (for example BTC).
networkstringOptionalBlockchain network (for example TRX).
addressstringRequiredThe wallet address to validate.

Example cURL (session-based)

bash
# Example only — requires a valid authenticated session cookie
curl -X POST "https://app.grineopay.com/api/grineopay/v1/wallets/validate" \
  -H "Content-Type: application/json" \
  -H "Cookie: wordpress_logged_in_your_session_cookie_here" \
  -d '{
    "currency": "BTC",
    "network": "BTC",
    "address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
  }'

Example Response

json
{
  "success": true,
  "result": true,
  "message": "Address is valid",
  "isActivated": null
}
ℹ️ Integration Recommendation

External merchant applications should rely primarily on the public API endpoints and on signed merchant webhook notifications for state changes, rather than trying to use session-based dashboard endpoints.

10. Health Check

Verify that the GrineoPay API is operational and inspect general environment configuration. This endpoint is public and does not require authentication.

GET /health 🌐 Public

cURL Example

bash
curl -X GET "https://app.grineopay.com/api/grineopay/v1/health"

Example Response

json
{
  "success": true,
  "plugin": "GrineoPay Crypto Admin",
  "version": "current-deployment-version",
  "configured": true,
  "environment": "live",
  "api_alias": "https://app.grineopay.com/api/grineopay/v1/health",
  "rest_url": "https://app.grineopay.com/wp-json/grineopay/v1/health"
}

11. Merchant Webhooks

GrineoPay sends real-time HTTP POST notifications to your configured merchant webhook URL whenever a transaction’s state changes. These webhook deliveries are sent from GrineoPay to your system after the platform updates its internal transaction status.

🔄 Important Distinction

GrineoPay also receives internal provider callbacks on a separate provider webhook endpoint inside the platform. That provider webhook is not part of the merchant integration surface. The webhook documented below is the merchant-facing webhook GrineoPay sends to your system.

Configuring Your Merchant Webhook URL

Set your merchant webhook URL in the Merchant Dashboard → Webhooks tab. You can also override the merchant webhook destination per transaction by passing the webhook_url parameter when creating a payment.

Webhook Signing

Every merchant webhook notification includes a cryptographic signature in the X-GrineoPay-Signature header. The signature is an HMAC-SHA256 hash of the raw JSON request body, signed using your merchant webhook signing secret.

🔒 Always Verify Signatures

Always verify the merchant webhook signature before processing the payload. Failing to do so may allow spoofed webhook deliveries to trigger false order fulfilment.

Merchant Webhook Payload

json
{
  "event": "crypto_payment.updated",
  "transaction_id": 1042,
  "order_id": "ORD-2024-00123",
  "status": "completed",
  "fiat_amount": 49.99,
  "fiat_currency": "USD",
  "crypto_amount": 0.00081234,
  "crypto_currency": "BTC",
  "crypto_network": "BTC",
  "deposit_address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "tx_hash_in": "a1b2c3d4e5f6...",
  "tx_hash_out": "f6e5d4c3b2a1...",
  "provider_id": "a1b2c3d4e5f6g7h8",
  "timestamp": "2024-07-15 14:45:22"
}

Simulate a Merchant Webhook with cURL

You can simulate delivery of a webhook payload to your own webhook endpoint using cURL. This is useful when testing your webhook handler logic locally or in staging.

bash
# Replace the JSON body and signature with values generated using your webhook secret
curl -X POST "https://yourdomain.com/webhooks/grineopay" \
  -H "Content-Type: application/json" \
  -H "X-GrineoPay-Signature: your_generated_hmac_signature_here" \
  -d '{
    "event": "crypto_payment.updated",
    "transaction_id": 1042,
    "order_id": "ORD-2024-00123",
    "status": "completed",
    "fiat_amount": 49.99,
    "fiat_currency": "USD",
    "crypto_amount": 0.00081234,
    "crypto_currency": "BTC",
    "crypto_network": "BTC",
    "deposit_address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
    "tx_hash_in": "a1b2c3d4e5f6...",
    "tx_hash_out": "f6e5d4c3b2a1...",
    "provider_id": "a1b2c3d4e5f6g7h8",
    "timestamp": "2024-07-15 14:45:22"
  }'

Webhook Payload Fields

FieldTypeDescription
eventstringEvent type. Currently crypto_payment.updated.
transaction_idintegerGrineoPay transaction ID returned during payment creation.
order_idstringYour original order/reference identifier.
statusstringNew transaction status. See status values below.
fiat_amountfloatOriginal fiat amount charged.
fiat_currencystringOriginal fiat currency code.
crypto_amountfloatCrypto amount expected/processed for the transaction.
crypto_currencystringCryptocurrency symbol.
crypto_networkstringBlockchain network used for this transaction.
deposit_addressstringThe deposit address used for the customer payment.
tx_hash_instringIncoming blockchain transaction hash when available.
tx_hash_outstringOutgoing blockchain transaction hash when available.
provider_idstringProvider/external payment identifier associated with the GrineoPay transaction.
timestampstringWebhook dispatch timestamp from the GrineoPay platform.

Transaction Status Values

StatusDescriptionRecommended Merchant Action
pending Payment session created. Waiting for the customer to send the required crypto amount. Mark order as awaiting payment.
processing Customer payment detected. GrineoPay/provider is confirming and processing the blockchain/payment flow. Mark order as payment processing.
completed Payment confirmed and payout flow completed. Fulfil the order ✅
failed Payment could not be completed. Mark order as failed or cancelled.
refunded The transaction has been marked refunded by the system/provider. Cancel the order and notify the customer if applicable.

Signature Verification Examples

php
<?php
$webhook_secret = 'whsec_your_signing_secret';
$raw_body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_GRINEOPAY_SIGNATURE'] ?? '';

$expected = hash_hmac('sha256', $raw_body, $webhook_secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$payload = json_decode($raw_body, true);

if ($payload['status'] === 'completed') {
    $order_id = $payload['order_id'];
    // Fulfil the order...
}

http_response_code(200);
echo 'OK';
javascript (Express)
const crypto = require('crypto');
const express = require('express');
const app = express();

app.use(express.json({
  verify: (req, res, buf) => { req.rawBody = buf; }
}));

const WEBHOOK_SECRET = 'whsec_your_signing_secret';

app.post('/webhooks/grineopay', (req, res) => {
  const signature = req.header('X-GrineoPay-Signature') || '';
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest('hex');

  if (signature !== expected) {
    return res.status(401).send('Invalid signature');
  }

  const payload = req.body;

  if (payload.status === 'completed') {
    const orderId = payload.order_id;
    // Fulfil the order...
  }

  res.status(200).send('OK');
});

app.listen(3000);
python (Flask)
from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_signing_secret"

@app.route("/webhooks/grineopay", methods=["POST"])
def handle_webhook():
    raw_body = request.get_data()
    signature = request.headers.get("X-GrineoPay-Signature", "")

    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        raw_body,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected, signature):
        return jsonify({"error": "Invalid signature"}), 401

    payload = request.get_json()

    if payload.get("status") == "completed":
        order_id = payload.get("order_id")
        # Fulfil the order...

    return jsonify({"status": "ok"}), 200

if __name__ == "__main__":
    app.run(port=5000)
⚡ Respond Quickly

Your merchant webhook endpoint should respond with 200 OK quickly after verifying and accepting the payload. If you need to run slower follow-up tasks, queue them asynchronously after responding.

🔁 Idempotency

Merchant webhooks may be delivered more than once. Design your webhook handler to be idempotent so processing the same transaction_id + status combination repeatedly produces the same final result.

12. Checkout Flow

The GrineoPay checkout flow is straightforward and merchant-friendly.

1

Customer starts checkout

Your application collects the customer order and the merchant-selected crypto payment option.

2

You create a payment session

Your server calls /payments/create using your GrineoPay API credentials.

3

You redirect the customer

You send the customer to the returned payment_url.

4

Customer sends crypto

The customer pays from their wallet using the deposit address and exact amount shown on the hosted checkout page.

5

GrineoPay updates transaction state

GrineoPay receives provider updates, confirms the transaction internally, and updates the transaction state.

6

Merchant webhook is sent

GrineoPay dispatches a signed merchant webhook to your system whenever the transaction state changes.

7

You fulfil the order

Once you receive and verify a completed merchant webhook, you can safely fulfil the order.

📊 Customer Checkout Polling

The hosted checkout page may poll GrineoPay transaction state to improve customer-facing UX, but merchants should always rely on signed merchant webhook notifications as their fulfilment trigger — not browser polling.

13. Error Codes & Handling

GrineoPay uses standard HTTP status codes. Error responses typically include a success field set to false and a message field describing the issue.

HTTP Status Meaning When It Occurs
200 OK Request successful.
400 Bad Request Missing required fields, invalid parameters, amount below minimum, or no matching payout wallet.
401 Unauthorized Missing, invalid, or mismatched API credentials.
403 Forbidden Authenticated but not permitted to access the resource or feature.
404 Not Found The requested resource was not found.
500 Server Error An unexpected server-side error occurred.

Common Error Messages

Error MessageLikely CauseRecommended Resolution
Missing crypto API credentials. Required auth headers not sent. Send both X-Api-Key and X-Api-Secret.
Invalid crypto API key. API key not found or wrong environment. Verify you are using the correct live or sandbox credential pair.
Invalid crypto API secret. API secret does not match the key. Regenerate credentials if needed and update your integration.
Missing required payment creation fields. Required request parameters missing. Provide at least amount, currency, crypto_currency, and order_id.
No matching crypto payout wallet is configured for this merchant. No wallet-backed payout route exists for the selected crypto/network. Add an active matching wallet in the Merchant Dashboard.
Unable to calculate crypto amount for checkout. Rate lookup or conversion issue. Retry after a short delay.
Merchant payout wallet validation failed. The stored wallet address failed validation for the selected chain. Update the merchant payout wallet to a valid address.
Amount is below provider minimum for this crypto/network. The calculated crypto amount is below the provider minimum. Increase the fiat amount or choose a different asset/network.

Retry Strategy

For temporary failures such as timeouts or server-side issues, use exponential backoff.

pseudo-code
# Recommended retry strategy
attempt 1: wait 0 seconds
attempt 2: wait 2 seconds
attempt 3: wait 4 seconds
attempt 4: wait 8 seconds
attempt 5: wait 16 seconds
# Stop after a sensible retry limit and log the failure

14. SDK & Integration Examples

Full PHP Integration Example

php — Complete integration
<?php
class GrineoPay_Client {
    private $api_key;
    private $api_secret;
    private $base_url;

    public function __construct($api_key, $api_secret, $base_url) {
        $this->api_key = $api_key;
        $this->api_secret = $api_secret;
        $this->base_url = rtrim($base_url, '/');
    }

    public function createPayment(array $params) {
        $ch = curl_init($this->base_url . '/payments/create');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'X-Api-Key: ' . $this->api_key,
            'X-Api-Secret: ' . $this->api_secret,
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);

        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        return [
            'status' => $http_code,
            'data' => json_decode($response, true),
        ];
    }

    public function verifyMerchantWebhookSignature($raw_body, $signature, $webhook_secret) {
        $expected = hash_hmac('sha256', $raw_body, $webhook_secret);
        return hash_equals($expected, $signature);
    }
}

$client = new GrineoPay_Client(
    'gp_live_your_api_key',
    'gp_secret_your_api_secret',
    'https://app.grineopay.com/api/grineopay/v1'
);

$result = $client->createPayment([
    'amount' => 99.50,
    'currency' => 'USD',
    'crypto_currency' => 'USDT',
    'crypto_network' => 'TRX',
    'order_id' => 'SHOP-' . uniqid(),
    'email' => '[email protected]',
    'return_url' => 'https://shop.com/success',
    'source' => 'woocommerce',
    'domain' => 'shop.com',
    'order_context' => 'woocommerce',
]);

if ($result['status'] === 200 && !empty($result['data']['success'])) {
    // Store the transaction_id in your system
    header('Location: ' . $result['data']['payment_url']);
    exit;
}

// Merchant webhook handler example:
$raw_body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_GRINEOPAY_SIGNATURE'] ?? '';
$webhook_secret = 'whsec_your_signing_secret';

if (!$client->verifyMerchantWebhookSignature($raw_body, $signature, $webhook_secret)) {
    http_response_code(401);
    exit('Invalid signature');
}

$payload = json_decode($raw_body, true);

switch ($payload['status']) {
    case 'completed':
        // fulfilOrder($payload['order_id'], $payload['transaction_id']);
        break;
    case 'failed':
        // failOrder($payload['order_id']);
        break;
    case 'refunded':
        // markRefunded($payload['order_id']);
        break;
}

http_response_code(200);
echo 'OK';

JavaScript E-Commerce Snippet

In a real production integration, your frontend should call your own backend, and your backend should call GrineoPay server-to-server.

html + javascript
<button id="gp-checkout-btn" onclick="initiateCryptoPayment()">
  Pay with Crypto
</button>

<script>
async function initiateCryptoPayment() {
  const btn = document.getElementById('gp-checkout-btn');
  btn.disabled = true;
  btn.textContent = 'Processing...';

  try {
    // Call YOUR backend, not GrineoPay directly from the browser
    const response = await fetch('/api/create-crypto-payment', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        orderId: 'ORD-' + Date.now(),
        amount: 49.99,
        currency: 'USD',
        crypto: 'BTC',
        customerEmail: '[email protected]'
      })
    });

    const data = await response.json();

    if (data.success) {
      window.location.href = data.payment_url;
    } else {
      alert('Payment initialization failed: ' + data.message);
    }
  } catch (error) {
    alert('Network error. Please try again.');
  } finally {
    btn.disabled = false;
    btn.textContent = 'Pay with Crypto';
  }
}
</script>
🚫 Never Call the API from Client-Side Code

Never expose your API Key or Secret in browser JavaScript, frontend source, or mobile app code. Always call GrineoPay from your backend/server only.