# Glomo S2S Integration - Technical Documentation

## Overview

Server-to-Server (S2S) integration allows you to collect card details on your platform and process payments through Glomopay's infrastructure. This integration is designed for PCI DSS certified merchants who want to maintain control over the payment experience while leveraging Glomopay's cross-border payment processing capabilities.

## Prerequisites

- **PCI DSS Certification**: You must be PCI DSS certified to collect and transmit card details
- **Glomopay Account**: Active merchant account
- **API Keys**: Secret keys for both sandbox (test) and production (live) environments


## Environment Configuration

### API Endpoint

All API requests use the same base URL for both environments:


```
https://api.glomopay.com
```

### Authentication

The secret key in your Authorization header determines the environment:

- **Sandbox Key** → Creates orders and payments in test mode
- **Production Key** → Creates orders and payments in live mode



```
Authorization: Bearer YOUR_SECRET_KEY
```

### Getting Your API Keys

1. Navigate to: https://app.glomopay.com/api-keys-and-webhooks/api-keys
2. Use the toggle to switch between Test Mode and Live Mode
3. Reveal / Regenerate the API key


For more information on Secret Keys, please refer to [Authentication](/api-documentation/authentication)

## Integration Flow

### Step 1: Before accepting payment, you need to create an order or a subscription in Glomo's system.

### One Time Payment - Orders

To learn what an order is, refer to [Orders](/product-guide/payin/order).

For the full API reference, refer to [Create Order API](/api-documentation/apis/openapi/orders/createorder).

### Subscriptions

With `as_presented` subscriptions, subsequent payments are merchant-initiated — no customer action is required. Card details are automatically carried over from the initial payment, so the `card`, `callback_url`, and `method` fields can be omitted.

