# How Generation Credits Are Released When APIMart Submission Fails

> Generation credits are automatically released upon APIMart submission failure. Learn how successful credit restoration prevents charges for unsuccessful image generation requests.

- Repository: [苍何/awesome-gpt-image-2](https://github.com/freestylefly/awesome-gpt-image-2)
- Tags: how-to-guide
- Published: 2026-09-09

---

**When an APIMart image generation request fails, the system immediately restores the reserved credits by invoking the `grant_user_credits` Supabase RPC through the `adjustCredits` helper function, ensuring users are never charged for unsuccessful submissions.**

The `freestylefly/awesome-gpt-image-2` repository implements a transactional credit system that reserves generation credits before submitting tasks to APIMart. Understanding how generation credits are released if APIMart submission fails is essential for maintaining accurate billing and user trust.

## The Credit Reservation Pattern

Before any network request is sent to APIMart, the system proactively reserves the required credits from the user’s balance. This reservation occurs in the main generation handler located in [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js). The code calls `adjustCredits` with a negative delta to deduct the estimated cost upfront.

This approach prevents race conditions where a user might spend credits on multiple concurrent requests without sufficient balance. The reservation is temporary; the credits are only permanently consumed once APIMart confirms the task creation.

## Handling Submission Failures in the API Layer

The actual submission to APIMart is wrapped in a try-catch block within [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js). The handler imports the `apimartSubmit` function from [`api/_lib/apimart.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/apimart.js), which encapsulates the HTTP logic for communicating with APIMart’s API.

If the `apimartSubmit` call throws an error—whether due to network timeouts, invalid authentication, or APIMart service errors—the catch block intercepts the failure. At this point, the system immediately triggers the credit restoration process before returning the error response to the client. This ensures that failed submissions never result in permanent credit deductions.

## Restoring Credits via Supabase RPC

The credit restoration mechanism relies on the `adjustCredits` utility defined in [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js). This helper function interfaces with the database by calling the `grant_user_credits` Supabase RPC (Remote Procedure Call).

When handling a failure, the code invokes `adjustCredits(userId, +creditsNeeded)`, passing a positive value to refund the previously deducted amount. The `grant_user_credits` function atomically increments the user’s credit balance, ensuring consistency even if multiple restoration attempts occur simultaneously.

## Persisting State on Successful Submissions

If the APIMart submission succeeds, the system transitions from a reserved state to a committed state. The handler records the task details in the `apimart_generation_tasks` table, defined in [`supabase/migrations/20260828090000_apimart_generation_tasks.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260828090000_apimart_generation_tasks.sql). This table stores the `apimart_task_id` alongside the user ID and the credit cost.

Only after successfully inserting this record are the credits considered permanently spent. If the database insertion fails after APIMart confirms the task, the system relies on the RPC’s atomicity to handle cleanup, though the primary failure mode addressed is the APIMart submission itself.

## Code Implementation

The following excerpts illustrate the transactional credit flow in [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) and the restoration helper in [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js).

```javascript
// ----- api/generate-image.js (excerpt) -----
import { apimartSubmit } from './_lib/apimart';
import { adjustCredits } from './_lib/supabase';

async function generateImage(req, res) {
  const { userId, prompt, creditsNeeded } = req.body;

  // 1️⃣ Reserve credits
  await adjustCredits(userId, -creditsNeeded);

  try {
    // 2️⃣ Submit to APIMart
    const task = await apimartSubmit({ prompt });
    // 3️⃣ Record task ID on success
    await recordApimartTask(userId, task.id, creditsNeeded);
    res.json({ taskId: task.id });
  } catch (err) {
    // 4️⃣ On failure – restore credits
    await adjustCredits(userId, +creditsNeeded);
    console.warn('APIMart generation submission failed', err);
    res.status(500).json({ error: 'Generation submission failed' });
  }
}

```

```javascript
// ----- api/_lib/supabase.js (excerpt) -----
export async function adjustCredits(userId, delta) {
  // Uses the Supabase RPC `grant_user_credits`
  const { error } = await supabase
    .rpc('grant_user_credits', { uid: userId, amount: delta });
  if (error) throw error;
}

```

## Key Files Reference

The credit restoration logic spans several critical files in the repository:

- **[`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js)** – Orchestrates the generation request, handles credit reservation, APIMart submission, and restoration on failure.
- **[`api/_lib/apimart.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/apimart.js)** – Wraps the APIMart HTTP API; throws exceptions on non-successful responses to trigger the catch block.
- **[`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js)** – Provides the `adjustCredits` abstraction that calls the `grant_user_credits` RPC for atomic credit adjustments.
- **[`supabase/migrations/20260828090000_apimart_generation_tasks.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260828090000_apimart_generation_tasks.sql)** – Defines the schema for storing successful APIMart task associations and credit costs.

## Summary

- **Credits are reserved upfront** before any external API call to prevent overspending.
- **APIMart submission failures trigger immediate restoration** via the catch block in [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js).
- **The `grant_user_credits` RPC** handles atomic credit restoration through the `adjustCredits` helper in [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js).
- **Successful submissions persist task metadata** in the `apimart_generation_tasks` table, finalizing the credit transaction.
- **Users are never charged for failed submissions** because the restoration logic executes before the error response is returned.

## Frequently Asked Questions

### What happens to my credits if the APIMart API returns a 500 error?

The system catches the HTTP error in [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) and immediately invokes `adjustCredits` with a positive value to restore the deducted amount via the `grant_user_credits` RPC. You will see the credits returned to your balance within the same request lifecycle.

### Is the credit restoration process atomic with the failure detection?

Yes. While the application-level try-catch block in [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) detects the failure, the actual credit update is performed by the `grant_user_credits` Supabase RPC, which executes atomically on the database side to prevent partial state updates or race conditions.

### Where is the generation task recorded after a successful APIMart submission?

Upon successful submission, the task ID and associated metadata are inserted into the `apimart_generation_tasks` table, as defined in the migration file [`supabase/migrations/20260828090000_apimart_generation_tasks.sql`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/supabase/migrations/20260828090000_apimart_generation_tasks.sql). This record serves as the permanent receipt for the credit deduction.

### Can the credit restoration fail independently of the APIMart submission?

If the `adjustCredits` call fails—for example, due to a database connectivity issue—the error will propagate up and be logged, but the user will not be charged because the initial reservation was the only state change. However, the system would return a 500 error indicating the restoration attempt failed, requiring administrative review to ensure consistency.