setup-payram

📁 payram/payram-helper-mcp-server 📅 9 days ago
1
总安装量
1
周安装量
#41153
全站排名
安装命令
npx skills add https://github.com/payram/payram-helper-mcp-server --skill setup-payram

Agent 安装分布

opencode 1
codex 1
claude-code 1

Skill 文档

Setup Payram

Configure your backend to connect to a self-hosted Payram server and validate the connection.

Overview

This skill guides you through:

  1. Creating the required .env configuration
  2. Understanding Payram’s authentication model
  3. Testing connectivity to your Payram instance
  4. Troubleshooting common connection issues

When to Use

  • Starting a new Payram integration
  • Validating existing Payram configuration
  • Troubleshooting connection errors
  • Setting up a new environment (staging, production)

Prerequisites

You must have:

  • A self-hosted Payram server deployed and accessible
  • Admin access to the Payram dashboard
  • An API key generated from the dashboard (Settings → Accounts → API Keys)

Instructions

Step 1: Create Environment Configuration

Create a .env file in your project root with the following variables:

# Payram REST base URL (include protocol, no trailing slash)
PAYRAM_BASE_URL=https://your-payram-server.example

# Payram API key (from dashboard Settings → Accounts → API Keys)
PAYRAM_API_KEY=pk_live_your_actual_key_here

Required Variables:

  • PAYRAM_BASE_URL: Full URL to your self-hosted Payram instance
  • PAYRAM_API_KEY: Project-scoped API key from the Payram dashboard

Important: Never commit .env files to version control. Add .env to your .gitignore.

Step 2: Understand Authentication

Payram uses header-based authentication:

API-Key: your_api_key_here

NOT Authorization: Bearer ... – this will fail with 401.

The API key must be:

  • Sent in the API-Key header (case-sensitive)
  • Generated for the specific project/workspace you’re integrating
  • Kept secret and never exposed in client-side code

Step 3: Test Connectivity

Create a test script to validate your connection. The connection test creates a minimal payment request to verify:

  • Network reachability
  • API key validity
  • Correct authentication setup

Node.js/TypeScript (Using Payram SDK)

Install SDK:

npm install payram dotenv

Test Script:

import { Payram, isPayramSDKError } from 'payram';
import dotenv from 'dotenv';

dotenv.config();

const baseUrl = process.env.PAYRAM_BASE_URL;
const apiKey = process.env.PAYRAM_API_KEY;

if (!baseUrl || !apiKey) {
  console.error('❌ Missing PAYRAM_BASE_URL or PAYRAM_API_KEY in .env');
  process.exit(1);
}

async function testConnection() {
  try {
    // Initialize Payram SDK
    const payram = new Payram({
      apiKey,
      baseUrl,
      config: {
        timeoutMs: 10_000,
        maxRetries: 2,
      },
    });

    console.log('🔄 Testing connection to Payram...');
    console.log(`   Base URL: ${baseUrl}`);

    // Create a minimal test payment
    const checkout = await payram.payments.initiatePayment({
      customerEmail: 'test@example.com',
      customerId: 'connectivity-test',
      amountInUSD: 1,
    });

    console.log('✅ Connection successful!');
    console.log(`   Reference ID: ${checkout.reference_id}`);
    console.log(`   Checkout URL: ${checkout.url}`);

    return true;
  } catch (error) {
    console.error('❌ Connection failed');

    if (isPayramSDKError(error)) {
      console.error(`   Status: ${error.status}`);
      console.error(`   Error: ${error.error}`);
      console.error(`   Request ID: ${error.requestId}`);
      console.error(`   Retryable: ${error.isRetryable}`);
    } else {
      console.error(`   Error: ${error instanceof Error ? error.message : String(error)}`);
    }

    return false;
  }
}

testConnection();

Python (Using requests)

Install dependencies:

pip install requests python-dotenv

Test Script:

import os
import requests
from dotenv import load_dotenv

load_dotenv()

base_url = os.getenv('PAYRAM_BASE_URL')
api_key = os.getenv('PAYRAM_API_KEY')

if not base_url or not api_key:
    print('❌ Missing PAYRAM_BASE_URL or PAYRAM_API_KEY in .env')
    exit(1)

