# API keys and scopes
Source: https://docs.meum.io/api-reference/api-keys-and-scopes
Bearer authentication and scopes for Public Merchant API v1.
## Authentication
```
Authorization: Bearer sk_live_...
```
* Store-scoped: one store per key
* Hashed at rest (SHA-256); prefix `sk_live_` with first 12 chars shown in dashboard
* Cannot access Merchant Admin session APIs
Create keys in [Get API credentials](/getting-started/get-api-credentials).
## Default developer scopes
| Scope | Access |
| -------------------------------------------- | ---------------------------------- |
| `invoices:read` | List and read invoices |
| `invoices:write` | Create and cancel invoices |
| `transactions:read` | Read on-chain payment transactions |
| `payment_links:read` / `payment_links:write` | Payment links |
| `webhooks:read` / `webhooks:write` | Webhook endpoints and deliveries |
Use `transactions:read` (not legacy `payments:read`).
## WooCommerce keys
| Key | Scopes | Use |
| --------- | ---------------------------------------------- | ---------------------------- |
| Bootstrap | `woocommerce:bootstrap` | Connect only (24h) |
| Dedicated | `invoices:create`, `invoices:read`, Woo scopes | Plugin runtime (auto-issued) |
Dedicated keys cannot access payment links, transaction list, or developer webhook management.
## Scope errors
HTTP `403`:
```json theme={null}
{
"error": {
"type": "permission_error",
"code": "INSUFFICIENT_SCOPE",
"message": "Missing transactions:read scope"
}
}
```
## Related pages
* [API key security](/security/api-key-security)
* [Authentication errors](/api-reference/errors)
# Customers
Source: https://docs.meum.io/api-reference/customers
Customer domain status for Public Merchant API v1.
## Public Customer API (not available)
Meum does **not** expose `/v1/customers` in Public Merchant API v1.
### What to use instead
* Pass customer context in invoice `metadata` or Woo `external_order_id`.
* Use **Merchant Admin** for wallet-based customer analytics (dashboard session only).
### Planned domain (not in v1)
A future Customer API may support store-scoped external customer IDs, separate from payer wallet addresses.
# Errors
Source: https://docs.meum.io/api-reference/errors
HTTP error codes and error response format.
## Error response format
```json theme={null}
{
"error": "Human-readable message",
"code": "MACHINE_READABLE_CODE"
}
```
The `code` field is present for structured errors but may be omitted for simple validation failures.
## Common HTTP status codes
| Status | Meaning |
| ------ | --------------------------------------------------------- |
| 400 | Validation error, missing payout wallet, bad request body |
| 401 | Missing or invalid API key |
| 403 | Insufficient scope or store mismatch |
| 404 | Resource not found |
| 409 | External order ID conflict |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
## Error codes
| Code | Description |
| ------------------------------------- | ------------------------------------------ |
| `BOOTSTRAP_KEY_INVOICE_FORBIDDEN` | Connection key used for invoice creation |
| `EXTERNAL_ORDER_INTEGRATION_CONFLICT` | Order ID belongs to another integration |
| `INSUFFICIENT_SCOPE` | API key lacks required scope |
| `SITE_ALREADY_CONNECTED` | Woo site bound to another store |
| `INTEGRATION_NOT_FOUND` | Woo integration not found on disconnect |
| `CURRENCY_NOT_ALLOWED` | Invoice currency not in merchant allowlist |
## Related pages
* [Common API errors](/troubleshooting/common-api-errors)
# Health check
Source: https://docs.meum.io/api-reference/health/health-check
/openapi.yaml get /health
# Idempotency
Source: https://docs.meum.io/api-reference/idempotency
Idempotent invoice creation behavior.
## Invoice creation
`POST /v1/invoices` is idempotent on `(store_id, external_order_id)`:
* Existing match → returns the same invoice with HTTP `201`
* Same `external_order_id` on a **different** Woo integration → HTTP `409` (`EXTERNAL_ORDER_INTEGRATION_CONFLICT`)
## Webhook deliveries
Dedupe on `X-Meum-Event-Id`. See [Webhooks overview](/webhooks/overview).
# Connect WooCommerce
Source: https://docs.meum.io/api-reference/integrations/connect-woocommerce
/openapi.yaml post /v1/integration/woocommerce/connect
Registers or reconnects a WooCommerce store. Returns a dedicated API key and
webhook secret. Uses legacy error shape on some failures.
# Disconnect WooCommerce
Source: https://docs.meum.io/api-reference/integrations/disconnect-woocommerce
/openapi.yaml post /v1/integration/woocommerce/disconnect
Requires a WooCommerce dedicated API key.
# Get WooCommerce integration status
Source: https://docs.meum.io/api-reference/integrations/get-woocommerce-integration-status
/openapi.yaml get /v1/integration/woocommerce/status
# Overview
Source: https://docs.meum.io/api-reference/invoices
Create, list, retrieve, poll status, and cancel invoices via Public Merchant API v1.
All invoice IDs use opaque `inv_` tokens. Internal UUIDs are never returned.
## Authentication
```
Authorization: Bearer sk_live_...
```
## Create invoice
`POST /v1/invoices`
| | |
| --------------- | --------------------------- |
| **Scope** | `invoices:write` |
| **Idempotency** | Not supported on this route |
| **Rate limit** | Write bucket (`enforce`) |
### Request body
| Field | Required | Validation |
| ------------------- | -------- | ------------------------------------------------- |
| `amount` | Yes | Decimal string, settlement amount |
| `currency` | Yes | ISO currency code |
| `external_order_id` | No | Merchant reference |
| `callback_url` | No | HTTPS webhook target (developer keys) |
| `return_url` | No | Buyer redirect after payment |
| `metadata` | No | JSON object; sensitive keys stripped in responses |
### Response `201`
Returns `id` (`inv_...`), `status`, `checkout_url`, `amount`, `currency`, `output_asset`, `expires_at`.
### Errors
| Code | HTTP | When |
| ------------------------------ | ---- | ----------------------------- |
| `INSUFFICIENT_SCOPE` | 403 | Missing `invoices:write` |
| `payout_wallet_not_configured` | 400 | Store payout not set |
| `store_mismatch` | 403 | `store_id` does not match key |
### Webhooks
`invoice.created` when the invoice is persisted.
### Examples
```bash theme={null}
curl -X POST https://api.meum.io/v1/invoices \
-H "Authorization: Bearer sk_live_EXAMPLE" \
-H "Content-Type: application/json" \
-d '{"amount":"99.00","currency":"USD","external_order_id":"order-1001"}'
```
```javascript theme={null}
const res = await fetch("https://api.meum.io/v1/invoices", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ amount: "99.00", currency: "USD" }),
});
```
```php theme={null}
$ch = curl_init("https://api.meum.io/v1/invoices");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer sk_live_EXAMPLE",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["amount" => "99.00", "currency" => "USD"]),
CURLOPT_RETURNTRANSFER => true,
]);
```
### Security
Never log full API keys. `checkout_url` is buyer-facing; do not embed secrets in metadata.
***
## List invoices
`GET /v1/invoices`
| | |
| -------------- | --------------------------------------------------- |
| **Scope** | `invoices:read` |
| **Pagination** | Cursor (`limit`, `starting_after`, `ending_before`) |
| **Rate limit** | Read bucket (`observe`) |
Query: `status`, `external_order_id`, `payment_link_id` (`plink_...`).
***
## Retrieve invoice
`GET /v1/invoices/{id}`
| | |
| ------------- | ---------------------- |
| **Scope** | `invoices:read` |
| **Path `id`** | `inv_...` public token |
Response uses snake\_case. Money fields are strings.
***
## Poll status
`GET /v1/invoices/{id}/status`
Lightweight status for hosted checkout polling. May include `deposit_address`, `swap_status`, and `return_url` when applicable.
***
## Cancel invoice
`POST /v1/invoices/{id}/cancel`
| | |
| --------- | ---------------- |
| **Scope** | `invoices:write` |
Only open invoices (`awaiting_payment`, `quoted`, etc.) can be cancelled. Emits `invoice.cancelled` webhook.
# Cancel invoice
Source: https://docs.meum.io/api-reference/invoices/cancel-invoice
/openapi.yaml post /v1/invoices/{id}/cancel
Cancels an open invoice. Not available for WooCommerce dedicated keys.
# Create invoice
Source: https://docs.meum.io/api-reference/invoices/create-invoice
/openapi.yaml post /v1/invoices
Creates a new checkout invoice for the authenticated store.
Returns a legacy error shape on some validation failures for backward compatibility.
# Get invoice
Source: https://docs.meum.io/api-reference/invoices/get-invoice
/openapi.yaml get /v1/invoices/{id}
# Get invoice status
Source: https://docs.meum.io/api-reference/invoices/get-invoice-status
/openapi.yaml get /v1/invoices/{id}/status
Lightweight status poll including deposit details and swap processing state.
# List invoice transactions
Source: https://docs.meum.io/api-reference/invoices/list-invoice-transactions
/openapi.yaml get /v1/invoices/{id}/transactions
# List invoices
Source: https://docs.meum.io/api-reference/invoices/list-invoices
/openapi.yaml get /v1/invoices
Returns invoices for the authenticated store with cursor pagination.
Results are ordered by creation time descending (newest first).
Date filters default to a 90-day window when not specified.
# API overview
Source: https://docs.meum.io/api-reference/overview
Public Meum Merchant API v1. Integrate without the Dashboard.
## Base URL
```
https://api.meum.io
```
## Authentication
Store-scoped API key: `Authorization: Bearer sk_live_...`
See [API keys and scopes](/api-reference/api-keys-and-scopes).
List endpoints use cursor pagination (`cursor`, `limit`). See OpenAPI per route.
## Public resource IDs
Merchant API responses use prefixed opaque IDs, never internal UUIDs:
| Prefix | Resource |
| ----------------------- | -------------------------------------- |
| `inv_` | Invoice |
| `txn_` | Payment transaction |
| `plink_` | Payment link (merchant API) |
| `plpub_` | Payment link buyer URL / public routes |
| `wh_` / `whd_` / `evt_` | Webhook endpoint / delivery / event |
| `int_` | Integration |
Tokens are **32 lowercase hex characters** after the prefix (128-bit). See [Payment Links API](/api-reference/payment-links) for `plink_` vs `plpub_`.
## Domains
| Domain | Prefix | Description |
| ------------- | ----------------------------- | --------------------------------------- |
| Invoices | `/v1/invoices` | Create, list, read, cancel, poll status |
| Transactions | `/v1/transactions` | Read-only on-chain payment ledger |
| Payment Links | `/v1/payment-links` | Create and manage pay links (API key) |
| Webhooks | `/v1/webhook-endpoints` | Developer webhook endpoint management |
| Integrations | `/v1/integration/woocommerce` | WooCommerce connect, disconnect, status |
## Public merchant endpoints (summary)
| Method | Path | Scope |
| --------------------- | ---------------------------------------- | ------------------------ |
| GET | `/health` | None |
| GET | `/v1/invoices` | `invoices:read` |
| POST | `/v1/invoices` | `invoices:write` |
| GET | `/v1/invoices/{id}` | `invoices:read` |
| GET | `/v1/invoices/{id}/status` | `invoices:read` |
| POST | `/v1/invoices/{id}/cancel` | `invoices:write` |
| GET | `/v1/invoices/{id}/transactions` | `transactions:read` |
| GET | `/v1/transactions` | `transactions:read` |
| GET | `/v1/transactions/{id}` | `transactions:read` |
| GET | `/v1/transactions/by-hash/{hash}` | `transactions:read` |
| POST | `/v1/payment-links` | `payment_links:write` |
| GET | `/v1/payment-links` | `payment_links:read` |
| GET/PATCH | `/v1/payment-links/{id}` | read/write |
| POST | `/v1/payment-links/{id}/activate` | `payment_links:write` |
| POST | `/v1/payment-links/{id}/deactivate` | `payment_links:write` |
| POST | `/v1/integration/woocommerce/connect` | `woocommerce:connect` |
| POST | `/v1/integration/woocommerce/disconnect` | `woocommerce:disconnect` |
| GET | `/v1/integration/woocommerce/status` | API key (store) |
| POST/GET/PATCH/DELETE | `/v1/webhook-endpoints` | `webhooks:*` |
Full schemas: OpenAPI reference generated from `openapi.yaml`.
## Browser-facing (not API key management)
These routes are for checkout UIs, not server integration:
* `/v1/checkout/*`: Hosted checkout session
* `/v1/public/payment-links/*`: Buyer pay-link page and checkout
## Not in public API
* Merchant Admin session APIs (JWT login at app.meum.io)
* `/v1/customers`: **Not available** (see [Customers](/api-reference/customers))
## Examples
### List invoices (cURL)
```bash theme={null}
curl "https://api.meum.io/v1/invoices?status=paid&limit=20" \
-H "Authorization: Bearer sk_live_EXAMPLE_DO_NOT_USE"
```
### Create payment link with idempotency (Node.js)
```javascript theme={null}
const response = await fetch("https://api.meum.io/v1/payment-links", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_EXAMPLE_DO_NOT_USE",
"Content-Type": "application/json",
"Idempotency-Key": "plink-create-order-1048-v1",
},
body: JSON.stringify({
title: "Consulting fee",
amount_mode: "fixed_amount",
amount: "250.00",
allow_multiple_payments: false,
}),
});
```
### WooCommerce status (PHP)
```php theme={null}
$response = wp_remote_get('https://api.meum.io/v1/integration/woocommerce/status', [
'headers' => ['Authorization' => 'Bearer ' . $api_key],
'timeout' => 15,
]);
$status = json_decode(wp_remote_retrieve_body($response), true);
```
# Overview
Source: https://docs.meum.io/api-reference/payment-links
Merchant `plink_` management and buyer `plpub_` checkout routes.
Payment links use two ID namespaces:
| Prefix | Use |
| -------- | -------------------------------------- |
| `plink_` | Merchant API resource id |
| `plpub_` | Buyer-facing URL token (public routes) |
### Public ID format
All public resource IDs use opaque prefixes plus a **32-character lowercase hex** token (128-bit entropy):
| Prefix | Example |
| -------- | ---------------------------------------- |
| `inv_` | `inv_cb1e73f508a2abf4ea639f100de14cef` |
| `plink_` | `plink_961544395accbc1e00c56bbdaa4f07da` |
| `plpub_` | `plpub_c9a9bb730611077574c828af5af5fed1` |
Legacy **12-character** `plpub_` URLs (issued before June 2026) still resolve; the API returns the current 32-char `public_id` in responses.
Buyer responses omit internal UUIDs, settlement wallets, and webhook configuration.
## Authentication (merchant routes)
```
Authorization: Bearer sk_live_...
```
Buyer routes under `/v1/public/payment-links/*` require **no API key**.
***
## Create payment link
`POST /v1/payment-links`
| | |
| --------------- | ---------------------------------- |
| **Scope** | `payment_links:write` |
| **Idempotency** | `Idempotency-Key` header supported |
| **Rate limit** | Write bucket |
### Request
| Field | Notes |
| --------------------------- | ------------------------------------------- |
| `amount_mode` | `fixed_amount` or `customer_defined_amount` |
| `amount` | Required for fixed mode (string) |
| `min_amount` / `max_amount` | Customer-defined mode |
| `allow_multiple_payments` | `true` = reusable; `false` = single-use |
### Response `201`
`id` (`plink_...`), `public_id` (`plpub_...`), `public_url`, pricing fields, `usage` (`reusable` / `single_use`).
***
## Retrieve / update
`GET` / `PATCH /v1/payment-links/{id}`
Path id must be `plink_...`. PATCH cannot change pricing after checkout has started.
***
## Activate / deactivate
`POST /v1/payment-links/{id}/activate`\
`POST /v1/payment-links/{id}/deactivate`
Scope: `payment_links:write`.
***
## Public buyer link
`GET /v1/public/payment-links/{public_id}`
| | |
| -------- | --------------------- |
| **Auth** | None (`security: []`) |
| **Path** | `plpub_...` |
Returns buyer-safe fields only: title, amounts, `store_name`, `merchant_name`. **Does not** expose store UUID, organization id, settlement wallet, webhooks, merchant email, or `store_logo_url` (CDN paths may embed org ids).
### cURL
```bash theme={null}
curl "https://api.meum.io/v1/public/payment-links/plpub_c9a9bb730611077574c828af5af5fed1"
```
***
## Start checkout
`POST /v1/public/payment-links/{public_id}/checkout`
| | |
| -------------- | ------------------ |
| **Auth** | None |
| **Rate limit** | Per `plpub_` token |
### Request
```json theme={null}
{
"amount": "42.50",
"origin_asset": "usdc.near",
"refund_to": "alice.near"
}
```
* **Fixed amount:** omit `amount`.
* **Customer-defined:** `amount` required within min/max.
* **Single-use:** reuses open invoice when present; returns `403` when already paid.
### Response `201`
```json theme={null}
{
"invoice_id": "inv_...",
"checkout_url": "https://pay.meum.io/...",
"reused": false
}
```
### Security
Buyer routes are unauthenticated; rely on rate limits and opaque `plpub_` tokens. Never embed `plink_` merchant ids in public pages.
# Activate payment link
Source: https://docs.meum.io/api-reference/payment-links/activate-payment-link
/openapi.yaml post /v1/payment-links/{id}/activate
# Create payment link
Source: https://docs.meum.io/api-reference/payment-links/create-payment-link
/openapi.yaml post /v1/payment-links
# Deactivate payment link
Source: https://docs.meum.io/api-reference/payment-links/deactivate-payment-link
/openapi.yaml post /v1/payment-links/{id}/deactivate
# Get buyer-facing payment link
Source: https://docs.meum.io/api-reference/payment-links/get-buyer-facing-payment-link
/openapi.yaml get /v1/public/payment-links/{public_id}
Public endpoint for hosted pay-link pages. No API key required.
Use the `plpub_` token from the merchant payment link `public_id` field.
# Get payment link
Source: https://docs.meum.io/api-reference/payment-links/get-payment-link
/openapi.yaml get /v1/payment-links/{id}
# List payment link invoices
Source: https://docs.meum.io/api-reference/payment-links/list-payment-link-invoices
/openapi.yaml get /v1/payment-links/{id}/invoices
# List payment link transactions
Source: https://docs.meum.io/api-reference/payment-links/list-payment-link-transactions
/openapi.yaml get /v1/payment-links/{id}/transactions
# List payment links
Source: https://docs.meum.io/api-reference/payment-links/list-payment-links
/openapi.yaml get /v1/payment-links
# Start payment link checkout
Source: https://docs.meum.io/api-reference/payment-links/start-payment-link-checkout
/openapi.yaml post /v1/public/payment-links/{public_id}/checkout
Creates or reuses an invoice for this payment link and returns a hosted checkout URL.
No API key required. Rate limited per buyer token.
**Fixed amount:** omit `amount` when the link uses `fixed_amount` mode.
**Customer-defined amount:** send `amount` as a decimal string within the link min/max.
**Single-use links:** a second checkout reuses the open invoice when one exists;
paid single-use links return `403`.
# Update payment link
Source: https://docs.meum.io/api-reference/payment-links/update-payment-link
/openapi.yaml patch /v1/payment-links/{id}
Pricing fields cannot be changed after a checkout has started.
# Rate limits
Source: https://docs.meum.io/api-reference/rate-limits
API rate limiting for public endpoints.
## Overview
Rate limits vary by endpoint and account. When a limit is exceeded, the API returns HTTP **429** with a `Retry-After` header (seconds).
Meum may apply different limits to authentication, checkout, invoice creation, integrations, and dashboard operations. Exact thresholds are not published as a fixed contract while limits are being calibrated on some routes.
## Rate limit response
When a limit is enforced:
```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
```
```json theme={null}
{
"error": "too_many_requests",
"message": "Too many requests. Please try again later.",
"retry_after_seconds": 60
}
```
Some routes may still be in observe-only mode during calibration and will not return 429 until limits are finalized.
## Integration guidance
* Retry idempotent reads with exponential backoff when you receive 429.
* Use `Idempotency-Key` on dashboard payment link creation where supported.
* WooCommerce invoice creation is deduplicated by `external_order_id` per store. Retries with the same order ID return the existing invoice when possible.
* If multiple integrations share one egress IP, coordinate request volume; per-API-key accounting may apply on some routes.
## Related pages
* [Common API errors](/troubleshooting/common-api-errors)
* [Idempotency](/api-reference/idempotency) (if documented)
# Overview
Source: https://docs.meum.io/api-reference/transactions
Read-only access to on-chain payment transactions.
Transaction IDs use `txn_...` opaque tokens.
## Authentication
```
Authorization: Bearer sk_live_...
```
**Scope:** `transactions:read` (legacy `payments:read` is no longer accepted).
***
## List transactions
`GET /v1/transactions`
Cursor pagination. Optional filters: `invoice_id` (`inv_...`), `type`, `status`.
Rate limit: read bucket (`observe`).
***
## Retrieve transaction
`GET /v1/transactions/{id}`
Path id: `txn_...`.
***
## Lookup by hash
`GET /v1/transactions/by-hash/{transactionHash}`
On-chain hash lookup within the store scope.
***
## Invoice transactions
`GET /v1/invoices/{id}/transactions`
Lists transactions linked to invoice `inv_...`. Requires `transactions:read`.
### Example (Node.js)
```javascript theme={null}
const res = await fetch(
`https://api.meum.io/v1/invoices/${invoiceId}/transactions`,
{ headers: { Authorization: `Bearer ${apiKey}` } }
);
```
Money fields (`amount`) are always strings in JSON responses.
# Get transaction
Source: https://docs.meum.io/api-reference/transactions/get-transaction
/openapi.yaml get /v1/transactions/{id}
# Get transaction by hash
Source: https://docs.meum.io/api-reference/transactions/get-transaction-by-hash
/openapi.yaml get /v1/transactions/by-hash/{transactionHash}
# List transactions
Source: https://docs.meum.io/api-reference/transactions/list-transactions
/openapi.yaml get /v1/transactions
Returns payment transactions for the authenticated store with cursor pagination.
# Overview
Source: https://docs.meum.io/api-reference/webhooks-api
Developer webhook endpoints, deliveries, and signature verification.
Scopes: `webhooks:read`, `webhooks:write`.
## Create endpoint
`POST /v1/webhook-endpoints`: returns `wh_...` and a **one-time** `secret`.
* HTTPS URL required
* Default events: `invoice.created`, `invoice.paid`, `invoice.expired`, `invoice.failed`
## Deliveries
* `GET /v1/webhook-endpoints/{id}/deliveries`: `whd_...` attempts
* `GET /v1/webhook-deliveries/{id}`: detail
Retries, ordering, and deduplication: [Webhooks overview](/webhooks/overview).
## Verify inbound webhooks
See [Verify signatures](/webhooks/verify-signatures). Payload IDs use `inv_...` and `evt_...`: [Event reference](/webhooks/event-reference).
# Create webhook endpoint
Source: https://docs.meum.io/api-reference/webhooks/create-webhook-endpoint
/openapi.yaml post /v1/webhook-endpoints
Creates a developer-managed webhook endpoint. The signing secret is returned
once in the response and cannot be retrieved again.
# Delete webhook endpoint
Source: https://docs.meum.io/api-reference/webhooks/delete-webhook-endpoint
/openapi.yaml delete /v1/webhook-endpoints/{id}
Soft-deletes (archives) the endpoint. Managed webhooks cannot be deleted.
# Get webhook delivery
Source: https://docs.meum.io/api-reference/webhooks/get-webhook-delivery
/openapi.yaml get /v1/webhook-deliveries/{id}
# Get webhook endpoint
Source: https://docs.meum.io/api-reference/webhooks/get-webhook-endpoint
/openapi.yaml get /v1/webhook-endpoints/{id}
# List webhook deliveries
Source: https://docs.meum.io/api-reference/webhooks/list-webhook-deliveries
/openapi.yaml get /v1/webhook-endpoints/{id}/deliveries
# List webhook endpoints
Source: https://docs.meum.io/api-reference/webhooks/list-webhook-endpoints
/openapi.yaml get /v1/webhook-endpoints
# Send test webhook
Source: https://docs.meum.io/api-reference/webhooks/send-test-webhook
/openapi.yaml post /v1/webhook-endpoints/{id}/test
Dispatches a `webhook.test` event to the endpoint. Rate limited.
# Update webhook endpoint
Source: https://docs.meum.io/api-reference/webhooks/update-webhook-endpoint
/openapi.yaml patch /v1/webhook-endpoints/{id}
Managed (integration-owned) webhooks cannot be modified via this API.
# Overview
Source: https://docs.meum.io/api-reference/woocommerce-api
Connect, disconnect, status, and invoice → webhook → order completion flow.
## Authentication
WooCommerce connect uses a bootstrap or reconnect key. After connect, the plugin uses a **dedicated integration key** with Woo-only scopes.
***
## Connect
`POST /v1/integration/woocommerce/connect`
| | |
| --------- | ------------------------------------------------ |
| **Scope** | `woocommerce:connect` (bootstrap/reconnect keys) |
Returns dedicated `api_key`, `webhook_secret`, and `integration_public_id` (`int_...`).
### Security
Store webhook secret in WordPress options only. Never expose in frontend.
***
## Disconnect
`POST /v1/integration/woocommerce/disconnect`
Scope: `woocommerce:disconnect`.
***
## Status
`GET /v1/integration/woocommerce/status`
Returns connection state, payout readiness, and `integration_public_id` (`int_...`).
***
## Invoice → webhook → `payment_complete()` flow
1. Woo plugin creates invoice via dedicated key (`invoices:create`).
2. Buyer pays on hosted checkout.
3. Meum delivers `invoice.paid` with `X-Meum-*` headers.
4. Plugin verifies signature, `X-Meum-Integration-Id` (`int_...`), and timestamp.
5. Handler calls `$order->payment_complete()` once per `X-Meum-Event-Id`.
6. Duplicate events return `{ "duplicate": true }` without re-running payment actions.
### Security notes
* Reject webhooks when integration id does not match stored `int_...`
* Do not replay production webhook payloads in test environments without proper isolation
# Accept your first payment
Source: https://docs.meum.io/getting-started/accept-first-payment
Create an invoice and complete a test payment.
## Prerequisites
* Settlement wallet configured
* Store-scoped API key with `invoices:write` scope (default for developer keys)
## Steps
1. Create an invoice:
```bash theme={null}
curl -X POST https://api.meum.io/v1/invoices \
-H "Authorization: Bearer sk_live_EXAMPLE_DO_NOT_USE" \
-H "Content-Type: application/json" \
-d '{
"external_order_id": "demo_order_001",
"amount": "10.00",
"currency": "USD",
"return_url": "https://example.com/thank-you"
}'
```
2. Open the `checkout_url` from the response (e.g. `https://pay.meum.io/inv_a1b2c3d4…`)
3. Select a payment token and enter a refund address
4. Complete the on-chain payment (or use dev simulation if available in your environment)
5. Poll status or wait for webhook:
```bash theme={null}
curl https://api.meum.io/v1/invoices/inv_a1b2c3d4…/status \
-H "Authorization: Bearer sk_live_EXAMPLE_DO_NOT_USE"
```
## Expected result
Invoice status transitions to `paid`. Webhook `invoice.paid` is delivered if configured.
## Related pages
* [Invoices API](/api-reference/invoices)
* [Webhooks overview](/webhooks/overview)
# Configure settlement wallet
Source: https://docs.meum.io/getting-started/configure-settlement-wallet
Set the wallet where Meum sends settled stablecoin payments.
Invoice creation returns HTTP 400 `payout_wallet_not_configured` until a settlement wallet is set.
Never share seed phrases or private keys. Meum only needs your **public wallet address**.
## Steps
1. **Dashboard → Account → Organization settlement** (org default), or
2. **Dashboard → Stores → \[Store] → Settings** (per-store override)
3. Set payout address and output asset (USDC/USDT)
4. Save
**Tips:** Verify the address carefully; use a dedicated settlement wallet; test with a small payment first.
## Settlement logs
View per-invoice settlement status in **Dashboard → invoice detail**. Settlement retry is handled by Meum operations: not available via public API.
Email alerts: **Dashboard → Notifications**.
## Troubleshooting
* [Invalid settlement wallet](/troubleshooting/invalid-settlement-wallet)
# Create an account
Source: https://docs.meum.io/getting-started/create-account
Register and set up your Meum organization.
## Steps
1. Go to [app.meum.io/register](https://app.meum.io/register)
2. Sign up with email/password or Google OAuth (Google requires a verified email)
3. A default **organization** and **store** are created automatically
4. Log in at [app.meum.io](https://app.meum.io)
Every new organization starts on the **Free** plan. Upgrade anytime from **Dashboard → Account → Plan & Billing**. See [Subscription plans](/getting-started/subscription-plans).
Registration may require reCAPTCHA when enabled on the platform.
## Organization settings
Manage at **Dashboard → Account → Organization**:
* Default settlement wallet and output asset
* Organization webhook (optional)
* Team members
Organizations with `SUSPENDED` platform access cannot use the dashboard or API.
## Next steps
* [Create a store](/getting-started/create-store) if you need an additional sales channel
* [Configure settlement wallet](/getting-started/configure-settlement-wallet)
# Create a store
Source: https://docs.meum.io/getting-started/create-store
Create a Meum store for payments and integrations.
A **store** represents a merchant storefront or sales channel. API keys, integrations, and invoices are scoped to a store.
## Prerequisites
* Active Meum organization
* Logged in to [app.meum.io](https://app.meum.io)
## Steps
1. Open **Dashboard → Stores**
2. Click **New store**
3. Enter store name and optional slug (public profile at `meum.io/@{slug}`)
4. Save the store
## Expected result
A new store appears in your store list. You can switch between stores using the store selector in the dashboard header.
Configure per-store **Checkout** settings (fee payer, timeout), **Storefront** branding (`meum.io/@{slug}`), and settlement wallet under **Dashboard → Stores → \[Store] → Settings**.
## Related pages
* [Subscription plans](/getting-started/subscription-plans)
* [Configure settlement wallet](/getting-started/configure-settlement-wallet)
* [Get API credentials](/getting-started/get-api-credentials)
# Get API credentials
Source: https://docs.meum.io/getting-started/get-api-credentials
Create store-scoped API keys and WooCommerce connection keys.
## Developer API key
1. Go to **Dashboard → API keys** (store-scoped)
2. Click **Create API key**
3. Copy the key immediately (shown only once (`sk_live_...`)
Default scopes: `invoices:read`, `invoices:write`, `transactions:read`, `payment_links:read`, `payment_links:write`, `webhooks:read`, `webhooks:write`.
| Key type | Scopes | Use |
| ------------- | ---------------------------------------------- | ----------------------------- |
| Developer key | See above | Custom integrations |
| Woo bootstrap | `woocommerce:bootstrap` | Plugin connect only (24h TTL) |
| Woo dedicated | `invoices:create`, `invoices:read`, Woo scopes | Auto-issued after connect |
Use in requests: `Authorization: Bearer sk_live_...` against `https://api.meum.io`.
## WooCommerce connection key
1. **Dashboard → Integrations → WooCommerce** → generate connection key
2. Paste in the plugin connect flow, then see [WooCommerce configuration](/woocommerce/configuration)
Bootstrap keys cannot create invoices. The plugin uses the dedicated key issued after connect.
## Related pages
* [API keys and scopes](/api-reference/api-keys-and-scopes)
* [API key security](/security/api-key-security)
# Subscription plans
Source: https://docs.meum.io/getting-started/subscription-plans
Free, Growth, and Business plans — limits, platform fees, and billing.
Meum offers three self-service plans. Limits and platform fee rates scale with your tier. View live pricing at **[meum.io/pricing](https://meum.io/pricing)**.
## Plans at a glance
| Plan | Monthly price | Platform fee | Stores | Pay links / store | Staff |
| ------------ | ------------- | ------------ | ------ | ----------------- | ---------- |
| **Free** | \$0 | 1.80% | 1 | Plan limit | Owner only |
| **Growth** | \$19 | 1.20% | 3 | Plan limit | Up to 5 |
| **Business** | \$49 | 0.80% | 10 | Plan limit | Up to 15 |
Exact limits are configured in platform settings and shown live on the pricing page and in **Dashboard → Account → Plan & Billing**.
## What's included on every plan
* Hosted checkout on `pay.meum.io`
* Multi-chain tokens and networks at checkout
* USD-priced orders and invoices
* USDC / USDT settlement to your configured wallet
* Transparent platform and network fee quotes at checkout
* Pay Links, WooCommerce plugin, REST API, and signed webhooks
* Multi-store merchant workspace
## Platform fee payer
Configure per store under **Dashboard → Stores → \[Store] → Settings → Checkout**:
| Setting | Free | Growth / Business |
| ----------------- | ------------- | --------------------------------- |
| **Merchant pays** | Yes (default) | Yes |
| **Customer pays** | No | Yes — fee added to checkout total |
Network fees are always shown in the live checkout quote regardless of plan.
## Upgrade and billing
1. Open **Dashboard → Account → Plan & Billing**
2. Compare plans and choose Growth or Business
3. Pay with crypto via the same hosted checkout flow used for customer payments
Annual prepay discounts may be available — shown in Plan & Billing when enabled.
## Related pages
* [Create an account](/getting-started/create-account)
* [Create a store](/getting-started/create-store)
* [How Meum payments work](/introduction/how-payments-work)
# How Meum payments work
Source: https://docs.meum.io/introduction/how-payments-work
End-to-end flow from invoice creation to merchant settlement.
1. **Merchant creates an invoice** via API, WooCommerce, or Pay Link
2. **Customer opens hosted checkout** at `pay.meum.io/inv_{publicId}`
3. **Customer selects origin token** and provides a refund address
4. **Checkout quote** shows order total, platform fee, network cost, and deposit address
5. **Customer confirms** and sends crypto to the deposit address
6. **Meum detects and validates** the payment
7. **Invoice status updates**: `paid`, `underpaid`, `failed`, or `expired`
8. **Webhook delivered** to your integration endpoint
9. **Settlement** sends USDC or USDT to your configured wallet
## Related pages
* [Checkout fees](/payments/checkout-fees)
* [Payment statuses](/payments/payment-statuses)
* [Webhooks overview](/webhooks/overview)
# Overview
Source: https://docs.meum.io/introduction/introduction
Accept crypto payments globally and receive settlement in USDC or USDT.
Meum integrates into your store, Pay Links, and custom apps. Customers pay with BTC, ETH, SOL, and other supported tokens.
## Start here
Create a store, Pay Links, and WooCommerce checkout with no custom code required.
Build with the merchant API, webhooks, and programmatic invoice creation.
## Products
Shareable links to accept crypto payments anywhere.
Customers pay at pay.meum.io and select a token at checkout.
WordPress plugin with hosted checkout and automatic order updates.
Signed invoice events for your backend or store integration.
Free, Growth, and Business — limits, platform fees, and upgrades.
# Create a Pay Link
Source: https://docs.meum.io/payment-links/create-payment-link
Create reusable or one-time Pay Links in Merchant Admin.
Pay Links let customers pay without a full e-commerce integration.
## Prerequisites
* Active store with settlement wallet configured
* Logged in to [app.meum.io](https://app.meum.io)
## Steps
1. Go to **Dashboard → Pay Links**
2. Click **New Pay Link**
3. Configure:
* **Title** and description
* **Amount mode**: `fixed` or `customer` (customer enters amount)
* **Fixed amount** and currency (if fixed mode)
4. Save
## Expected result
A Pay Link with public URL `https://pay.meum.io/plpub_{publicId}` is created (`plpub_` followed by a 32-character hex token).
## Related pages
* [Share Pay Links and storefront](/payment-links/share-and-storefront)
* [Payment links API](/api-reference/payment-links)
* [How Meum payments work](/introduction/how-payments-work)
# Share Pay Links and storefront
Source: https://docs.meum.io/payment-links/share-and-storefront
URL, QR, embeds, and public storefront at meum.io/@your-store.
Every Pay Link includes share tools in **Dashboard → Pay Links → \[Link] → Share**.
## Share methods
| Method | Use case |
| ----------------- | ----------------------------------------------- |
| **Shareable URL** | Paste into email, chat, or social |
| **QR code** | Download SVG for print, menus, or events |
| **Embed button** | HTML snippet — primary, light, or dark variants |
| **Amount widget** | iframe for customer-entered amount links |
## Public storefront
Mark a Pay Link **public** to list it on your storefront at:
```
https://meum.io/@{store-slug}
```
Configure storefront branding under **Dashboard → Stores → \[Store] → Settings → Storefront**:
* Logo and cover banner
* Social links
* Featured links and sort order
## Link modes
| Mode | Behavior |
| -------------- | ------------------------------------------- |
| **Reusable** | Stays active for ongoing sales or donations |
| **Single-use** | Closes after the first successful payment |
## Related pages
* [Create a Pay Link](/payment-links/create-payment-link)
* [Create a store](/getting-started/create-store)
# Checkout fees
Source: https://docs.meum.io/payments/checkout-fees
Platform fees, network costs, and who pays at checkout.
Before a customer confirms payment, hosted checkout on `pay.meum.io` shows a **live quote** with:
* Order total (USD)
* **Platform fee** — percentage on successful payment, based on your plan
* **Network cost** — depends on token and network the customer selects
There are no hidden fees after pay-in.
## Platform fee payer
Set the default per store in **Dashboard → Stores → \[Store] → Settings → Checkout**:
| Mode | Customer sees | Settlement |
| ----------------- | ----------------------------- | ----------------------------------------------------------- |
| **Merchant pays** | Listed order amount only | Platform fee deducted from settlement |
| **Customer pays** | Order + platform fee in total | Customer pays listed amount; fee included in checkout total |
**Free plan:** platform fee is paid by the merchant only. **Growth and Business** can pass the platform fee to the customer.
## Network fees
Blockchain routing costs vary by origin token and network. Meum surfaces them in the quote before the customer confirms — not as a surprise after payment.
## Related pages
* [Subscription plans](/getting-started/subscription-plans)
* [How Meum payments work](/introduction/how-payments-work)
* [Configure settlement wallet](/getting-started/configure-settlement-wallet)
# Payment statuses
Source: https://docs.meum.io/payments/payment-statuses
Invoice and payment row status enums.
See [How Meum payments work](/introduction/how-payments-work) for the end-to-end flow.
## Invoice statuses
```
pending | quoted | awaiting_payment | paid | underpaid | expired | failed | refunded | cancelled
```
**Open** (can still receive payment): `awaiting_payment`, `quoted`, `pending`
**Terminal** (no further payment updates): `paid`, `underpaid`, `failed`, `expired`, `refunded`, `cancelled`
## Payment row statuses
Tracks the on-chain payment record (separate from invoice status):
| Status | Description |
| ----------- | ------------------------------- |
| `pending` | Detected, awaiting confirmation |
| `completed` | Fully confirmed |
| `underpaid` | Less than expected |
| `overpaid` | More than expected |
| `failed` | Payment failed |
## Webhook mapping
| Invoice status | Event | Default subscription |
| -------------- | ------------------- | ------------------------- |
| (on create) | `invoice.created` | Yes |
| `paid` | `invoice.paid` | Yes |
| `underpaid` | `invoice.underpaid` | Yes |
| `failed` | `invoice.failed` | Yes |
| `expired` | `invoice.expired` | Yes |
| `cancelled` | `invoice.cancelled` | Yes (Woo managed) |
| `refunded` | `invoice.refunded` | No: platform polling only |
## Related pages
* [Event reference](/webhooks/event-reference)
* [Underpayment and overpayment](/payments/underpayment-and-overpayment)
# Underpayment and overpayment
Source: https://docs.meum.io/payments/underpayment-and-overpayment
How Meum handles partial and excess payments.
## Underpayment
When received amount is less than expected:
* Invoice status → `underpaid`
* Webhook → `invoice.underpaid`
* WooCommerce order → `on-hold` with order note
## Overpayment
Payment row status may be `overpaid` when received amount exceeds expected. Invoice handling depends on platform validation logic at detection time.
Always verify webhook `received_amount`, `expected_amount`, and `difference_amount` fields rather than assuming full payment.
## Related pages
* [Payment statuses](/payments/payment-statuses)
* [Payment remains pending](/troubleshooting/payment-remains-pending)
# API status
Source: https://docs.meum.io/resources/api-status
Check Meum API health and availability.
## Health endpoint
```bash theme={null}
curl https://api.meum.io/health
```
Example response:
```json theme={null}
{
"status": "ok",
"worker_heartbeat": {
"status": "ok",
"last_at": "2024-06-24T12:05:00.000Z"
}
}
```
## Related pages
* [API overview](/api-reference/overview)
* [Contact support](/resources/contact-support)
# Changelog
Source: https://docs.meum.io/resources/changelog
Updates to the Meum documentation site.
## July 2026
* Added [Subscription plans](/getting-started/subscription-plans) — Free, Growth, Business limits and billing
* Added [Checkout fees](/payments/checkout-fees) — platform fee payer and transparent quotes
* Added [Share Pay Links and storefront](/payment-links/share-and-storefront)
* Fixed WooCommerce plugin ZIP filename (`meum-crypto-payments-for-woocommerce.zip`)
* Redirects for removed URLs: `/introduction/supported-payment-flow`, `/woocommerce/troubleshooting`
* Contact email: **[support@meum.io](mailto:support@meum.io)**
## Earlier
Documentation migrated to Mintlify at [docs.meum.io](https://docs.meum.io).
# Contact support
Source: https://docs.meum.io/resources/contact-support
Get help with Meum integration and account issues.
## Email
[support@meum.io](mailto:support@meum.io)
## Before contacting support
Include (never include secrets):
* Organization name and store slug
* Invoice ID or external order ID
* Timestamp of the issue
* Error message or HTTP status code
* Integration type (WooCommerce, API, Pay Link)
Never email API keys, webhook secrets, seed phrases, or private keys.
## Related pages
* [Troubleshooting](/troubleshooting/payment-remains-pending)
* [WooCommerce configuration](/woocommerce/configuration)
# Glossary
Source: https://docs.meum.io/resources/glossary
Meum terminology reference.
| Term | Definition |
| --------------------- | ------------------------------------------------------------------------ |
| **Invoice** | Payment request with hosted checkout URL (`inv_...`) |
| **Payment** | On-chain transaction record linked to an invoice |
| **Settlement** | Conversion and transfer to merchant stablecoin wallet |
| **Settlement wallet** | Merchant payout address |
| **Output asset** | Settlement stablecoin (e.g. USDC) |
| **Origin asset** | Token the customer pays with |
| **Pay Link** | Shareable URL at `pay.meum.io/plpub_{token}` |
| **Storefront** | Public catalog at `meum.io/@{store-slug}` |
| **Platform fee** | Percentage on successful payment; payer configurable per store (Growth+) |
| **Connection key** | Bootstrap key for WooCommerce connect |
| **Dedicated key** | Runtime key issued after WooCommerce connect |
# Api Key Security
Source: https://docs.meum.io/security/api-key-security
Best practices for API key handling.
* Never commit keys to source control: use environment variables or a secret manager
* Rotate immediately if compromised (**Dashboard → API keys**)
* Woo **bootstrap** keys: connect flow only; runtime uses the dedicated key issued after connect
## Related pages
* [API keys and scopes](/api-reference/api-keys-and-scopes)
* [Incident reporting](/security/incident-reporting)
# Customer Data
Source: https://docs.meum.io/security/customer-data
How Meum handles customer-related data.
Customer records are wallet-centric and derived from invoice metadata.
* WooCommerce customer IDs, emails, and phone may appear in invoice `metadata`
* Analytics are available in Merchant Admin (session login) — not via public API
* Follow applicable privacy regulations for your jurisdiction
## Related pages
* [Customers API status](/api-reference/customers)
* [API key security](/security/api-key-security)
# Incident Reporting
Source: https://docs.meum.io/security/incident-reporting
Report security incidents to Meum.
Email [support@meum.io](mailto:support@meum.io) with:
* Organization and store name (not API keys or secrets)
* Timestamp and affected invoice IDs
* Description of the incident
Rotate compromised API keys and webhook secrets immediately in Merchant Admin.
## Related pages
* [API key security](/security/api-key-security)
* [Verify signatures](/webhooks/verify-signatures)
# Common API errors
Source: https://docs.meum.io/troubleshooting/common-api-errors
Common Meum API and WooCommerce invoice error codes and fixes.
| HTTP | Error | Fix |
| ---- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| 401 | Unauthorized | Check Bearer token |
| 403 | Bootstrap key for invoices | Use dedicated key after Woo connect |
| 403 | `CURRENCY_NOT_ALLOWED` | Allow the shop/invoice currency in Merchant Admin fiat/invoice currency settings, or change the WooCommerce shop currency to a permitted currency |
| 400 | Payout wallet not configured | Configure settlement wallet |
| 409 | Order ID conflict | Use unique external\_order\_id |
| 429 | Too many requests | Back off and retry |
`CURRENCY_NOT_ALLOWED`
Invoice creation returns HTTP **403** with code `CURRENCY_NOT_ALLOWED` when the requested fiat currency is not in the merchant’s allowed invoice fiat currencies.
**Typical WooCommerce case:** the shop currency (for example `EUR`) is sent on `POST /v1/invoices`, but the connected Meum org/store only allows another currency (often `USD` by default).
**Fix (pick one):**
1. In Merchant Admin, allow that currency for invoice fiat currencies (org/store settings), **or**
2. Change **WooCommerce → Settings → General → Currency** to a currency Meum already allows.
The WooCommerce plugin shows a short shopper-safe checkout message; merchants see the full currency hint under **WooCommerce → Settings → Payments → Meum**.
## Related pages
* [Errors](/api-reference/errors)
* [WooCommerce configuration](/woocommerce/configuration)
* [Configure settlement wallet](/getting-started/configure-settlement-wallet)
# Invalid Settlement Wallet
Source: https://docs.meum.io/troubleshooting/invalid-settlement-wallet
Troubleshoot invalid settlement wallet issues with Meum.
Invoice creation or WooCommerce connect fails with payout wallet error.
**Resolution:**
1. Go to **Dashboard → Account → Organization settlement**
2. Enter a valid payout address for your chosen settlement stablecoin
3. Select output asset (settlement stablecoin)
4. Retry operation
See [Configure settlement wallet](/getting-started/configure-settlement-wallet).
## Related pages
* [Configure settlement wallet](/getting-started/configure-settlement-wallet)
* [Errors](/api-reference/errors)
# Payment Expired
Source: https://docs.meum.io/troubleshooting/payment-expired
Troubleshoot payment expired issues with Meum.
Invoice status is `expired`.
**Cause:** Invoice passed `expires_at` without full payment.
**Resolution:** Create a new invoice or Pay Link. WooCommerce orders are set to `cancelled`.
## Related pages
* [Payment statuses](/payments/payment-statuses)
* [Accept your first payment](/getting-started/accept-first-payment)
# Payment Received Order Not Updated
Source: https://docs.meum.io/troubleshooting/payment-received-order-not-updated
Troubleshoot payment received order not updated issues with Meum.
Payment confirmed in Meum but WooCommerce order not updated.
**Check:**
1. Webhook URL reachable from the public internet (check the URL shown in WooCommerce payment settings after connect)
2. WordPress permalinks enabled (not plain)
3. Webhook secret matches between Meum and plugin
4. Check WooCommerce order notes for webhook errors
5. Verify HTTP 200 response with `{ "received": true }`
See [WooCommerce webhook verification](/woocommerce/webhook-verification).
## Related pages
* [Webhook verification](/woocommerce/webhook-verification)
* [Verify signatures](/webhooks/verify-signatures)
# Payment Remains Pending
Source: https://docs.meum.io/troubleshooting/payment-remains-pending
Troubleshoot payment remains pending issues with Meum.
Invoice status stays `awaiting_payment` or `quoted`.
**Check:**
1. Customer completed on-chain payment to correct deposit address
2. Correct token/network selected at checkout
3. Poll `GET /v1/invoices/{id}/status` to trigger on-demand status check
4. Confirm you are testing against the production API (not a staging environment)
**Expected result:** Status transitions within normal confirmation window.
## Related pages
* [Payment statuses](/payments/payment-statuses)
* [How Meum payments work](/introduction/how-payments-work)
# Webhook Delivery Failed
Source: https://docs.meum.io/troubleshooting/webhook-delivery-failed
Troubleshoot webhook delivery failed issues with Meum.
Webhook shows failed in Merchant Admin or integration events.
**Check:**
1. Endpoint returns HTTP 2xx within 10 seconds
2. Signature verification passes on your server
3. For WooCommerce: response body passes acknowledgment check
4. Developer endpoints disabled after 10 consecutive failures. Re-enable in dashboard
See [Webhooks overview](/webhooks/overview).
## Related pages
* [Verify signatures](/webhooks/verify-signatures)
* [Webhooks overview](/webhooks/overview)
# Woocommerce Connection Failed
Source: https://docs.meum.io/troubleshooting/woocommerce-connection-failed
Troubleshoot woocommerce connection failed issues with Meum.
WooCommerce plugin connect fails.
| Error | Action |
| ---------------------------- | ------------------------------------------------- |
| Invalid connection key | Generate new key in Merchant Admin → Integrations |
| Insufficient scope | Use bootstrap connection key, not dedicated key |
| Site already connected | Disconnect from other store first |
| Payout wallet not configured | Configure settlement wallet |
| API unreachable | Verify Platform API URL is `https://api.meum.io` |
## Related pages
* [WooCommerce configuration](/woocommerce/configuration)
* [Get API credentials](/getting-started/get-api-credentials)
# Configure endpoint
Source: https://docs.meum.io/webhooks/configure-endpoint
Set up webhook endpoints in Merchant Admin or via WooCommerce connect.
## WooCommerce (managed)
Webhook endpoint is created automatically on connect. The plugin registers:
```
https://your-store.com/?wc-api=stablecoin_webhook
```
(`your-store.com` is your WordPress site URL.) Also shown in **WooCommerce → Settings → Payments → Meum** after connect.
## Custom integration (dashboard)
1. **Dashboard → Webhooks** → add endpoint URL
2. Select events to subscribe
3. Copy webhook secret (shown once)
For one-off invoices without a stored endpoint, pass `callback_url` in `POST /v1/invoices`.
## Default events
`invoice.created`, `invoice.paid`, `invoice.expired`, `invoice.failed`
WooCommerce managed endpoints also include `invoice.cancelled` and `invoice.underpaid`.
Send a test event from the dashboard (`webhook.test`).
## Related pages
* [Webhooks overview](/webhooks/overview)
* [Verify signatures](/webhooks/verify-signatures)
* [Testing webhooks](/webhooks/testing-webhooks)
# Event reference
Source: https://docs.meum.io/webhooks/event-reference
Complete webhook event payload reference.
## Payload envelope
All events share this structure:
```json theme={null}
{
"id": "evt_a1b2c3d4e5f6789012345678abcdef01",
"type": "invoice.paid",
"createdAt": "2024-06-24T12:00:00.000Z",
"data": {
"invoice_id": "inv_a1b2c3d4e5f6789012345678abcdef01",
"integration_id": "int_a1b2c3d4e5f6789012345678abcdef01",
"external_order_id": "order_1048",
"amount": "100.00",
"expected_amount": "100.00",
"received_amount": "100.00",
"difference_amount": "0.00",
"paid_amount": "100.00",
"currency": "USD",
"output_asset": "usdc",
"tx_hash": "0x…",
"paid_at": "2024-06-24T12:05:00.000Z",
"payment_url": "https://pay.meum.io/inv_a1b2c3d4e5f6789012345678abcdef01",
"status": "paid"
}
}
```
Payloads use opaque public IDs (`inv_`, `evt_`, `int_`). Do not rely on undocumented fields if present in a response.
## Standard merchant events
### invoice.created
Sent immediately after invoice creation. `data.status` is typically `awaiting_payment`.
### invoice.paid
Sent when full payment is validated. `data.paid_at` and `data.tx_hash` are populated.
### invoice.underpaid
Sent when partial payment detected. Check `difference_amount`.
### invoice.failed
Sent on payment failure.
### invoice.expired
Sent when invoice expires.
### invoice.cancelled
Sent when a merchant cancels an open invoice via `POST /v1/invoices/{id}/cancel`. Only invoices in open states (`awaiting_payment`, `quoted`, `pending`) can be cancelled. Terminal states (`paid`, `refunded`, etc.) cannot be cancelled.
Previously this event was subscribed on WooCommerce endpoints but not emitted. Public cancel API now dispatches `invoice.cancelled`.
### webhook.test
```json theme={null}
{
"id": "evt_demo_test",
"type": "webhook.test",
"data": { "message": "Test webhook from Meum" }
}
```
## Platform-emitted events (not in default subscriptions)
### invoice.refunded
Not a standard merchant integration event. Do not assume this event is subscribed or delivered by default.
**When emitted:** Platform status polling detects a refund on an open invoice. The invoice status becomes `refunded` and `invoice.refunded` is dispatched.
**Not available:** Merchant-initiated refund API. Default WooCommerce managed webhook subscriptions do not include this event.
**WooCommerce behavior if received:** Adds an order note only; does not change order status.
## Expected HTTP response
Return **HTTP 200** with JSON body acknowledging receipt.
## Related pages
* [Verify signatures](/webhooks/verify-signatures)
* [Webhooks overview](/webhooks/overview)
* [Webhooks overview](/webhooks/overview)
# Webhooks overview
Source: https://docs.meum.io/webhooks/overview
Meum outbound webhooks for events, headers, delivery, and reliability.
Meum sends HTTP POST webhooks when invoice status changes.
## Events
| Event | Trigger |
| ------------------- | ------------------------------------------------------- |
| `invoice.created` | Invoice created |
| `invoice.paid` | Full payment received |
| `invoice.underpaid` | Partial payment |
| `invoice.failed` | Payment failed |
| `invoice.expired` | Invoice expired |
| `invoice.cancelled` | Invoice cancelled |
| `webhook.test` | Manual test from dashboard |
| `invoice.refunded` | Platform polling only: **not** in default subscriptions |
WooCommerce managed endpoints subscribe to all invoice events except `webhook.test` and `invoice.refunded`.
Full payload shapes: [Event reference](/webhooks/event-reference).
## Delivery headers
| Header | Required | Description |
| ----------------------- | ------------- | -------------------------------- |
| `X-Meum-Event` | Yes | Event type |
| `X-Meum-Event-Id` | Yes | `evt_...`: use for deduplication |
| `X-Meum-Timestamp` | Yes | Unix seconds (signature input) |
| `X-Meum-Signature` | Yes | `v1=` |
| `X-Meum-Integration-Id` | If integrated | `int_...` |
Legacy `X-Stablecoin-*` headers are **not** sent.
Verify every delivery: [Verify signatures](/webhooks/verify-signatures).
## Delivery and reliability
| Topic | Behavior |
| ---------------- | ------------------------------------------------------------------------------------ |
| **Retries** | Up to 6 attempts, exponential backoff from 60s, 10s timeout |
| **Ordering** | Not guaranteed globally; per-invoice events follow the state machine |
| **Duplicates** | Retries may redeliver: dedupe on `X-Meum-Event-Id` |
| **Auto-disable** | Custom developer endpoints disabled after 10 consecutive failures |
| **WooCommerce** | Endpoint auto-created on connect: [Configure endpoint](/webhooks/configure-endpoint) |
## Related pages
* [Configure endpoint](/webhooks/configure-endpoint)
* [Testing webhooks](/webhooks/testing-webhooks)
* [Webhooks API](/api-reference/webhooks-api)
# Testing webhooks
Source: https://docs.meum.io/webhooks/testing-webhooks
Test webhook delivery from Merchant Admin.
## Dashboard test
1. Go to **Dashboard → Webhooks**
2. Select an endpoint
3. Click **Send test webhook**
4. Event type: `webhook.test`
## Verify locally
Use a tunnel (ngrok, cloudflared) to expose your local endpoint:
```bash theme={null}
ngrok http 3000
```
Register the tunnel URL in **Dashboard → Webhooks**.
Do not use `webhook.site` placeholder URLs in production. Meum skips known placeholder URLs.
## Related pages
* [Configure endpoint](/webhooks/configure-endpoint)
* [Verify signatures](/webhooks/verify-signatures)
# Verify signatures
Source: https://docs.meum.io/webhooks/verify-signatures
HMAC v1 webhook signature verification.
## Signature format
```
signedPayload = timestamp + "." + rawBody
signature = HMAC_SHA256(webhook_secret, signedPayload)
header value = "v1=" + hex(signature)
```
## Verification steps
1. Read raw request body (before JSON parsing)
2. Require `X-Meum-Signature` and `X-Meum-Timestamp`
3. Reject timestamps older than **300 seconds**
4. When `X-Meum-Integration-Id` is present, match your stored `int_...`
5. Compare signatures with constant-time equality
6. Deduplicate on `X-Meum-Event-Id` before processing
## Example (Node.js)
```javascript theme={null}
const crypto = require("crypto");
function verifyWebhook(rawBody, headers, secret) {
const timestamp = headers["x-meum-timestamp"];
const signature = headers["x-meum-signature"];
if (!timestamp || !signature) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp)) > 300) return false;
const signed = `${timestamp}.${rawBody}`;
const expected = "v1=" + crypto.createHmac("sha256", secret).update(signed).digest("hex");
try {
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
} catch {
return false;
}
}
```
## Security checklist
* Return HTTP 200 only after verification succeeds
* Never log webhook secrets
* Rotate secrets immediately if compromised ([Incident reporting](/security/incident-reporting))
## Related pages
* [WooCommerce webhook verification](/woocommerce/webhook-verification)
* [Webhooks overview](/webhooks/overview)
# Checkout flow
Source: https://docs.meum.io/woocommerce/checkout-flow
WooCommerce checkout to Meum hosted checkout flow.
## Flow
1. Customer selects **Pay with Crypto** at WooCommerce checkout
2. Plugin calls `POST /v1/invoices` with Woo order ID as `external_order_id`
3. Order status set to `on-hold` with awaiting-payment order note
4. Order meta stores the Meum invoice ID and checkout URL for the customer to resume payment
5. Customer redirected to hosted checkout (`checkout_url`, e.g. `https://pay.meum.io/inv_…`)
6. Customer completes crypto payment on hosted checkout
7. Meum sends `invoice.paid` webhook to WooCommerce
8. Plugin calls `$order->payment_complete()` and adds payment received order note
## Redirect behavior
Plugin returns `{ result: 'success', redirect: checkout_url }`. Full redirect to Meum hosted checkout.
## Related pages
* [Webhook verification](/woocommerce/webhook-verification)
* [How Meum payments work](/introduction/how-payments-work)
# Configuration
Source: https://docs.meum.io/woocommerce/configuration
Connect WooCommerce to Meum via connection key.
## Prerequisites
* Plugin installed and activated
* Settlement wallet configured in Merchant Admin
* WooCommerce connection key from **Dashboard → Integrations → WooCommerce**
## Steps
1. Open **WooCommerce → Settings → Payments → Meum Crypto Payments**
2. Paste the **connection key** from Merchant Admin
3. Click **Connect**
4. On success, the plugin stores:
* Dedicated API key
* Webhook secret
* Integration ID
5. Enable the gateway checkbox
6. Save settings
## Advanced settings
* **Platform API URL**: default `https://api.meum.io`. Change only when Meum support provides a different base URL for your environment.
On **Growth** and **Business** plans, configure whether the platform fee is paid by the merchant or customer under **Dashboard → Stores → \[Store] → Settings → Checkout**. See [Checkout fees](/payments/checkout-fees).
## Shop currency
WooCommerce sends the store **shop currency** on each invoice. That currency must be allowed in Meum merchant invoice fiat settings. Otherwise checkout fails with `CURRENCY_NOT_ALLOWED` (HTTP 403).
**Fix:** allow the shop currency in Merchant Admin, or change **WooCommerce → Settings → General → Currency** to a currency Meum already allows. See [Common API errors](/troubleshooting/common-api-errors#currency_not_allowed).
## Expected result
Gateway shows "Connected" status. Checkout displays "Pay with Crypto".
## Related pages
* [Webhook verification](/woocommerce/webhook-verification)
* [Checkout flow](/woocommerce/checkout-flow)
* [Common API errors](/troubleshooting/common-api-errors)
# Installation
Source: https://docs.meum.io/woocommerce/installation
Install the Meum WooCommerce plugin.
## Requirements
* WordPress 6.5+
* WooCommerce 7.0+
* PHP 7.4+
* HTTPS-enabled site (required for webhooks)
* Meum merchant account with settlement wallet configured
## Download
Download the latest plugin ZIP from:
* **[meum.io/integrations](https://meum.io/integrations#woocommerce)** — version shown on the page
* Direct file: `meum-crypto-payments-for-woocommerce.zip`
## Installation steps
1. In WordPress admin, go to **Plugins → Add New → Upload Plugin**
2. Upload the `meum-crypto-payments-for-woocommerce.zip` file
3. Click **Install Now**, then **Activate**
4. Go to **WooCommerce → Settings → Payments → Meum Crypto Payments**
## Expected result
The Meum payment gateway appears in WooCommerce payments settings with a connection form.
## Related pages
* [Configuration](/woocommerce/configuration)
# Webhook verification
Source: https://docs.meum.io/woocommerce/webhook-verification
WooCommerce plugin webhook URL and acknowledgment behavior.
## Webhook URL
```
https://your-store.com/?wc-api=stablecoin_webhook
```
Built by the plugin on connect. Also shown in **WooCommerce → Settings → Payments → Meum**.
## Plugin behavior
* Verifies `X-Meum-*` headers (see [Verify signatures](/webhooks/verify-signatures))
* Rejects legacy `X-Stablecoin-*` headers
* Dedupes on `X-Meum-Event-Id` in order meta
* Returns HTTP `200` with `{ "received": true }` or `{ "duplicate": true }`
## Related pages
* [Checkout flow](/woocommerce/checkout-flow)
* [Configure endpoint](/webhooks/configure-endpoint)