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

# Error Codes

> Reference of Payment SDK API and error codes

## HTTP Error Responses

All API errors return a JSON response with an error message.

```json theme={null}
{
  "error": "The 'amount' field is required."
}
```

### Status Codes

| Status | Description                                                         | Resolution                                                          |
| ------ | ------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `400`  | Invalid request — malformed body, missing fields, or invalid values | Check that `amount` is a positive number and `currency` is provided |
| `401`  | Unauthorized — API key is missing, invalid, or revoked              | Verify your `CUBEPAY_API_KEY` environment variable                  |
| `500`  | Internal server error                                               | Retry with exponential backoff                                      |
| `502`  | Bad gateway — upstream payment service unavailable                  | The Grain API is temporarily unreachable. Retry shortly             |

***

## SDK Errors

These errors are thrown by the client-side SDK service during payment execution.

### CubePayClosedError

Thrown when the user closes the payment modal without completing the transaction. This is **not a failure** — it indicates the user chose to cancel.

```typescript theme={null}
try {
  const result = await cubePayService.executePayment({ amount: 50, currency: "USD" });
} catch (error) {
  if (error.name === "CubePayClosedError") {
    // User cancelled — handle gracefully
    return;
  }
  throw error;
}
```

### Initialization Errors

| Error Message                                                  | Cause                                                 | Resolution                                                 |
| -------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- |
| `NEXT_PUBLIC_CUBEPAY_MERCHANT_ID is not set`                   | Missing merchant ID environment variable              | Add the variable to your `.env` file                       |
| `Missing CubePay container element with id 'cubepay-sdk-root'` | Mount point not in the DOM                            | Add `<div id="cubepay-sdk-root" />` to your layout         |
| `Failed to load Cubist Pay SDK script`                         | SDK bundle not found or failed to load                | Verify `public/vendor/cubist-pay-client-sdk.umd.js` exists |
| `Failed to load Cubist Pay SDK`                                | `window.CubePaySDK` not available after script loaded | Check the browser console for script errors                |

### Session Creation Errors

| Error Message                      | Cause                                          | Resolution                                          |
| ---------------------------------- | ---------------------------------------------- | --------------------------------------------------- |
| `Amount must be a positive number` | Invalid amount (zero, negative, NaN, Infinity) | Validate the amount before calling `executePayment` |
| `Failed to create payment session` | Server returned a non-2xx response             | Check server logs for the upstream API error        |
| `Payment service unavailable`      | Network error or API timeout                   | Retry the request                                   |

***

## Webhook Error Handling

Your webhook endpoint should always return `200` regardless of internal processing status:

```typescript theme={null}
export async function POST(request: Request) {
  try {
    const body = await request.json();
    await processWebhook(body);
  } catch (error) {
    // Log but don't return an error status
    console.error("Webhook processing failed:", error);
  }

  // Always acknowledge receipt
  return NextResponse.json({ jsonrpc: "2.0", result: "ok" });
}
```

<Warning>
  Returning a non-2xx status causes the payment service to retry webhook delivery. Always return `200` to prevent duplicate processing.
</Warning>

***

## Debugging Tips

<Accordion title="Check the browser console">
  The SDK logs initialization steps and errors to the browser console. Open DevTools and filter for "CubePay" or "cubepay" messages.
</Accordion>

<Accordion title="Verify environment variables">
  Missing or incorrect environment variables are the most common cause of SDK failures. Double-check that `NEXT_PUBLIC_CUBEPAY_MERCHANT_ID` is set on the client and `CUBEPAY_API_KEY` is set on the server.
</Accordion>

<Accordion title="Use development mode">
  When `CUBEPAY_API_KEY` is absent and `NODE_ENV` is not `production`, the SDK returns mock data. This is useful for isolating whether an issue is in your code or the API integration.
</Accordion>

<Accordion title="Inspect network requests">
  Use the browser Network tab to inspect requests to `/api/payment-sessions`. Check that the request body is valid JSON and the response contains `paymentSessionId` and `paymentSessionToken`.
</Accordion>
