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


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?


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