CourseLayer Logo

Checkout

Payment processing and course purchase endpoints

Process course purchases and handle payment transactions.

Process Checkout

Requires authentication. Process a checkout request for one or multiple courses.

Endpoint

POST /api/v1/checkout

Headers

Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

Request Body

Prop

Type

Example Request

{
  "courses": [123, 456, 789]
}

Response Codes

{
  "status": "SUCCESS",
  "checkout_url": "https://checkout.stripe.com/...",
  "session_id": "cs_test_...",
  "order_id": 12345,
  "total_amount": 199.97,
  "courses": [
    {
      "id": 123,
      "title": "JavaScript Fundamentals",
      "price": 49.99
    },
    {
      "id": 456,
      "title": "Advanced React",
      "price": 99.99
    },
    {
      "id": 789,
      "title": "Node.js Mastery",
      "price": 49.99
    }
  ]
}

Redirect the user to the checkout_url to complete the payment.

{
  "status": "ERROR",
  "message": "Unauthorized - Please log in"
}
{
  "status": "ERROR",
  "message": "Access forbidden"
}

This may occur if the user's account is restricted or if they've already purchased the courses.

{
  "status": "ERROR",
  "message": "Validation failed",
  "errors": {
    "courses": [
      "The courses field is required.",
      "At least one course must be selected."
    ]
  }
}
{
  "status": "ERROR",
  "message": "An error occurred while processing your request"
}

Checkout Flow

Select Courses

User browses courses and adds them to cart. Collect course IDs for purchase.

Authenticate User

Ensure user is logged in and has a valid access token.

Create Checkout Session

Send POST request to /api/v1/checkout with course IDs.

Redirect to Payment

Redirect user to the checkout_url returned in the response.

Handle Webhook

Listen for payment confirmation webhooks from your payment provider.

Grant Access

Upon successful payment, courses are automatically added to user's account.


Important Notes

Security Considerations

  • Never process payments client-side
  • Always validate course availability and pricing server-side
  • Use HTTPS for all checkout requests
  • Implement CSRF protection

Pricing Validation

The API automatically validates:

  • Course availability
  • Current pricing (prevents price manipulation)
  • User eligibility
  • Course ownership (prevents duplicate purchases)

Payment Methods

The checkout process supports multiple payment methods depending on your payment provider configuration:

  • Credit/Debit Cards
  • Digital Wallets (Apple Pay, Google Pay)
  • Bank Transfers
  • Local Payment Methods

Testing Checkout

Use test course IDs and test payment credentials in your development environment.

Test Request

curl -X POST https://api.courselayer.com/api/v1/checkout \
  -H "Authorization: Bearer YOUR_TEST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "courses": [1, 2, 3]
  }'

Webhook Testing

To test webhook functionality:

  1. Set up a webhook endpoint in your application
  2. Configure the webhook URL in your CourseLayer settings
  3. Use test mode to trigger payment events
  4. Verify your endpoint receives and processes webhooks correctly

Error Handling

Common Errors

Error CodeDescriptionSolution
401User not authenticatedEnsure valid Bearer token is provided
403Access forbiddenCheck user has permission to purchase courses
422Invalid course IDsVerify all course IDs exist and are available
500Payment processing errorRetry request or contact support

Retry Logic

Implement exponential backoff for failed requests:

async function checkoutWithRetry(courses, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch('/api/v1/checkout', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ courses })
      });
      
      if (response.ok) {
        return await response.json();
      }
      
      if (response.status >= 400 && response.status < 500) {
        // Client error, don't retry
        throw new Error('Client error');
      }
      
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
    }
  }
}