def test_connection():
    try:
        print('🔄 Testing connection to Payram...')
        print(f'   Base URL: {base_url}')

        endpoint = f"{base_url}/api/v1/payment"
        headers = {
            'API-Key': api_key,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        }
        payload = {
            'customerEmail': 'test@example.com',
            'customerId': 'connectivity-test',
            'amountInUSD': 1,
        }

        response = requests.post(endpoint, json=payload, headers=headers, timeout=10)

        if response.status_code in [200, 201]:
            data = response.json()
            print('✅ Connection successful!')
            print(f"   Reference ID: {data.get('reference_id', 'N/A')}")
            print(f"   Checkout URL: {data.get('url', 'N/A')}")
            return True
        else:
            print('❌ Connection failed')
            print(f"   Status: {response.status_code}")
            print(f"   Response: {response.text}")
            return False

    except requests.exceptions.RequestException as e:
        print('❌ Connection failed')
        print(f"   Error: {str(e)}")
        return False

if __name__ == '__main__':
    test_connection()

Go (Using net/http)

Test Script:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
    "time"

    "github.com/joho/godotenv"
)

type PaymentRequest struct {
    CustomerEmail string  `json:"customerEmail"`
    CustomerID    string  `json:"customerId"`
    AmountInUSD   float64 `json:"amountInUSD"`
}

type PaymentResponse struct {
    ReferenceID string `json:"reference_id"`
    URL         string `json:"url"`
}

func testConnection() bool {
    godotenv.Load()

    baseURL := os.Getenv("PAYRAM_BASE_URL")
    apiKey := os.Getenv("PAYRAM_API_KEY")

    if baseURL == "" || apiKey == "" {
        fmt.Println("❌ Missing PAYRAM_BASE_URL or PAYRAM_API_KEY in .env")
        return false
    }

    fmt.Println("🔄 Testing connection to Payram...")
    fmt.Printf("   Base URL: %s\n", baseURL)

    payload := PaymentRequest{
        CustomerEmail: "test@example.com",
        CustomerID:    "connectivity-test",
        AmountInUSD:   1.0,
    }

    body, _ := json.Marshal(payload)

    client := &http.Client{Timeout: 10 * time.Second}
    req, err := http.NewRequest("POST", baseURL+"/api/v1/payment", bytes.NewBuffer(body))
    if err != nil {
        fmt.Printf("❌ Failed to create request: %v\n", err)
        return false
    }

    req.Header.Set("API-Key", apiKey)
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Accept", "application/json")

    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("❌ Connection failed: %v\n", err)
        return false
    }
    defer resp.Body.Close()

    if resp.StatusCode == 200 || resp.StatusCode == 201 {
        var result PaymentResponse
        bodyBytes, _ := io.ReadAll(resp.Body)
        json.Unmarshal(bodyBytes, &result)

        fmt.Println("✅ Connection successful!")
        fmt.Printf("   Reference ID: %s\n", result.ReferenceID)
        fmt.Printf("   Checkout URL: %s\n", result.URL)
        return true
    } else {
        fmt.Printf("❌ Connection failed: Status %d\n", resp.StatusCode)
        bodyBytes, _ := io.ReadAll(resp.Body)
        fmt.Printf("   Response: %s\n", string(bodyBytes))
        return false
    }
}

func main() {
    testConnection()
}

PHP (Using cURL)

Test Script:

<?php
require __DIR__ . '/vendor/autoload.php';

use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

$baseUrl = $_ENV['PAYRAM_BASE_URL'] ?? null;
$apiKey = $_ENV['PAYRAM_API_KEY'] ?? null;

if (!$baseUrl || !$apiKey) {
    echo "❌ Missing PAYRAM_BASE_URL or PAYRAM_API_KEY in .env\n";
    exit(1);
}

function testConnection($baseUrl, $apiKey) {
    echo "🔄 Testing connection to Payram...\n";
    echo "   Base URL: $baseUrl\n";

    $payload = [
        'customerEmail' => 'test@example.com',
        'customerId' => 'connectivity-test',
        'amountInUSD' => 1,
    ];

    $ch = curl_init($baseUrl . '/api/v1/payment');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            'API-Key: ' . $apiKey,
            'Content-Type: application/json',
            'Accept: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
    ]);

    $response = curl_exec($ch);
    $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);

    if ($error) {
        echo "❌ Connection failed: $error\n";
        return false;
    }

    if ($statusCode === 200 || $statusCode === 201) {
        $data = json_decode($response, true);
        echo "✅ Connection successful!\n";
        echo "   Reference ID: " . ($data['reference_id'] ?? 'N/A') . "\n";
        echo "   Checkout URL: " . ($data['url'] ?? 'N/A') . "\n";
        return true;
    } else {
        echo "❌ Connection failed: Status $statusCode\n";
        echo "   Response: $response\n";
        return false;
    }
}

