# Creating Payments

Learn how to create payment sessions and redirect customers to checkout.

---

## Basic Payment

Create a simple payment with amount, currency, and description:

+++ TypeScript
```typescript
import { HivePay } from '@hivepay/client';

const hivepay = new HivePay({ apiKey: 'sk_live_xxx' });

const payment = await hivepay.payments.create({
  amount: '10500',          // 10.500 (in satoshis/smallest unit)
  currency: 'HBD',          // 'HIVE' or 'HBD'
  description: 'Order #123' // Shown to customer
});

console.log(payment.id);          // Payment ID
console.log(payment.checkoutUrl); // Redirect URL
console.log(payment.status);      // 'pending'
```
+++ cURL
```bash
curl -X POST https://hivepay.me/api/public/payments \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "10500",
    "currency": "HBD",
    "description": "Order #123"
  }'
```
+++

---

## Amount Format

Amounts are specified as strings in the smallest unit (satoshis):

| Input | Actual Amount |
|-------|---------------|
| `"1000"` | 1.000 HIVE/HBD |
| `"10500"` | 10.500 HIVE/HBD |
| `"100000"` | 100.000 HIVE/HBD |

Both HIVE and HBD use 3 decimal precision.

---

## Payment Options

### Redirect URLs

Specify where to redirect customers after payment:

+++ TypeScript
```typescript
const payment = await hivepay.payments.create({
  amount: '10500',
  currency: 'HBD',
  description: 'Order #123',
  redirectUrl: 'https://yourstore.com/order/123/success',
  cancelUrl: 'https://yourstore.com/order/123/cancelled'
});
```
+++ cURL
```bash
curl -X POST https://hivepay.me/api/public/payments \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "10500",
    "currency": "HBD",
    "description": "Order #123",
    "redirectUrl": "https://yourstore.com/order/123/success",
    "cancelUrl": "https://yourstore.com/order/123/cancelled"
  }'
```
+++

### Custom Metadata

Attach custom data to a payment for your reference:

+++ TypeScript
```typescript
const payment = await hivepay.payments.create({
  amount: '10500',
  currency: 'HBD',
  description: 'Order #123',
  metadata: {
    orderId: '12345',
    customerId: 'cust_abc',
    items: ['item1', 'item2']
  }
});

// Metadata is returned with the payment
console.log(payment.metadata.orderId); // '12345'
```
+++

---

## Payment Response

A successful payment creation returns:

```json
{
  "id": "cmj7b2rg10004d2rimvum8kaz",
  "slug": "order-12345-a1b2c3d4",
  "redirectUrl": "https://hivepay.me/for/order-12345-a1b2c3d4"
}
```

| Field | Description |
|-------|-------------|
| `id` | Unique payment identifier |
| `slug` | URL-friendly identifier |
| `redirectUrl` | URL to redirect customer to |

---

## Redirecting to Checkout

After creating a payment, redirect the customer to the checkout URL:

![Payment Review](/images/payment-view.webp)

![Payment Methods](/images/payment-methods.webp)

+++ JavaScript (Browser)
```javascript
// Create payment on your server, then redirect
window.location.href = payment.checkoutUrl;
```
+++ React
```tsx
const handleCheckout = async () => {
  const payment = await createPayment(); // Your server call
  window.location.href = payment.checkoutUrl;
};

<button onClick={handleCheckout}>Pay with Hive</button>
```
+++ HTML Link
```html
<a href="https://hivepay.me/for/{paymentId}">Complete Payment</a>
```
+++

---

## After Payment

When the payment is completed or cancelled:

1. Customer is redirected to your `redirectUrl` or `cancelUrl`
2. A [webhook](/payments/webhooks/) is sent to your configured endpoint
3. You can [check the status](/payments/tracking/) using the payment ID

!!!success Best Practice
Always verify payment status via webhook or API before fulfilling orders. Don't rely solely on the redirect.
!!!

---

## AML Limits

HivePay enforces anti-money laundering (AML) checks on every payment creation request. If a single transaction or cumulative volume within a short timeframe exceeds the configured thresholds, the merchant account is flagged and all further session creation is blocked until KYC verification is completed.

When flagged, the API responds with:

```json
{
  "statusCode": 403,
  "statusMessage": "AML limit reached. Please contact us at aml@hivepay.me to perform KYC verification process."
}
```

!!!warning
Once your account is AML-flagged, **all** payment creation requests will be rejected until verification is complete. Contact **aml@hivepay.me** with your merchant account details to begin the KYC process.
!!!

---

## Error Handling

+++ TypeScript
```typescript
import { isHivePayError } from '@hivepay/client';

try {
  const payment = await hivepay.payments.create({
    amount: '10500',
    currency: 'HBD',
    description: 'Order #123'
  });
} catch (error) {
  if (isHivePayError(error)) {
    if (error.isForbidden()) {
      // Could be inactive account or AML limit reached
      console.error('Forbidden:', error.message);
    } else if (error.isValidation()) {
      console.error('Invalid payment data:', error.message);
    } else if (error.isAuthError()) {
      console.error('Invalid API key');
    } else {
      console.error('Payment creation failed:', error.message);
    }
  }
}
```
+++
