> ## Documentation Index
> Fetch the complete documentation index at: https://docs.deployhub.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Verify Payment and Activate Subscription

> Verify Razorpay payment signature and activate user subscription

This endpoint verifies the Razorpay payment signature using HMAC-SHA256, creates a project, and activates the user's subscription with automated expiry notifications.

## Authentication

Requires JWT authentication via the `verifyJWT` middleware.

## Request Body

<ParamField body="razorpay_payment_id" type="string" required>
  The payment ID returned by Razorpay after successful payment
</ParamField>

<ParamField body="razorpay_order_id" type="string" required>
  The order ID created in the [init endpoint](/api/subscriptions/init)
</ParamField>

<ParamField body="razorpay_signature" type="string" required>
  The signature generated by Razorpay to verify payment authenticity
</ParamField>

## Signature Verification

The endpoint verifies payment authenticity using HMAC-SHA256:

```javascript theme={null}
const generated_signature = crypto
  .createHmac("sha256", process.env.KEY_SECRET)
  .update(razorpay_order_id + "|" + razorpay_payment_id)
  .digest("hex");

if (generated_signature === razorpay_signature) {
  // Payment verified
}
```

Implementation details in `verify.controller.js:20`.

<Warning>
  The `KEY_SECRET` is your Razorpay API secret. Never expose this on the client side. Signature verification must always happen on the server.
</Warning>

## Subscription Duration

The subscription end date is calculated based on the environment:

### Production Environment

* **Start Date**: Current timestamp
* **End Date**: Current timestamp + (months × 30 days)
* **Expiry Warning**: 5 days before end date (months × 25 days)

### Development/Test Environment

* **Start Date**: Current timestamp
* **End Date**: Current timestamp + 60 minutes
* **Expiry Warning**: 2 minutes before end

```javascript theme={null}
const subscriptionEnd = process.env.NODE_ENV === "production"
  ? new Date(now.getTime() + months * 30 * 24 * 60 * 60 * 1000)
  : new Date(now.getTime() + 60 * 60 * 1000);
```

See implementation in `verify.controller.js:54`.

## Response

<ResponseField name="success" type="boolean">
  Indicates successful payment verification
</ResponseField>

<ResponseField name="userSubscribe" type="object">
  User's subscription status (if available)
</ResponseField>

<ResponseField name="projectId" type="string">
  The ID of the newly created project
</ResponseField>

<ResponseField name="message" type="string">
  Success message: `"Payment verified successfully!"`
</ResponseField>

## Activation Flow

On successful verification, the endpoint performs the following operations:

### 1. Verify Pending Order

* Fetches `PendingOrder` matching user ID and order ID
* Validates order exists and status is not already `"completed"`
* Prevents duplicate processing

### 2. Create Completed Order

Creates a `CompletedOrder` record with:

* `userid`: User ID
* `orderid`: Razorpay order ID
* `months`: Subscription duration
* `amount`: Payment amount in paise
* `plan`: Subscription plan ("pro")
* `status`: `"completed"`
* `projectid`: Reference to created project

### 3. Create Project

Creates a new `Project` with:

* `paymentId`: Reference to CompletedOrder
* `plan`: Subscription plan ("pro")
* `startDate`: Current timestamp
* `endDate`: Calculated expiry date
* `owner`: Authenticated user ID

### 4. Schedule Background Jobs

Three Bull queue jobs are scheduled:

#### Expiry Warning Notification

```javascript theme={null}
await isBeforeExpiryNotify.add(
  "deployhub-isBeforeExpiryQueue",
  {
    userId: req.user._id,
    email: req.user.email,
    fullname: req.user.fullName
  },
  {
    delay: isBeforeExpiryDate - Date.now(),
    jobId: req.user._id.toString(),
    removeOnComplete: true
  }
);
```

#### Subscription Start Notification

```javascript theme={null}
await subscriptionStart.add("deployhub-subscriptionstart", {
  fullName: req.user.fullName,
  email: req.user.email,
  price: orderfromdb.amount / 100,
  duration: orderfromdb.months,
  plan: orderfromdb.plan
});
```

#### Subscription Expiry Handler

```javascript theme={null}
await subscriptionExpire.add(
  "deployhub-subscriptionend",
  { userId: req.user._id },
  {
    jobId: req.user._id.toString(),
    delay: subscriptionend - Date.now()
  }
);
```