testConnection($baseUrl, $apiKey);

Java (Using HttpClient)

Test Script:

package com.example.payram;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

import io.github.cdimascio.dotenv.Dotenv;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class ConnectionTest {

    public static void main(String[] args) {
        Dotenv dotenv = Dotenv.load();

        String baseUrl = dotenv.get("PAYRAM_BASE_URL");
        String apiKey = dotenv.get("PAYRAM_API_KEY");

        if (baseUrl == null || apiKey == null) {
            System.out.println("❌ Missing PAYRAM_BASE_URL or PAYRAM_API_KEY in .env");
            System.exit(1);
        }

        testConnection(baseUrl, apiKey);
    }

    public static boolean testConnection(String baseUrl, String apiKey) {
        try {
            System.out.println("🔄 Testing connection to Payram...");
            System.out.println("   Base URL: " + baseUrl);

            // Create JSON payload
            ObjectMapper mapper = new ObjectMapper();
            ObjectNode payload = mapper.createObjectNode();
            payload.put("customerEmail", "test@example.com");
            payload.put("customerId", "connectivity-test");
            payload.put("amountInUSD", 1);

            // Build HTTP request
            HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();

            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(baseUrl + "/api/v1/payment"))
                .header("API-Key", apiKey)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload)))
                .timeout(Duration.ofSeconds(10))
                .build();

            // Send request
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() == 200 || response.statusCode() == 201) {
                ObjectNode result = (ObjectNode) mapper.readTree(response.body());
                System.out.println("✅ Connection successful!");
                System.out.println("   Reference ID: " + result.get("reference_id").asText());
                System.out.println("   Checkout URL: " + result.get("url").asText());
                return true;
            } else {
                System.out.println("❌ Connection failed: Status " + response.statusCode());
                System.out.println("   Response: " + response.body());
                return false;
            }

        } catch (Exception e) {
            System.out.println("❌ Connection failed: " + e.getMessage());
            return false;
        }
    }
}

Step 4: Interpret Results

Success (200/201):

{
  "checkout": {
    "id": "...",
    "url": "https://...",
    ...
  }
}

Your configuration is correct and Payram is reachable.

401 Unauthorized:

  • Check that API-Key header is used (not Authorization)
  • Verify the API key is correct and hasn’t been revoked
  • Ensure the key is for the correct project/workspace

404 Not Found:

  • Verify PAYRAM_BASE_URL is correct
  • Check for typos in the endpoint path
  • Confirm Payram is deployed and running

Network Errors:

  • Verify firewall rules allow outbound HTTPS
  • Check DNS resolution of your Payram domain
  • Confirm SSL certificates are valid

Best Practices

  1. Environment Separation

    • Use different API keys for staging vs production
    • Never share API keys between environments
    • Rotate keys regularly
  2. Security

    • Store API keys in secure secret management systems (AWS Secrets Manager, Vault, etc.)
    • Never log full API keys
    • Use environment-specific .env files (.env.staging, .env.production)
  3. Error Handling

    • Always check response status codes
    • Log failures with context but without sensitive data
    • Implement retry logic with exponential backoff for network errors
  4. Validation

    • Test connectivity before deploying to production
    • Run connectivity tests as part of CI/CD health checks
    • Monitor connection health in production with periodic pings

Troubleshooting

“Missing PAYRAM_BASE_URL or PAYRAM_API_KEY”

Cause: Environment variables not loaded.

Solution:

  • Ensure .env file exists in project root
  • Verify .env contains both variables
  • Check that your code loads .env (e.g., dotenv.config() in Node, load_dotenv() in Python)

“401 Unauthorized” or “Authentication Failed”

Cause: Invalid or missing API key.

Solution:

  • Confirm you’re using API-Key header, not Authorization
  • Regenerate API key in Payram dashboard if needed
  • Check for extra whitespace in .env values

“Network error” or “Connection refused”

Cause: Payram server unreachable.

Solution:

  • Verify PAYRAM_BASE_URL includes protocol (https://)
  • Check firewall rules and network connectivity
  • Confirm Payram service is running (systemctl status payram)

“404 Not Found”

Cause: Wrong endpoint or base URL.

Solution:

  • Remove trailing slashes from PAYRAM_BASE_URL
  • Verify endpoint path is /api/v1/payment
  • Check Payram version compatibility

Related Skills

  • integrate-payments – After setup, implement payment flows
  • integrate-payouts – Configure outbound payment capabilities
  • handle-webhooks – Receive Payram event notifications