---
title: "Charge a meter — Anis Developers"
description: "Buy a meter charge with an operation id you save before sending. A 202 means the charge is accepted or its outcome is still being checked."
url: https://developers.anis.ly/reference/create-meter-charge/
language: en
---

> Every page of this documentation: https://developers.anis.ly/llms.txt

[API reference](https://developers.anis.ly/reference.md) · Meter charges

# Charge a meter

`POST /v1/wallets/{walletId}/meter-charges`

Buy a meter charge with an operation id you save before sending. A 202 means the charge is accepted or its outcome is still being checked.

- **Permission:** `meter_charges:create`
- **Authentication:** Signed purchase
- **Anis’s answer:** Signed
- **Staff-set limits it counts toward:** All requests, Purchases (orders limit)
- **.NET SDK:** `anis.MeterCharges.CreateAsync(walletId, operationId, request)`

- Every processing `202` contains exactly `operationId`, `operationType` and `status: "processing"`; `operationType` is `meterCharge`. Full operation reads use `200`.
- A missing operation read never proves absence. Retry the exact saved body with the same operation id and a fresh signature. A duplicate remains `202` during projection lag. Only a duplicate command on this retry, at or after 60 seconds since original admission, followed by an application-scoped read still not found, closes the operation with `idempotency_conflict` (`409`). A read miss or timeout alone never proves a conflict. That code does not prove nothing was charged: the first request may already have been accepted, so read the operation before any new attempt.
- This purchase counts toward the existing `orders` limit and the same daily application spending cap as card orders and other purchases.

## Parameters

| Name | In | Type | Notes |
| --- | --- | --- | --- |
| `walletId` (required) | `path` | UUID | A UUID, lower-case with hyphens. |

## Request

Signed with your key, with a one-time nonce, a digest of the body and your operation id as `Idempotency-Key`.

Headers: `Signature-Input`, `Signature`, `Content-Digest`, `Nonce`, `Idempotency-Key`, `X-Anis-Date`, `Accept-Language` (optional). The SDKs set all of them for you.

**Body:** [CreateMeterChargeRequest](#type-createmeterchargerequest), as JSON.

| Field | Type | Notes |
| --- | --- | --- |
| `packageId` (required) | UUID | The selected package's id from the package list. |
| `meterNumber` (required) | string | The meter number as text; preserve leading zeros. |
| `expectedTotal` (required) | any | The total you confirmed from the package or quote, as LYD Money. |
| `externalReference` | string | Your reference, included when supplied. |

## Responses

| Status | Meaning | Body |
| --- | --- | --- |
| 200 | Success. | [MeterCharge](#type-metercharge) |
| 202 | Accepted — no outcome yet. | [MeterChargeAccepted](#type-meterchargeaccepted) |
| 400 | Refused: the signed request is badly built. | [Problem](#refusals) |
| 401 | Refused: not authenticated. | [Problem](#refusals) |
| 403 | Refused: not allowed. | [Problem](#refusals) |
| 404 | Refused: not found, or not yours. | [Problem](#refusals) |
| 409 | Refused: conflicts with the current state. | [Problem](#refusals) |
| 422 | Refused: the request breaks a rule. | [Problem](#refusals) |
| 429 | Refused: a limit was reached. | [Problem](#refusals) |
| 503 | No decision: a dependency was unavailable. | [Problem](#refusals) |

Every answer of this call is signed by Anis — success and every refusal. Require the signature and verify it before you act on the answer; an answer without one is a failure, never an answer ([how](https://developers.anis.ly/docs/verifying-answers.md)).

## Refusals

Every refusal of this call is a signed problem. Branch on its `code`; each links to what it means and what to do.

| Error | Code | Status |
| --- | --- | --- |
| [Invalid credentials](https://developers.anis.ly/errors/invalid-credentials.md) | `invalid_credentials` | 401 |
| [Malformed signed request](https://developers.anis.ly/errors/malformed-signed-request.md) | `malformed_signed_request` | 400 |
| [Insufficient scope](https://developers.anis.ly/errors/insufficient-scope.md) | `insufficient_scope` | 403 |
| [Source address not allowed](https://developers.anis.ly/errors/source-ip-not-allowed.md) | `source_ip_not_allowed` | 403 |
| [Rate limited](https://developers.anis.ly/errors/rate-limited.md) | `rate_limited` | 429 |
| [Validation failed](https://developers.anis.ly/errors/validation-failed.md) | `validation_failed` | 422 |
| [Service unavailable](https://developers.anis.ly/errors/dependency-unavailable.md) | `dependency_unavailable` | 503 |
| [Request timeout](https://developers.anis.ly/errors/request-timeout.md) | `request_timeout` | 504 |
| [Internal error](https://developers.anis.ly/errors/internal-error.md) | `internal_error` | 500 |
| [Account not authorised](https://developers.anis.ly/errors/binding-not-authorized.md) | `binding_not_authorized` | 403 |
| [Account inactive](https://developers.anis.ly/errors/account-inactive.md) | `account_inactive` | 403 |
| [Wallet not granted](https://developers.anis.ly/errors/wallet-not-granted.md) | `wallet_not_granted` | 404 |
| [Not found](https://developers.anis.ly/errors/resource-not-found.md) | `resource_not_found` | 404 |
| [Currency not supported](https://developers.anis.ly/errors/currency-not-supported.md) | `currency_not_supported` | 422 |
| [Wallet disabled](https://developers.anis.ly/errors/wallet-disabled.md) | `wallet_disabled` | 409 |
| [Wallet expired](https://developers.anis.ly/errors/wallet-expired.md) | `wallet_expired` | 409 |
| [Business subscription required](https://developers.anis.ly/errors/business-subscription-required.md) | `business_subscription_required` | 409 |
| [Replay detected](https://developers.anis.ly/errors/replay-detected.md) | `replay_detected` | 409 |
| [Operation id already used](https://developers.anis.ly/errors/idempotency-conflict.md) | `idempotency_conflict` | 409 |
| [Price changed](https://developers.anis.ly/errors/price-changed.md) | `price_changed` | 409 |
| [Insufficient balance](https://developers.anis.ly/errors/insufficient-balance.md) | `insufficient_balance` | 409 |
| [Spending cap reached](https://developers.anis.ly/errors/spending-limit-exceeded.md) | `spending_limit_exceeded` | 429 |
| [Meter refused](https://developers.anis.ly/errors/meter-rejected.md) | `meter_rejected` | 422 |
| [Package unavailable](https://developers.anis.ly/errors/package-unavailable.md) | `package_unavailable` | 409 |

## Types

### CreateMeterChargeRequest

| Field | Type | Notes |
| --- | --- | --- |
| `packageId` (required) | UUID | The selected package's id from the package list. |
| `meterNumber` (required) | string | The meter number as text; preserve leading zeros. |
| `expectedTotal` (required) | any | The total you confirmed from the package or quote, as LYD Money. |
| `externalReference` | string | Your reference, included when supplied. |

### MeterCharge

| Field | Type | Notes |
| --- | --- | --- |
| `operationId` (required) | UUID | The same UUID sent as Idempotency-Key for this purchase. |
| `status` (required) | [MeterChargeStatus](#type-meterchargestatus) | processing, succeeded or failed. A failed read still needs refund.status to explain the money outcome. |
| `walletId` (required) | string | The wallet used for this purchase. |
| `meterNumber` (required) | string | The meter number as text; preserve leading zeros. |
| `package` (required) | [MeterChargePackage](#type-meterchargepackage) | The package recorded for this charge. |
| `total` (required) | [Money](#type-money) | The frozen total wallet cost in every state, as LYD Money. |
| `personalPrice` (required) | [Money](#type-money) | The frozen retail display price in every state; do not substitute it for the payable total. |
| `externalReference` | string | Your reference, included when supplied. |
| `createdAt` (required) | string (date-time) | When the charge was recorded, in UTC. |
| `completedAt` | string (date-time) | When the charge succeeded; omitted in processing and failed states. |
| `receipt` | [MeterReceipt](#type-meterreceipt) | Present after successful charging; includes the full token list. |
| `failure` | [MeterFailure](#type-meterfailure) | The charge failure and localized display message; present for a failed charge. |
| `refund` | [MeterRefund](#type-meterrefund) | For a failed charge, whether money returned, was not taken or is still pending. |

### MeterChargeStatus

### MeterChargePackage

| Field | Type | Notes |
| --- | --- | --- |
| `id` (required) | UUID | The meter package identifier. |
| `name` (required) | string | One stored package name, not a bilingual text object. |
| `gecolPackageName` (required) | string | The electricity supplier's package name. |

### Money

| Field | Type | Notes |
| --- | --- | --- |
| `amount` (required) | string | A decimal string, never a JSON number. Wallet balances may be negative while allowed debt is used. Prices and totals follow each route's amount rules. |
| `currency` (required) | string | An uppercase three-letter currency code, such as `LYD`. Read a wallet’s currency from `balance.currency`. |
| `asOf` | string (date-time) | When this price or balance was read. |

### MeterReceipt

| Field | Type | Notes |
| --- | --- | --- |
| `receiptNumber` | string | The receipt number supplied by the electricity supplier. |
| `creditedAmount` | string | The supplier's credited amount string, passed through unchanged; not the wallet total. |
| `tokens` (required) | list of [MeterToken](#type-metertoken) | Every supplier token in sequence order, including key changes before credit. |
| `taxes` (required) | list of [MeterTax](#type-metertax) | The supplier receipt's tax lines. |

### MeterToken

| Field | Type | Notes |
| --- | --- | --- |
| `sequence` (required) | integer | Supplier token order; preserve gaps rather than renumbering. |
| `label` (required) | string | The supplier's token label. |
| `code` (required) | string | The complete token string, including spaces and leading zeros. |
| `description` | string | The token's display description when supplied. |

### MeterTax

| Field | Type | Notes |
| --- | --- | --- |
| `description` (required) | string | The electricity company's original Arabic tax description, unchanged. |
| `amount` (required) | string | The original supplier amount string; no Money-scale conversion. |

### MeterFailure

| Field | Type | Notes |
| --- | --- | --- |
| `code` (required) | string | A charge-read failure value, not an HTTP problem code. Values: `meter_number_invalid`, `meter_not_whitelisted`, `meter_not_linked`, `meter_removed`, `meter_inactive`, `meter_account_blocked`, `meter_data_incomplete`, `meter_debt_exceeds_package`, `package_unavailable`, `package_limit_reached`, `token_not_written`, `insufficient_balance`, `gecol_unavailable`, `charge_failed` |
| `message` | [LocalizedText](#type-localizedtext) | Arabic and English messages matching the charging result. |

### LocalizedText

| Field | Type | Notes |
| --- | --- | --- |
| `ar` | string | The Arabic text; omitted when empty. |
| `en` | string | The English text; omitted when empty. |

### MeterRefund

| Field | Type | Notes |
| --- | --- | --- |
| `status` (required) | [MeterRefundStatus](#type-meterrefundstatus) | refunded means returned; notCharged means nothing taken; pending means money has not returned yet. |
| `amount` | any | The refund Money value when present; never infer settlement from this amount alone. |

### MeterRefundStatus

### MeterChargeAccepted

| Field | Type | Notes |
| --- | --- | --- |
| `operationId` (required) | UUID | The same UUID sent as Idempotency-Key for this purchase. |
| `operationType` (required) | string | Always meterCharge. Values: `meterCharge` |
| `status` (required) | string | Always processing; the outcome is not final. Values: `processing` |
