Skip to main content

Quick Start: Your First Payment

This guide walks you through creating a complete payment flow from merchant registration to payment completion. You’ll learn how to use Payment Intents to create a secure, hosted checkout experience for your customers.
What You’ll Build: A payment flow where your customer is redirected to a secure checkout page, completes payment, and is redirected back to your site.

Overview: Payment Intent Flow


Prerequisites

Before you start, you’ll need:

API Endpoint

https://paymentgateway.redahaloubi.com

Test Card

4242 4242 4242 4242
Exp: 12/2027
CVV: 123
Production Environment: This guide uses the live production API. All payments are simulated (no real money is charged), but use test cards only.

Step 1: Register Your Account

First, create a user account to access the platform.

Register User

curl -X POST https://paymentgateway.redahaloubi.com/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Merchant",
    "email": "[email protected]",
    "password": "SecurePass123!"
  }'
{
  "success": true,
  "data": {
    "user": {
      "id": "{user_id}",
      "name": "John Merchant",
      "email": "[email protected]",
      "email_verified": false,
      "status": "pending_verification",
      "created_at": "2026-01-24T10:00:00Z"
    }
  },
  "message": "Registration successful. Please verify your email."
}
400 Bad Request - Email already exists
{
  "success": false,
  "error": "email already registered"
}
400 Bad Request - Weak password
{
  "success": false,
  "error": "password must be at least 8 characters"
}

Step 2: Login & Get Access Token

Login to receive a JWT access token for API authentication.

Login

curl -X POST https://paymentgateway.redahaloubi.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "SecurePass123!"
  }'
{
  "success": true,
  "data": {
    "user": {
      "id": "{user_id}",
      "name": "John Merchant",
      "email": "[email protected]",
      "status": "active"
    },
    "access_token": "{jwt_access_token}",
    "refresh_token": "{jwt_refresh_token}",
    "token_type": "Bearer",
    "expires_in": 86400
  }
}
Save Your Access Token: Copy the access_token value. You’ll need it for all subsequent API calls.Example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Step 3: Create a Merchant Account

Create a merchant profile to start accepting payments.

Create Merchant

curl -X POST https://paymentgateway.redahaloubi.com/api/v1/merchants \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {jwt_access_token}" \
  -d '{
    "business_name": "Your Store Inc",
    "email": "[email protected]",
    "business_type": "corporation",
    "website": "https://yourstore.com"
  }'
{
  "success": true,
  "data": {
    "merchant": {
      "id": "{merchant_id}",
      "merchant_code": "mch_abc123def456",
      "business_name": "Your Store Inc",
      "email": "[email protected]",
      "status": "pending_review",
      "owner_id": "{user_id}",
      "created_at": "2026-01-24T10:05:00Z"
    }
  },
  "message": "Merchant created successfully"
}
Save Your Merchant ID: Copy the id value from the response. You’ll need it to generate API keys.Example: 550e8400-e29b-41d4-a716-446655440000

Step 4: Generate API Key

Create an API key to authenticate payment requests from your server.

Create API Key

curl -X POST https://paymentgateway.redahaloubi.com/api/v1/merchants/api-keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {jwt_access_token}" \
  -d '{
    "merchant_id": "{merchant_id}",
    "name": "Production API Key"
  }'
{
  "success": true,
  "data": {
    "api_key": {
      "id": "{api_key_id}",
      "name": "Production API Key",
      "key_prefix": "pk_live_",
      "created_at": "2026-01-24T10:10:00Z"
    },
    "plain_key": "pk_live_abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"
  },
  "message": "⚠️ Save this API key! It won't be shown again."
}
IMPORTANT: Save Your API Key!The plain_key is only shown once. Store it securely in your environment variables.Example:
export PAYMENT_GATEWAY_API_KEY="pk_live_abc123def456..."
If you lose it, you’ll need to generate a new key.

Step 5: Create a Payment Intent

Now you’re ready to create your first payment! A Payment Intent represents a customer’s payment session.

Create Payment Intent

curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payment-intents \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {your_api_key}" \
  -d '{
    "merchant_id": "{merchant_id}",
    "amount": 9999,
    "currency": "USD",
    "success_url": "https://yourstore.com/order/success?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url": "https://yourstore.com/order/cancel",
    "description": "Order #12345 - Premium Plan",
    "metadata": {
      "order_id": "12345",
      "customer_id": "cus_abc123"
    }
  }'
{
  "success": true,
  "data": {
    "id": "pi_abc123def456ghi789",
    "client_secret": "pi_abc123def456ghi789_secret_xyz789uvw456rst123",
    "checkout_url": "https://checkout-page-amber.vercel.app/checkout/pi_abc123def456ghi789?client_secret=pi_abc123def456ghi789_secret_xyz789uvw456rst123",
    "amount": 9999,
    "currency": "USD",
    "status": "created",
    "success_url": "https://yourstore.com/order/success",
    "cancel_url": "https://yourstore.com/order/cancel",
    "description": "Order #12345 - Premium Plan",
    "expires_at": "2026-01-24T11:10:00Z",
    "created_at": "2026-01-24T10:10:00Z"
  }
}

