# API Access

:::note{title="Beta"}

API Monetization is in beta and free to try. The APIs are stable but should be
evaluated in non-production environments first. To go to production, contact
[sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
announced.

:::

## Buckets

Each Zuplo project includes three isolated buckets that mirror your
[environment structure](../environments.mdx):

| Bucket           | Purpose                                                       |
| ---------------- | ------------------------------------------------------------- |
| **Working Copy** | Your development sandbox for building and testing             |
| **Preview**      | Staging environments for validating changes before production |
| **Production**   | Your live environment serving real customers                  |

Meters, features, plans, and subscriptions are all scoped to a specific bucket.
This isolation enables independent development workflows where you can:

- **Experiment freely** - Test new pricing models or usage tracking in
  development without affecting production data
- **Validate changes** - Promote your product catalog configuration through
  preview environments before going live
- **Maintain separation** - Keep development test data completely isolated from
  production customer usage

When you're satisfied with your configuration in one bucket, you can recreate
that same configuration in another bucket to promote changes through your
deployment pipeline.

## Authentication

All Monetization API requests require authentication using a Zuplo API key.

All examples in this documentation assume the following environment variables
are set in your terminal:

```bash
# Your Bucket ID (could be working-copy, preview, or production)
# (Found in Project Services > Bucket Details — https://portal.zuplo.com/+/account/project/services)
export BUCKET_ID=your-bucket-id
# Your Zuplo API Key (Found in Account Settings > Zuplo API Keys —
# https://portal.zuplo.com/+/account/settings/api-keys)
export ZAPI_KEY=zpka_YOUR_API_KEY
```

Include your API key in the `Authorization` header:

```shell
curl \
  https://dev.zuplo.com/v3/metering/$BUCKET_ID/meters \
  --header "Authorization: Bearer $ZAPI_KEY"
```

## Bucket monetization configuration

Each bucket has an optional `MonetizationConfiguration` record that holds
bucket-wide defaults. The configuration is read by the runtime and the Developer
Portal — it is not stored in OpenMeter.

| Method   | Path                                                 |
| -------- | ---------------------------------------------------- |
| `GET`    | `/v3/metering/{bucketId}/monetization-configuration` |
| `PUT`    | `/v3/metering/{bucketId}/monetization-configuration` |
| `DELETE` | `/v3/metering/{bucketId}/monetization-configuration` |

The `PUT` endpoint upserts the record. At least one of the four fields below
must be present. Pass any combination — fields that are omitted retain their
previous value.

| Field                          | Type               | Description                                                                                                                                                                                                                                                                                                                                                    |
| ------------------------------ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `multipleSubscriptionsEnabled` | `boolean`          | Stored on the bucket. Reserved for future enforcement of multi-subscription rules; today the Developer Portal create-subscription path enforces a single active subscription per customer regardless of this flag.                                                                                                                                             |
| `planOrder`                    | `string[]`         | Plan keys in display order. Drives the pricing page sort and is used by [plan changes](./subscription-lifecycle.md#plan-changes-upgrades-and-downgrades) to decide upgrade vs downgrade — moving to a plan with a higher (or equal) index is treated as an upgrade with `"immediate"` timing; a lower index is a downgrade with `"next_billing_cycle"` timing. |
| `planSettings`                 | `object`           | Per-plan overrides keyed by plan key. The supported sub-key today is `visiblePhases` — an array of phase keys that should appear on the pricing page. Omitted means no filtering; `[]` hides all phases for that plan.                                                                                                                                         |
| `maxPaymentOverdueDays`        | `integer` (`>= 0`) | Bucket-level grace period for overdue payments. Used as the lowest-priority value in the resolution chain: customer metadata → plan metadata → this bucket value → built-in default of `3` days. See [Subscription and payment validation](./monetization-policy.md#subscription-and-payment-validation).                                                      |

```bash
curl -X PUT "https://dev.zuplo.com/v3/metering/$BUCKET_ID/monetization-configuration" \
  --header "Authorization: Bearer $ZAPI_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "planOrder": ["free", "developer", "pro"],
    "planSettings": {
      "pro": { "visiblePhases": ["default"] }
    },
    "maxPaymentOverdueDays": 7
  }'
```

`DELETE` removes the record entirely; `GET` on a bucket with no record returns
the schema defaults (`multipleSubscriptionsEnabled: false`, `planOrder: []`,
`planSettings: {}`, `maxPaymentOverdueDays: 3`).

## Stripe setup and billing readiness

These endpoints script the Stripe integration that the
[Monetization Service UI](./stripe-integration.md#connecting-your-stripe-account)
runs interactively. They live on the Zuplo developer API (not OpenMeter), so the
request shape is documented here.

### Connect a Stripe app

```http
POST /v3/metering/{bucketId}/setup/stripe
```

Installs a Stripe app on the bucket and creates the default billing profile
linked to that app.

| Field         | Type      | Description                                                                                      |
| ------------- | --------- | ------------------------------------------------------------------------------------------------ |
| `apiKey`      | `string`  | Stripe secret or restricted key. Required.                                                       |
| `name`        | `string`  | Display name for the app. Required.                                                              |
| `taxEnabled`  | `boolean` | Initial value for `workflow.tax.enabled` on the billing profile. Optional; defaults to `false`.  |
| `taxEnforced` | `boolean` | Initial value for `workflow.tax.enforced` on the billing profile. Optional; defaults to `false`. |
| `country`     | `string`  | ISO 3166-1 alpha-2 supplier country for the billing profile. Optional; defaults to `"US"`.       |

The request fails if the key prefix does not match the bucket environment:

- Working-copy or preview buckets accept `sk_test_*` or `rk_test_*`.
- Production buckets accept `sk_live_*` or `rk_live_*`.

```bash
curl -X POST "https://dev.zuplo.com/v3/metering/$BUCKET_ID/setup/stripe" \
  --header "Authorization: Bearer $ZAPI_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "apiKey": "rk_test_...",
    "name": "Zuplo Monetization (test)",
    "taxEnabled": false,
    "country": "US"
  }'
```

### Read the connected Stripe app

```http
GET /v3/metering/{bucketId}/setup/stripe
```

Returns a summary of the connected Stripe app, the matched billing profile, and
connection-test status. Use this to confirm the integration is wired up before
continuing.

### Add a billing profile to a Stripe app

```http
POST /v3/metering/{bucketId}/setup/stripe/{stripeAppId}/billing-profile
```

Creates an additional billing profile against an already-installed Stripe app.
This is rarely needed — the default profile is created during initial setup. Use
this endpoint to create per-supplier-country profiles.

### Check billing readiness

```http
GET /v3/metering/{bucketId}/billing-readiness
```

Returns:

```json
{
  "hasStripeApp": true,
  "stripeAppId": "app_01H...",
  "hasDefaultBillingProfile": true,
  "defaultBillingProfileId": "bp_01H..."
}
```

Use this in setup wizards to gate the UI on whether Stripe is connected.

### Update an app

```http
PUT /v3/metering/{bucketId}/apps/{appId}
```

Replaces an app's configuration (name, description, metadata, and — for Stripe
apps — `secretAPIKey`). The same key-prefix validation as `POST /setup/stripe`
applies: a Stripe key must match the bucket environment.

## API Reference

For complete API operations, see the API Reference documentation:

- [Meters API](../../api/metering-meters)
- [Features API](../../api/metering-features)
- [Plans API](../../api/metering-plans)
