# Creates a new credit bundle or plan for an environment

`POST /api/configuration/credits`

- **Products:** Gladstone Admin Areas (`ADMIN`)
- **Features:** not restricted by feature

HTML version: [Creates a new credit bundle or plan for an environment](https://support.gladstonesoftware.cloud/reference/configuration/creates-a-new-credit-bundle-or-plan-for-an-environment)

## Overview

Grants an environment a pool of email and SMS credits, which are then drawn down as messages are sent. `planId` decides which of two quite different things happens:

- **`planId` above 0 — a recurring plan.** The plan is recorded as the environment's active plan, and its credits are added to the environment. An environment may hold only one active recurring plan; a second attempt is rejected with `400`.
- **`planId` of 0, or omitted — a one-off bundle.** No active plan is recorded; the credits are simply added to the environment. Because no plan is recorded, one-off bundles do not collide with each other or with a recurring plan, and you can add as many as you like.

Valid `planId` values come from `GET /api/configuration/default-communication-plans`; what an environment currently holds comes from `GET /api/configuration/communication-plans/{environmentId}`.

A successful call returns `200 OK` with an **empty body** — not `201`, and with no identifier for what it created. The credits are applied asynchronously after the response has been sent, so a `200` means "accepted", not "the balance has changed". Read the balance back from `GET /api/configuration/communication-plans/{environmentId}`.

Validation runs in a fixed order — environment, then dates, then plan and credits, then the active-plan check — and stops at the first failure, so fix the errors in that order.

## Endpoint

`POST {base_url}/api/configuration/credits`

`{base_url}` is the environment URL issued to your integration. See [Authenticating with Gladstone APIs](../../guides/authenticating-with-gladstone-apis.md).

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | integer (int32) | No | Ignored on create. The field exists because `PUT /api/configuration/credits` takes the same body, where it identifies the plan being amended. Whatever you send here is discarded, and the id assigned is not returned. |
| `tenantId` | string | Yes | The tenant that owns the environment, as a GUID. It is trimmed before use, and must parse as a GUID — anything else is rejected with `TenantId '{value}' is not a valid GUID.` and a blank or whitespace-only value with `TenantId was unexpectedly blank or null.` Omitting the field entirely, or sending null, is worse than sending a blank string: you get a `500` rather than a `400`. Maximum 40 characters. |
| `environmentId` | integer (int32) | Yes | The environment the credits are granted to. Must be above 0 (`EnvironmentId must be an integer above 0.`) and must already exist (`EnvironmentId {id} does not exist.`). |
| `planId` | integer (int32) | No | Which default communication plan this grant is based on. Take the value from `GET /api/configuration/default-communication-plans`; a value that does not match one is rejected with `PlanId {id} does not exist.` and a negative value with `PlanId must be a positive integer.` Send `0`, or omit the field, to create a one-off bundle instead of a recurring plan — the field is not nullable, so omitting it is the same as sending `0`. Any value above 0 is treated as a recurring plan and is subject to the one-active-plan-per-environment rule. |
| `isActive` | boolean | No | Ignored on create. The plan is always created as active regardless of what you send. To retire a plan, use `PUT /api/configuration/credits`. |
| `includedEmails` | integer (int32) | No | The number of email credits this grant adds. Omit it, or send null, to grant no email credits — but at least one of `includedEmails` and `includedSMS` must be 1 or more, or the request is rejected with `Plan cannot include 0 credits. At least 1 credit must be included for Email or SMS.` A negative value in only one of the two fields is currently accepted rather than rejected, so validate signs yourself. |
| `includedSMS` | integer (int32) | No | The number of SMS credits this grant adds. Behaves exactly as `includedEmails`, and is subject to the same combined rule and the same acceptance of a negative value — the pair is only rejected when both values are absent or 0 or below. |
| `startDate` | string (date-time) | Yes | When the credits become available. It must be supplied (`StartDate must be specified and cannot be blank.`) even though the field is nullable. Only the date part is kept; the time is discarded. A start date in the past is accepted. |
| `expiryDate` | string (date-time) | No | When the credits lapse. Only the date part is kept. It must not be earlier than today (`ExpiryDate cannot be in the past.`) nor earlier than `startDate` (`ExpiryDate cannot be before the StartDate.`). Omit it, or send null, and it defaults to `startDate` plus 12 months — it does not mean "never expires". |

## Sample request

```bash title="cURL"
curl -X POST '{base_url}/api/configuration/credits' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "id": 12345,
  "tenantId": "string",
  "environmentId": 12345,
  "planId": 12345,
  "isActive": true,
  "includedEmails": 1,
  "includedSMS": 1,
  "startDate": "2026-08-14T19:00:00Z",
  "expiryDate": "2026-08-14T19:00:00Z"
}'
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | The environment is wrong: `EnvironmentId must be an integer above 0.` for a value of 0 or below, or `EnvironmentId {id} does not exist.` when no such environment is registered. |
| `400` | Bad request | `tenantId` is blank or whitespace (`TenantId was unexpectedly blank or null.`), or is not a GUID (`TenantId '{value}' is not a valid GUID.`). |
| `400` | Bad request | The dates do not hang together: `StartDate must be specified and cannot be blank.`, `ExpiryDate cannot be in the past.`, or `ExpiryDate cannot be before the StartDate.` |
| `400` | Bad request | `planId` is negative (`PlanId must be a positive integer.`) or names a default plan that does not exist (`PlanId {id} does not exist.`). |
| `400` | Bad request | Neither `includedEmails` nor `includedSMS` carries a positive value — `Plan cannot include 0 credits. At least 1 credit must be included for Email or SMS.` |
| `400` | Bad request | You sent a recurring plan (`planId` above 0) for an environment that already holds one — `EnvironmentId {id} already has an active credit plan.` One-off bundles (`planId` of 0) are not subject to this rule and remain accepted. |
| `400` | Bad request | The whole body was sent as `null` — `Add credits request cannot be null.` |
| `500` | Internal server error | `tenantId` was omitted or sent as `null`. A missing field fails with an unexpected server-side error rather than the `400` you would expect. Send an empty string if you want the validation message instead. |
| `500` | Internal server error | The environment could not be resolved when applying the credits, or the credits could not be queued for processing. For a recurring plan the active plan may already have been recorded before this point, so re-check with `GET /api/configuration/communication-plans/{environmentId}` before retrying. |