Understanding the Response

1

Payment Intent ID

id: Unique identifier for this payment sessionUse this to check payment status or cancel the intent.
2

Client Secret

client_secret: Browser-safe authentication tokenInclude this in the checkout URL to authenticate the customer’s session securely.
3

Checkout URL

checkout_url: Ready-to-use checkout page URLPre-built URL with payment intent ID and client secret included. Simply redirect your customer to this URL.
4

Expiration

expires_at: Automatic expiration timestamp (1 hour)Payment intents expire automatically for security. Customer must complete payment before this time.

Step 6: Redirect Customer to Checkout

The payment intent response includes a ready-to-use checkout_url. Simply redirect your customer to this URL. The response includes a pre-built checkout URL with all required parameters:
// From the payment intent response
const checkoutUrl = paymentIntent.checkout_url;
// Example: https://checkout-page-amber.vercel.app/checkout/pi_abc123def456?client_secret=pi_abc123_secret_xyz789

Option 2: Build the URL manually

# Base URL
CHECKOUT_URL="https://checkout-page-amber.vercel.app/checkout"

# Add payment intent ID and client secret
FULL_URL="${CHECKOUT_URL}/{payment_intent_id}?client_secret={client_secret}"

# Example:
https://checkout-page-amber.vercel.app/checkout/pi_abc123def456ghi789?client_secret=pi_abc123def456ghi789_secret_xyz789uvw456rst123

Implementation Examples

<!-- On your order confirmation page -->
<script>
  // Use the checkout_url from payment intent response
  const checkoutUrl = "https://checkout-page-amber.vercel.app/checkout/pi_abc123def456?client_secret=pi_abc123_secret_xyz789";
  window.location.href = checkoutUrl;
</script>

Step 7: Customer Completes Payment

Your customer will see a secure checkout page where they can enter their card details.
Checkout Page

What Happens on the Checkout Page

1

Payment Intent Validation

The checkout page validates the client_secret to ensure the session is valid and not expired.
2

Customer Enters Card Details

Customer enters:
  • Card number (e.g., 4242 4242 4242 4242)
  • Cardholder name
  • Expiry date (MM/YY)
  • CVV (3 digits)
All validation happens client-side first (Luhn algorithm, expiry checks).
3

Payment Processing

When customer clicks “Pay $99.99”:
  1. Card data sent to Payment API (secured by client_secret)
  2. Card tokenized (never stored in plain text)
  3. Transaction authorized or declined
  4. Payment intent status updated
4

Automatic Redirect

Based on payment result:
  • Success: Redirects to success_url with payment intent ID
  • Declined: Shows error, allows retry (max 5 attempts)
  • ⏱️ Expired: Redirects to cancel_url

Test Cards for Development

✅ Successful Payment

Card Number: 4242 4242 4242 4242Expiry: Any future date (e.g., 12/2027)CVV: Any 3 digits (e.g., 123)Result: Authorization approved

❌ Declined - Insufficient Funds

Card Number: 4000 0000 0000 9995Expiry: Any future dateCVV: Any 3 digitsResult: Declined with code 51

❌ Declined - Expired Card

Card Number: 4000 0000 0000 0069Expiry: Any future dateCVV: Any 3 digitsResult: Declined with code 54

❌ Declined - CVV Mismatch

Card Number: 4000 0000 0000 0127Expiry: Any future dateCVV: Any 3 digitsResult: Declined with code N7
All test cards:
  • Use any future expiry date (e.g., 12/2027)
  • Use any cardholder name
  • For Mastercard, use: 5555 5555 5555 4444 (approved)

Step 8: Handle Success Redirect

After successful payment, the customer is redirected back to your success_url.

Success URL Parameters

https://yourstore.com/order/success?session_id=pi_abc123def456ghi789&payment_intent=pi_abc123def456ghi789
payment_intent
string
required
The payment intent ID that was just completed
session_id
string
Same as payment_intent (included if you used {CHECKOUT_SESSION_ID} placeholder)

Verify Payment Status