To learn what a subscription is, refer to: [Subscriptions](https://docs.glomopay.com/product-guide/payin/subscriptions).

For the full API reference, refer to: [Create a Subscription API](https://docs.glomopay.com/api-documentation/apis/openapi/subscription/createsubscription).

### Step 2: Initiate Payment

Once you have the order_id/subscription_id generated from Step 1, submit card details to initiate payment.

**Request Body:**


```bash
curl -i -X POST \
  https://api.glomopay.com/api/v1/payment \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "order_id": "order_68c00b7btsthf",
    "subscription_id": "sub_5JU9yv0lGSUP",
    "method": "card",
    "sequence": "initial",
    "card": {
      "holder_name": "John Doe",
      "number": "4111111111111111",
      "expiry_month": "09",
      "expiry_year": "2030",
      "cvv": "123"
    },
    "callback_url": "https://server.yoursite.com/payment/callback",
    "notes": {
      "internal_ref": "ref_12345"
    }
  }'
```

**Request Body Parameters:**

| Parameter | Type | Required | Description |
|  --- | --- | --- | --- |
| order_id | string | Yes* | Order ID. Either `order_id` or `subscription_id` must be provided, but not both. |
| subscription_id | string | Yes* | Subscription ID. Either `order_id` or `subscription_id` must be provided, but not both. |
| method | string | Yes (initial) | Payment method. Must be `card`. Not required for subsequent payments (defaults to `card`). |
| sequence | string | No | Payment sequence: `initial` (default) or `subsequent`. Use `subsequent` for merchant-initiated payments on `as_presented` subscriptions. |
| card | object | Yes (initial) | Card details (holder_name, number, expiry_month, expiry_year, cvv). Required for initial payments. Not required for subsequent payments — the card from the last successful payment is reused. |
| callback_url | string | Yes (initial) | HTTPS URL for redirect after payment. Required for initial payments. Not required for subsequent payments as there is no customer redirect involved. |
| request_id | string | Yes (subsequent) | Idempotency key. Required for subsequent payments. |
| amount | integer | Yes (subsequent) | Payment amount in minor units. Required for subsequent subscription payments. Cannot exceed the subscription's `max_amount`. |
| currency | string | Yes (subsequent) | Currency code. Must match the subscription's currency for subsequent payments. |
| notes | object | No | Additional key-value metadata. |


**Response:**


```json
{
  "payment_id": "payt_691eeb9aV79Uk",
  "status": "pending",
  "next_steps": [
    {
      "action": "redirect",
      "payload": {
        "url": "https://secure.glomopay.com?paymentId=payt_123&authToken=ey...&redirectUrl=encoded_url"
      }
    },
    {
      "action": "poll",
      "payload": {
        "url": "https://api.glomopay.com/api/v1/payment/payt_691eeb9aV79Uk",
        "interval_in_ms": 5000
      }
    }
  ]
}
```

### Step 3: Handle Redirect

The response contains a redirect URL where the user needs to complete authentication (3DS, OTP, etc.).

| Method | Use Case | Implementation |
|  --- | --- | --- |
| New Tab | Web | `window.open(redirectUrl, '_blank')` |
| Same Tab | Web | `window.location.href = redirectUrl` |
| WebView | Mobile apps | Open URL in native WebView component |


### Step 4: Handle Callback

After payment processing, Glomopay redirects the user back to your `callback_url` with query parameters.

**Callback URL Format:**


```
https://server.yoursite.com/payment/callback?order_id=order_XXX&payment_id=payt_XXX&status=success&signature=abc123
```

**Query Parameters:**

| Parameter | Description | Values |
|  --- | --- | --- |
| order_id | The order identifier | order_XXX |
| payment_id | The payment identifier | payt_XXX |
| status | Payment outcome | success, failed |
| signature | HMAC signature for verification | SHA-256 hash |
| error | Something went wrong in the payment journey | message |


### Step 5: Verify Signature

Always verify the signature on your server to ensure the callback is authentic. The callback URL should point to your server, where you can perform this verification. The necessary information for verification will be sent in the query parameters. The response of this API call should ideally be a redirect to your frontend.

**Sample Code:**

details
summary
JavaScript

```javascript
const express = require('express');
const crypto = require('crypto');
const router = express.Router();

// Your Glomopay secret key (store in environment variables)
const GLOMOPAY_SECRET_KEY = process.env.GLOMOPAY_SECRET_KEY;

/**
 * Generate HMAC SHA256 signature for verification
 */
function generateSignature(orderId, paymentId, status, secret) {
  const data = `${orderId}|${paymentId}|${status}`;
  return crypto.createHmac('sha256', secret).update(data).digest('hex');
}

/**
 * Glomopay Payment Callback Handler
 */
router.get('/payment/callback', (req, res) => {
  // Extract query parameters
  const { order_id, payment_id, status, signature } = req.query;

  // Generate signature for verification
  const calculatedSignature = generateSignature(order_id, payment_id, status, GLOMOPAY_SECRET_KEY);

  // Verify signature
  if (signature !== calculatedSignature) {
    console.error('Signature verification failed');
    return res.redirect(`/payment/error?message=Invalid signature`);
  }

  // Signature is valid - proceed based on payment status
  console.log('Payment verified successfully');

  // Redirect based on payment status
  if (status === 'success') {
    return res.redirect(`/payment/success?order_id=${order_id}&payment_id=${payment_id}`);
  } else if (status === 'failed') {
    return res.redirect(`/payment/failed?order_id=${order_id}`);
  } else {
    return res.redirect(`/payment/error?order_id=${order_id}`);
  }
});

module.exports = router;
```

details
summary
PHP

```php
<?php

/**
 * Generate HMAC SHA256 signature for verification
 */
function generateSignature($orderId, $paymentId, $status, $secret) {
    $data = "$orderId|$paymentId|$status";
    return hash_hmac('sha256', $data, $secret);
}

// Verify signature
$calculatedSignature = generateSignature($orderId, $paymentId, $status, $glomopaySecretKey);
if ($signature !== $calculatedSignature) {
    // Signature verification failed
}
```

details
summary
Ruby

```ruby
require 'openssl'

# Generate HMAC SHA256 signature for verification
def generate_signature(order_id, payment_id, status, secret)
  data = "#{order_id}|#{payment_id}|#{status}"
  OpenSSL::HMAC.hexdigest('SHA256', secret, data)
end

# Verify signature
calculated_signature = generate_signature(order_id, payment_id, status, GLOMOPAY_SECRET_KEY)
if signature != calculated_signature
  # Signature verification failed
end
```

details
summary
Go

```go
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)

// generateSignature creates HMAC SHA256 signature for verification
func generateSignature(orderID, paymentID, status, secret string) string {
    data := fmt.Sprintf("%s|%s|%s", orderID, paymentID, status)

    h := hmac.New(sha256.New, []byte(secret))
    h.Write([]byte(data))

    return hex.EncodeToString(h.Sum(nil))
}

// Verify signature
calculatedSignature := generateSignature(orderID, paymentID, status, glomopaySecretKey)
if calculatedSignature != signature {
    // Signature verification failed
}
```

details
summary
Java

```java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public static boolean verifySignature(String orderId, String paymentId, String status,
                                      String signature, String secret) {
    try {
        String data = orderId + "|" + paymentId + "|" + status;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret.getBytes(), "HmacSHA256"));

        byte[] hash = mac.doFinal(data.getBytes());
        StringBuilder hex = new StringBuilder();
        for (byte b : hash) hex.append(String.format("%02x", b));

        return hex.toString().equals(signature);
    } catch (Exception e) {
        return false;
    }
}
```

### Step 6: Handle Webhooks

Webhooks deliver server-to-server notifications about payment events directly to your backend.

For complete webhook implementation details:
[Webhooks Documentation](/api-documentation/webhooks)

## Testing

### Test Cards

Use these cards in sandbox mode to simulate different scenarios:
[Test Card Details](/product-guide/payin/payment-methods/cards#test-card-details)

For technical support, contact your integration manager or reach out via the merchant dashboard.