# Account provisioning

If you embed Met inside your product, your customers don't have to sign up by hand: you can **create their account from your backend** and hand it over ready to use. This is the "Meteor as a service" case.

It is available to **approved Tech Partners**, with a partner API key. A workspace key cannot do it: the permissions in this guide only exist on partner keys.

## Scopes

| Scope | What it is for |
|---|---|
| `workspaces:provision` | Create a new account with its owner |
| `workspaces:recharge` | Top up an account you created |

Both are **partner-key only**, and neither works with a test key (`met_test_`): the accounts they create are real, and so are the charges.

## Create an account

```ts
import Met from '@meteor.ia/sdk';

const met = new Met(process.env.MET_PARTNER_KEY!);

const account = await met.workspaces.create({
  business_name: 'Inmobiliaria Andes',
  owner_email: 'ana@andes.co',
  owner_name: 'Ana Gómez',
  owner_phone: '+573001234567',
  country: 'CO',
});

console.log(account.id, account.operational); // 1234  false
```

```python
from meteor_ia import Met

met = Met(api_key=os.environ["MET_PARTNER_KEY"])

account = met.workspaces.create(
    business_name="Inmobiliaria Andes",
    owner_email="ana@andes.co",
    owner_name="Ana Gómez",
    owner_phone="+573001234567",
    country="CO",
)
```

The account starts on the **Tech Partner** plan: monthly, no fixed fee, Energy at a premium rate. Your customer can move up to a commercial plan whenever they want, and from then on they pay that plan's rate.

## Three things worth knowing first

### The account starts with no energy

The response carries `operational: false` and `balance_usd: 0`. **An account without energy cannot run a single Met turn**: the first message replies that there is no budget.

Energy is always paid by the account consuming it, so the next step is topping it up (below) or asking your customer to do it. Don't leave it until after the first message.

### You do not set the password

You don't send a password in the call, and there is no way to do so. Met emails the owner a link to set their own. The `owner.invitation_sent` field tells you whether that email went out; if it came back `false`, your customer can request it again from "Forgot my password".

### Retrying does not duplicate

The `Idempotency-Key` header is **required**. The SDK generates one for you if you don't pass it, but it is better to pass your own — the id of your own record, for instance: that way a network-timeout retry returns the same account instead of creating a second one.

```ts
await met.workspaces.create(data, { idempotencyKey: `signup-${myRecord.id}` });
```

## Top up energy

```ts
const payment = await met.workspaces.recharge(account.id, 50);
// payment.checkout_url → Stripe payment link
```

Topping up **does not credit the balance instantly**: it returns a `checkout_url`, and the energy lands when the payment completes. The minimum is USD 5.

It only works on accounts you created. Someone else's account returns `403`.

## Quotas

Each partner tier has a **monthly** quota of new accounts:

| Tier | Accounts per month |
|---|---|
| Bronze | 100 |
| Silver | 300 |
| Gold | 1000 |

Once it runs out, creation returns `403` with the quota, how much you have used and when it resets. The counter goes back to zero on the first day of each month.

## Errors

| Code | What happened |
|---|---|
| `403 scope_not_allowed_for_owner` | You are using a workspace key; this needs a partner key |
| `403 test_mode_restricted` | You are using a `met_test_` key; these operations are real |
| `403` with a capability message | Your partner account does not have the Tech Partner capability approved |
| `403` with a quota message | You ran out of quota for the month |
| `400` | The `Idempotency-Key` header is missing, or some owner detail is invalid |

For the full detail on retries and idempotency, see [Errors and idempotency](errors-and-idempotency.html).