Always verify the payment status on your server (don’t trust client-side redirects alone).
curl -X GET https://paymentgateway.redahaloubi.com/api/v1/payment-intents/{payment_intent_id} \
  -H "X-API-Key: {your_api_key}"
{
  "success": true,
  "data": {
    "id": "pi_abc123def456ghi789",
    "status": "authorized",
    "payment_id": "pay_xyz123abc456",
    "amount": 9999,
    "currency": "USD",
    "card_brand": "visa",
    "card_last4": "4242",
    "auth_code": "123456",
    "created_at": "2026-01-24T10:10:00Z",
    "confirmed_at": "2026-01-24T10:15:23Z"
  }
}

Implementation Example

app.get('/order/success', async (req, res) => {
  const paymentIntentId = req.query.payment_intent;
  
  // Verify payment status server-side
  const response = await fetch(
    `https://paymentgateway.redahaloubi.com/api/v1/payment-intents/${paymentIntentId}`,
    {
      headers: {
        'X-API-Key': process.env.PAYMENT_GATEWAY_API_KEY
      }
    }
  );
  
  const data = await response.json();
  
  if (data.data.status === 'authorized' || data.data.status === 'captured') {
    // Payment successful - fulfill order
    await fulfillOrder(data.data.payment_id);
    res.render('order-success', { payment: data.data });
  } else {
    // Payment not completed
    res.redirect('/order/cancel');
  }
});

Step 9: Receive Webhook Notifications (Optional)

For asynchronous payment confirmation, configure webhooks to receive real-time updates.

Configure Webhook URL

First, set your webhook URL in merchant settings:
curl -X PATCH https://paymentgateway.redahaloubi.com/api/v1/merchants/{merchant_id}/settings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {jwt_access_token}" \
  -d '{
    "webhook_url": "https://yourstore.com/webhooks/payment",
    "webhook_secret": "{your_webhook_secret}"
  }'

Webhook Payload

When payment status changes, you’ll receive a POST request:
{
  "event": "payment.authorized",
  "timestamp": "2026-01-24T10:15:23Z",
  "id": "evt_abc123def456",
  "data": {
    "payment_intent_id": "pi_abc123def456ghi789",
    "payment_id": "pay_xyz123abc456",
    "merchant_id": "{merchant_id}",
    "status": "authorized",
    "amount": 9999,
    "currency": "USD",
    "card_brand": "visa",
    "card_last4": "4242",
    "auth_code": "123456",
    "created_at": "2026-01-24T10:15:23Z"
  }
}

Verify Webhook Signature

Always verify webhook signatures to ensure requests are from Payment Gateway.
const crypto = require('crypto');

app.post('/webhooks/payment', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const payload = JSON.stringify(req.body);
  
  // Compute expected signature
  const expected = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  if (signature !== expected) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook
  const event = req.body;
  if (event.event === 'payment.authorized') {
    fulfillOrder(event.data.payment_id);
  }
  
  res.status(200).send('OK');
});

🎉 Congratulations!

You’ve successfully:
1

✅ Registered an account

Created user credentials and logged in
2

✅ Created a merchant

Set up your business profile
3

✅ Generated API key

Obtained credentials for payment processing
4

✅ Created payment intent

Initiated a customer payment session
5

✅ Processed payment

Customer completed payment on hosted checkout
6

✅ Verified payment

Confirmed payment status on your server

Next Steps

Auth API Reference

Explore user management, roles, and API keys

Merchant API Reference

Manage teams, settings, and webhooks

Payment API Reference

Learn about capture, void, refund operations

Checkout Integration

Customize the checkout experience

Common Issues

Cause: API key is incorrect or expiredSolution:
  • Verify you’re using the correct API key (starts with pk_live_ or pk_test_)
  • Check the key hasn’t been deactivated
  • Generate a new API key if needed
Cause: Amount must be in cents (integer)Solution:
  • ❌ Wrong: "amount": 99.99
  • ✅ Correct: "amount": 9999 (represents $99.99)
Cause: Client secret doesn’t match payment intentSolution:
  • Ensure you’re using the correct client_secret from the payment intent response
  • Check the payment intent hasn’t expired (1 hour limit)
  • Verify the payment intent ID in the URL matches the client secret
Cause: Trying to confirm a payment intent that’s already authorizedSolution:
  • Check payment intent status first: GET /payment-intents/:id
  • If status is authorized, payment is already complete
  • Create a new payment intent for a new payment
Cause: Test card triggered a decline scenarioSolution:
  • Use approved test card: 4242 4242 4242 4242
  • Check you’re using a future expiry date
  • See test cards section for specific decline scenarios

Need Help?

GitHub Issues

Report bugs or request features

Email Support

Contact for technical assistance

Ready to integrate? Head to the API Reference to explore all available endpoints!