See `verify.controller.js:87`.

### 5. Update Order Status

Marks `PendingOrder` status as `"completed"` to prevent reprocessing.

## Request Example

```bash theme={null}
curl -X POST https://api.deployhub.com/api/subscription/verify \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "razorpay_payment_id": "pay_KjQ5xU0vFJmJ4r",
    "razorpay_order_id": "order_rcptid_0.8347562",
    "razorpay_signature": "9b5e67890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
  }'
```

## Response Examples

### Success Response

```json theme={null}
{
  "success": true,
  "userSubscribe": {
    "plan": "pro",
    "status": "active"
  },
  "projectId": "507f1f77bcf86cd799439011",
  "message": "Payment verified successfully!"
}
```

### Missing Parameters

```json theme={null}
{
  "message": "required details fro verify payment"
}
```

### User Not Found

```json theme={null}
{
  "success": false,
  "message": "User not found!"
}
```

### Order Not Found

```json theme={null}
{
  "message": "something went wrong! PLease Contact your team"
}
```

### Already Processed

```json theme={null}
{
  "message": "Your Oder ALready PRocessed"
}
```

### Invalid Signature

```json theme={null}
{
  "success": false,
  "message": "Payment verification failed!"
}
```

### Server Error

```json theme={null}
{
  "error": "Error verifying payment"
}
```

## Security Considerations

<Warning>
  Always verify the signature on the server side. Never trust payment verification from the client.
</Warning>

1. **Signature Verification**: Uses HMAC-SHA256 with your Razorpay secret key
2. **Duplicate Prevention**: Checks if order is already processed
3. **User Authentication**: Requires valid JWT token
4. **Order Ownership**: Verifies order belongs to authenticated user
5. **Expiry Protection**: Pending orders auto-delete after 2 hours

## Database Schema

### CompletedOrder

```javascript theme={null}
{
  userid: ObjectId,           // Reference to User
  orderid: String,            // Razorpay order ID
  months: Number,             // Subscription duration
  amount: Number,             // Payment amount in paise
  plan: String,               // "pro"
  status: String,             // "completed"
  projectid: ObjectId,        // Reference to Project
  createdAt: Date,
  updatedAt: Date
}
```

### Project Updates

```javascript theme={null}
{
  paymentId: ObjectId,        // Reference to CompletedOrder
  plan: "pro",                // Subscription plan
  startDate: Date,            // Subscription start
  endDate: Date,              // Subscription expiry
  owner: ObjectId,            // User ID
  status: "pending"           // Initial status
}
```

## Integration Example

```javascript theme={null}
// Frontend Razorpay integration
const options = {
  key: "rzp_test_...",
  amount: order.amount,
  currency: "INR",
  name: "DeployHub",
  description: "Pro Plan Subscription",
  order_id: order.id,
  handler: async function (response) {
    // Send to verify endpoint
    const result = await fetch('/api/subscription/verify', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        razorpay_payment_id: response.razorpay_payment_id,
        razorpay_order_id: response.razorpay_order_id,
        razorpay_signature: response.razorpay_signature
      })
    });
    
    const data = await result.json();
    if (data.success) {
      console.log('Project ID:', data.projectId);
      // Redirect to project dashboard
    }
  }
};

const rzp = new Razorpay(options);
rzp.open();
```

## Error Handling

The endpoint handles several error scenarios:

1. **Missing payment details** (400): Returns error if any required field is missing
2. **Invalid user** (400): User must be authenticated
3. **Order not found** (400): Order must exist in PendingOrders
4. **Already processed** (400): Prevents duplicate subscription activation
5. **Signature mismatch** (400): Payment verification failed
6. **Server errors** (500): Database or Razorpay API errors

## Best Practices

1. **Idempotency**: The endpoint checks for already-processed orders
2. **Atomic Operations**: Uses database transactions where possible
3. **Background Jobs**: Email notifications are queued, not blocking
4. **Error Logging**: Errors are logged to console for debugging
5. **Webhook Integration**: Consider adding Razorpay webhooks for redundancy

<Warning>
  In production, implement webhook verification as a backup to handle edge cases where the user closes the browser before the verify call completes.
</Warning>
