# Best Practices Source: https://docs.mufi.app/docs/best-practices Security guidelines for building with the Mufi API Follow these practices to keep your integration and your users safe. ## API Key Security Your API key grants full access to your project. Treat it like a password. * **Store in environment variables** — never hardcode keys in source code or commit them to version control * **Server-side only** — API keys should only be used on your backend. Never expose them in client-side code, mobile apps, or browser JavaScript * **Rotate when compromised** — if you suspect a key has been leaked, regenerate it immediately from the [Mufi Dashboard](https://my.mufi.app) * **Least privilege** — use read-only keys for endpoints that only need to query data ## Dashboard Access * **Limit access** — only grant Mufi Dashboard access to team members who need it * **Use strong authentication** — set up a time-based one-time password (e.g., Google Authenticator) for your dashboard account * **Audit regularly** — review who has access to your project and remove inactive team members ## Transport Security * **Always use HTTPS** — all requests to the Mufi API must use HTTPS. Never make API calls over plain HTTP * **Validate SSL certificates** — ensure your HTTP client verifies SSL certificates to prevent man-in-the-middle attacks ## Frontend Security If your application has a frontend that interacts with your backend (which then calls the Mufi API): ### Content Security Policy (CSP) * Enforce a strict CSP to prevent cross-site scripting (XSS) attacks * Limit permissible JavaScript sources and avoid `unsafe-inline` * Set appropriate `frame-src` directives if embedding content ### CORS Configuration * Specify exact origins — avoid wildcards (`*`) in production * Be especially strict in your production environment (no `localhost` origins) * Review CORS settings when deploying to new domains ### General * Implement TLS/HTTPS for all requests from your frontend to your backend * Avoid open redirects that could be exploited for phishing * Sanitize all user input before processing ## Incident Response If a team member's account is compromised: 1. **Immediately regenerate** all API keys for affected projects 2. **Review recent activity** in the Mufi Dashboard for unauthorized actions 3. **Revoke access** for the compromised account 4. **Contact us** at [connect@mufi.app](mailto:connect@mufi.app) if you suspect unauthorized API activity # Create Product Source: https://docs.mufi.app/docs/endpoint/engagement/create-product post /v1/products Create a new product for an event. Products define redeemable items that can be distributed to users, such as vouchers, coupons, or digital collectibles. # Create Product Items Source: https://docs.mufi.app/docs/endpoint/engagement/create-product-items post /v1/products/{id}/items Issue product items to users by user ID or email. Users must be customers of the project. At least one of `users` or `emails` must be provided. # Event Attendee Registration Source: https://docs.mufi.app/docs/endpoint/engagement/event-attendee-registration post /v1/events/attendees/register Register a user to an event. This is used to create a record of the user attending the event and can by used to update the timestamp of the registration or attendance. # Event Creation Source: https://docs.mufi.app/docs/endpoint/engagement/event-creation post /v1/events/create Create a new event record for a project. This can be used to track events such as music festivals, conferences, or any other event that can be attended by users. # Event Deletion Source: https://docs.mufi.app/docs/endpoint/engagement/event-deletion delete /v1/events/delete Delete an existing event record for a project. This will remove the event from the project and all associated data. # Event Update Source: https://docs.mufi.app/docs/endpoint/engagement/event-update put /v1/events/update Update an existing event record for a project. This can be used to update the event name, description, start date, and end date. # Fetch Event Attendees Source: https://docs.mufi.app/docs/endpoint/engagement/fetch-event-attendees get /v1/events/{event_id}/attendees Fetch the attendees of an event. This is used to get a list of users that have registered to attend the event. # Fetch Events Source: https://docs.mufi.app/docs/endpoint/engagement/fetch-events get /v1/events Fetch all events for a project ordered by creation date and then ID. Results can be paginated with `page` and `limit` query parameters. # Get Event Source: https://docs.mufi.app/docs/endpoint/engagement/get-event get /v1/events/{IdOrReferenceId} Fetch an existing event record for a project. # Get Product Source: https://docs.mufi.app/docs/endpoint/engagement/get-product get /v1/products/{id} Fetch a single product by ID for the project. # List Product Sales Source: https://docs.mufi.app/docs/endpoint/engagement/list-product-sales get /v1/products/{id}/sales Fetch all sales (order items) for a product. Results are paginated. # List Products Source: https://docs.mufi.app/docs/endpoint/engagement/list-products get /v1/products Fetch all products for a project ordered by creation date. Results can be paginated with `page` and `limit` query parameters. # Redeem Product Item Source: https://docs.mufi.app/docs/endpoint/engagement/redeem-product-item post /v1/products/{id}/items/redeem Redeem a product item on behalf of a user. Product items can only be redeemed once. # Transfer Product Item Source: https://docs.mufi.app/docs/endpoint/engagement/transfer-product-item post /v1/products/{id}/transfer Transfer a product item from one user to another. The product must have `is_transferable` set to true. Users can be identified by email or user ID. # API Version Source: https://docs.mufi.app/docs/endpoint/version/api-version get /v1/version Retrieve the current version of the API. This endpoint serves as a health check to ensure the API is operational and can be used to verify the availability of new API endpoints based on the version number. It returns a JSON object containing the version string, which can be useful for debugging and ensuring compatibility with client applications. # Activate User Source: https://docs.mufi.app/docs/endpoint/wallets/activate-user post /v1/users/activate Set a user to activated. Activation status is required to manage any features associated with their wallets. The current date is used as the activation date. You can query the activation status of a user using the `POST /v1/users/activation` endpoint. # Create User Source: https://docs.mufi.app/docs/endpoint/wallets/create-user post /v1/users/create Users are created immediately and will have a blockchain wallet asynchronously created in the background. Wallet generation involves securely splitting the private key into encrypted fragments using **[Shamir's Secret Sharing Scheme (SSSS)](https://en.wikipedia.org/wiki/Shamir%28s_secret_sharing)**. These fragments are then distributed across a fault-tolerant, distributed storage system across multiple platform providers with an additional layer of re-encryption to enhance security. For large batches of users, the wallet creation process may take a few minutes to complete depending on the batch size and system load. Once complete, the users and their wallets are fully operational and available for blockchain transactions. ## Key Features of the Process: **API Key Association**: Each user is linked to your organization's project application via the API key for secure access. **Asynchronous Processing**: User wallet creation occurs in the background to avoid delays in the user experience. **Enhanced Security**: Wallet secrets are created and split into encrypted fragments (SSSS) and stored in a distributed system with re-encryption. # Fetch User Source: https://docs.mufi.app/docs/endpoint/wallets/fetch-user post /v1/users/profile Retrieve detailed information about a user, including their associated wallets, by querying with `email`, `id`, or `referenceId`. # Fetch Users Source: https://docs.mufi.app/docs/endpoint/wallets/fetch-users post /v1/users/fetch Retrieve users linked to your project application. This `POST` endpoint allows querying by `email`, `id`, or `referenceId`. Use only one field; priority is given to `email`, then `referenceId`, and finally `id` in the MuFi database. # Fetch Wallets Source: https://docs.mufi.app/docs/endpoint/wallets/fetch-wallets get /v1/projects/wallets Get all wallets for a project. # Get User Count Source: https://docs.mufi.app/docs/endpoint/wallets/get-user-count get /v1/users/count Get the number of active users. # Get Wallet Balances Source: https://docs.mufi.app/docs/endpoint/wallets/get-wallet-balances post /v1/users/balances Get the balances of a user's wallets for a given blockchain. # User Activation Status Source: https://docs.mufi.app/docs/endpoint/wallets/user-activation-status post /v1/users/activation Get the activation status of a user. Users are activated after calling the `POST /v1/users/activate` endpoint. # Events Source: https://docs.mufi.app/docs/events-overview Create, manage, and track events with attendee registration and check-ins The Events API gives you full lifecycle management for any type of gathering — music festivals, conferences, meetups, product launches, and more. Create events, register attendees, track check-ins, and associate products like tickets and vouchers. ## How Events Work ``` Create Event → Create Products (tickets, perks) → Register Attendees → Check In → Redeem Items ``` Events serve as the **parent entity for products**. When you create a ticket, voucher, or perk, you associate it with an event via the `event_id` field. This lets you: * Offer multiple product types per event (general admission, VIP, drink vouchers) * Track inventory and sales per event * Manage attendee registration and check-in independently from product issuance ## Event Lifecycle | Stage | What happens | | ------------ | -------------------------------------------------------------------------------------------------------------------- | | **Create** | Define your event with name, description, dates, location, and an optional `reference_id` to link to your own system | | **Manage** | Update event details or delete events as plans change | | **Products** | Create tickets, perks, and vouchers linked to your event via the [Products API](/docs/products/introduction) | | **Register** | Register users as attendees with optional `registered_at` and `checked_in_at` timestamps | | **Check-in** | Update attendee records when they arrive at the venue | ## Key Features Fetch events by Mufi UUID or your own custom `reference_id` — integrate seamlessly with your existing systems. Track registration and check-in timestamps independently. Safe to call repeatedly — existing records are updated, not duplicated. Associate multiple product types (admission, presale, perks) with a single event for complete event monetization. Create, read, update, and delete events. List all events with pagination or fetch individual events by ID. ## Quick Example Create an event and register an attendee: ```bash cURL theme={null} # Create an event curl -X POST https://api.mufi.app/v1/events/create \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Summer Festival", "location": "Miami, FL", "address": "123 Ocean Drive", "start_date": 1756684800, "end_date": 1756857600 }' # Register an attendee curl -X POST https://api.mufi.app/v1/events/attendees/register \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "event_id": "EVENT_ID", "user_id": "USER_ID", "registered_at": 1756684800 }' ``` ## Learn More Full API documentation with all endpoints, parameters, and response schemas. Learn how to create tickets, vouchers, and perks for your events. # Introduction Source: https://docs.mufi.app/docs/events/introduction Create and manage events with attendee registration and check-in The Events API provides full lifecycle management for events such as music festivals, conferences, meetups, and any other gatherings. Create events, register attendees, track check-ins, and manage event details — all through a simple REST interface. ## Key Concepts ### Event Lifecycle 1. **Creation** — Define your event with a name, description, dates, location, and address. 2. **Management** — Update event details or delete events as plans change. 3. **Registration** — Register users as attendees and track their check-in timestamps. 4. **Products** — Associate products (tickets, perks, vouchers) with events via the Products API. ### Event Identification Events support flexible lookup using either their Mufi-generated UUID or a custom `reference_id` that you provide at creation. This makes it easy to cross-reference events with your own systems. ### Attendee Management The attendee system tracks two key moments in a user's event journey: | Timestamp | Description | | --------------- | --------------------------------------------- | | `registered_at` | When the user registered for the event | | `checked_in_at` | When the user physically arrived at the venue | Both timestamps are optional and can be set independently. Calling the register endpoint on an existing attendee updates their record rather than creating a duplicate, making it safe to call repeatedly (e.g., updating check-in after initial registration). Users must be created via the Users API before they can be registered as event attendees. You can identify attendees by email, user ID, or reference ID. ### Events and Products Events serve as the parent entity for products. When creating a product (ticket, perk, voucher), you associate it with an event via the `event_id` field. This allows you to: * Offer multiple product types per event (e.g., general admission, VIP, drink vouchers) * Track which products belong to which event * Manage event-scoped inventory and sales See the [Products tab](/docs/endpoint/engagement/create-product) for product endpoint documentation. ## Available Endpoints Create a new event with name, dates, location, and description. List all events for your project with pagination support. Retrieve a single event by its ID or reference ID. Update event details such as name, description, and dates. Delete an event and all associated data. Register a user for an event or update their registration and check-in timestamps. List all registered attendees for an event with registration and check-in details. # Introduction Source: https://docs.mufi.app/docs/introduction The developer platform for fan engagement, creator monetization, and digital experiences Brussels Crowd Hero Mufi is the developer platform for fan engagement, creator monetization, and digital experiences. We provide a simple REST API that lets you create users with blockchain wallets, manage events, issue digital products, and process payments — all through familiar workflows while leveraging web3 infrastructure under the hood. Mufi is currently in **Alpha**. [Get started](https://my.mufi.app) by creating an account, or email [connect@mufi.app](mailto:connect@mufi.app) to join the program. ## Why Mufi? A standard REST API with JSON payloads. No blockchain knowledge required — we handle wallets, keys, and on-chain operations behind the scenes. Wallet secrets are split using Shamir's Secret Sharing across isolated, multi-region custodians. No single point of failure. No full secret stored anywhere. Create up to 1,500 users per request. Issue items to 550 users at once. Wallets are provisioned asynchronously so your app never blocks. ## Platform Overview Custodial Polkadot wallets for every user — provisioned automatically, secured with distributed secret sharing. Users can also attach their own non-custodial wallets. Full event lifecycle management with attendee registration, check-ins, and digital products — tickets, vouchers, perks, and NFT-backed collectibles. Flexible payment processing to monetize your events and products worldwide.
**Coming soon.**
Mufi's own legendary music events — a live playground for the platform.
## API Capabilities Build your entire fan engagement stack with three core APIs: Create users with automatic wallet provisioning. Manage activation, profiles, and wallet balances. Batch create up to 1,500 users per request. Create and manage events with full lifecycle support. Register attendees, track check-ins, and associate products with events. Issue digital products — admission tickets, presale offers, perks, and NFT collectibles. Manage redemptions, transfers, and sales tracking. ## Quick Links Go from zero to your first API call in minutes. Learn how to authenticate your API requests. Understand how Mufi protects wallet secrets at scale. Security tips for keeping your integration safe. # Products Source: https://docs.mufi.app/docs/products-overview Issue digital products — tickets, vouchers, perks, and NFT collectibles The Products API lets you create digital products and distribute them to your users. Products cover everything from event admission tickets to drink vouchers, VIP perks, and NFT-backed collectibles — with full lifecycle management for issuance, redemption, transfer, and sales tracking. ## How Products Work ``` Create Product → Issue Items to Users → Redeem at Event → (Optional) Transfer Between Users ``` Every product belongs to an **event** and has a **type** that defines its purpose: | Type | Use Case | Example | | ----------- | ------------------- | ---------------------------------------------- | | `admission` | Entry tickets | General admission, VIP pass | | `presale` | Early access offers | Presale tickets, early bird deals | | `perks` | Vouchers and extras | Drink coupons, merch credits, backstage access | ## Product Items A **product item** is a single instance of a product issued to a user. Think of a product as the template (e.g., "General Admission Ticket") and items as individual copies given to specific users. Items support: * **Sequential IDs** — Each item gets a unique `item_id` (also used as NFT ID if minted) * **Multi-use redemption** — Configure `redemption_quantity` for items valid for multiple uses (e.g., a voucher for 3 drinks) * **Transfers** — Allow users to send items to other users (when `is_transferable` is enabled) * **Batch issuance** — Issue to up to **550 users** per request ## Configuration Options Products offer fine-grained control over distribution: | Field | What it does | Default | | --------------------- | ------------------------------------------------- | --------- | | `stock` | Total available inventory (`null` = unlimited) | Unlimited | | `max_per_account` | Max items per user (`null` = unlimited) | Unlimited | | `redemption_quantity` | Times each item can be redeemed | 1 | | `is_transferable` | Allow transfers between users | `false` | | `is_claimable` | Allow claiming via direct URL | `false` | | `price` | Product price as decimal string (e.g., `"49.99"`) | — | | `active` | Whether items can currently be issued | `true` | ## NFT Minting Products can optionally mint an NFT on the Polkadot network for each issued item. When enabled: * Set `mint_nft: true` when creating the product * Provide a `metadata_uri` pointing to a JSON file with `name`, `image`, and `description` * Choose a `chain`: `AssetHub` (mainnet) or `WestendAssetHub` (testnet) * Your project wallet needs at least **2 DOT** (or 2 WND on testnet) for on-chain fees * Each item's sequential `item_id` becomes its on-chain NFT ID ## Quick Example Create a ticket and issue it: ```bash cURL theme={null} # Create a product curl -X POST https://api.mufi.app/v1/products \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "admission", "name": "General Admission", "price": "49.99", "stock": 500, "is_transferable": true, "event_id": "EVENT_ID" }' # Issue items to users curl -X POST https://api.mufi.app/v1/products/PRODUCT_ID/items \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "PRODUCT_ID", "emails": ["fan1@example.com", "fan2@example.com"] }' # Redeem an item curl -X POST https://api.mufi.app/v1/products/PRODUCT_ID/items/redeem \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_item_id": "ITEM_ID" }' ``` ## Learn More Full API documentation with all endpoints, parameters, and response schemas. Learn how events and products work together. # Introduction Source: https://docs.mufi.app/docs/products/introduction Create products, issue items, and manage redemptions and transfers The Products API lets you create digital products — tickets, vouchers, perks, and NFT-backed collectibles — and distribute them to your users. Products are associated with events and support a full item lifecycle: creation, issuance, redemption, transfer, and sales tracking. ## Key Concepts ### Product Types Every product has a `type` that defines its purpose: | Type | Description | | ----------- | -------------------------------------------------------------- | | `admission` | Entry tickets for events (e.g., general admission, VIP) | | `presale` | Early access or presale offers | | `perks` | Vouchers and extras (e.g., drink coupons, merchandise credits) | ### Product Configuration Products offer fine-grained control over distribution and usage: | Field | Description | Default | | --------------------- | ---------------------------------------------------------------------- | --------- | | `stock` | Total available inventory. `null` for unlimited. | Unlimited | | `max_per_account` | Maximum items a single user can hold. `null` for unlimited. | Unlimited | | `redemption_quantity` | Number of times each item can be redeemed before it is fully consumed. | 1 | | `is_transferable` | Whether items can be transferred between users. | `false` | | `is_claimable` | Whether items can be claimed via a direct URL. | `false` | | `min_rep_balance` | Minimum reputation balance required to receive an item. | 0 | | `max_items` | Maximum items in the collection. `null` for unlimited. | Unlimited | | `active` | Whether the product is currently active and items can be issued. | `true` | ### Product Items A **product item** is a single instance of a product issued to a user. Each item has: * A unique sequential `item_id` (also used as the NFT ID if minted) * A `redemption_count` tracking how many times it has been redeemed * An `is_fully_redeemed` flag indicating whether all redemptions have been used * Owner information (user ID, email, name) Items can be issued in bulk — up to **550 users per request** — by providing user IDs, email addresses, or a mix of both. ### Redemption Redeeming an item increments its `redemption_count`. Once the count reaches the product's `redemption_quantity`, the item is marked as fully redeemed and cannot be redeemed again. This supports both single-use items (e.g., event tickets) and multi-use items (e.g., a voucher valid for 3 drinks). ### Transfers When a product has `is_transferable` set to `true`, items can be transferred between users. Transfers are subject to the following rules: * The sender must be the current owner of the item * The item must not be fully redeemed * The recipient must be a user in your project * Self-transfers are not allowed * The recipient must not exceed the product's `max_per_account` limit ### NFT Minting Products can optionally mint an NFT for each issued item by setting `mint_nft` to `true`. When enabled: * A `metadata_uri` is required — a URL pointing to a JSON file with `name`, `image`, and `description` fields * A `chain` must be specified: `AssetHub` (Polkadot) or `WestendAssetHub` (testnet) * Your project wallet must hold at least **2 DOT** (AssetHub) or **2 WND** (WestendAssetHub) to cover on-chain fees * Each item's sequential `item_id` is used as the on-chain NFT ID ### Pricing and Sales Products support optional pricing via the `price` field (a decimal string, e.g., `"9.99"`). When products are sold, the Sales endpoint provides paginated access to order history including order numbers, quantities, unit prices, and buyer details. ## Available Endpoints Create a new product with type, pricing, stock limits, and optional NFT minting. Fetch all products for your project with pagination. Retrieve a single product by ID with full configuration details. Issue items to up to 550 users per request by user ID or email. Redeem an item, incrementing its redemption count. Transfer an item from one user to another. Fetch paginated sales history for a product. # Quickstart Source: https://docs.mufi.app/docs/quickstart Go from zero to your first API call in 5 minutes This guide walks you through setting up your Mufi account, creating an organization and project, getting your API key, and making your first API calls. By the end, you'll have created a user with a wallet, set up an event, and issued a product. ## Prerequisites * A [Mufi Dashboard](https://my.mufi.app) account (email [connect@mufi.app](mailto:connect@mufi.app) if you need access) * A tool to make HTTP requests (cURL, Postman, or any HTTP client) ## Step 1: Get Your API Key Go to [my.mufi.app](https://my.mufi.app) and sign in with your email. You'll receive a one-time code to authenticate. Once logged in, create a new organization. Organizations are the top-level entity that groups your projects, team members, and fans. Inside your organization, create a new project. Each project has its own set of users, events, products, and API keys. Navigate to the API Keys section in your project settings and generate a new key. Copy it — you'll need it for all API requests. Your API key does not expire automatically. Store it securely in an environment variable — never hardcode it in your application or commit it to version control. ## Step 2: Set Up Your Environment Store your API key as an environment variable: ```bash theme={null} export MUFI_API_KEY="your-api-key-here" ``` Verify your connection by checking the API version: ```bash cURL theme={null} curl -H "Authorization: Bearer $MUFI_API_KEY" \ https://api.mufi.app/v1/version ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.mufi.app/v1/version', { headers: { 'Authorization': `Bearer ${process.env.MUFI_API_KEY}` } }); const data = await response.json(); console.log(data); ``` ```python Python theme={null} import os, requests response = requests.get('https://api.mufi.app/v1/version', headers={ 'Authorization': f'Bearer {os.getenv("MUFI_API_KEY")}' }) print(response.json()) ``` ```json Response theme={null} { "version": "2.72.0" } ``` **Using the staging environment?** Replace `api.mufi.app` with `dev.api.mufi.app` for testing. All API Playground examples in these docs point to the staging URL. ## Step 3: Create Your First User Create a user — Mufi automatically provisions a custodial Polkadot wallet for them in the background. ```bash cURL theme={null} curl -X POST https://api.mufi.app/v1/users/create \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '[{ "email": "fan@example.com", "firstName": "Alex", "lastName": "Rivera", "referenceId": "your-internal-id-123" }]' ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.mufi.app/v1/users/create', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.MUFI_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify([{ email: 'fan@example.com', firstName: 'Alex', lastName: 'Rivera', referenceId: 'your-internal-id-123' }]) }); ``` ```python Python theme={null} import os, requests response = requests.post('https://api.mufi.app/v1/users/create', headers={ 'Authorization': f'Bearer {os.getenv("MUFI_API_KEY")}', 'Content-Type': 'application/json' }, json=[{ 'email': 'fan@example.com', 'firstName': 'Alex', 'lastName': 'Rivera', 'referenceId': 'your-internal-id-123' }] ) ``` ```json Response theme={null} { "message": "Created" } ``` **Batch creation:** You can create up to 1,500 users in a single request by adding more objects to the array. Wallets are provisioned asynchronously — users are available immediately while wallets generate in the background. ## Step 4: Activate the User Users must be activated before they can hold assets, redeem products, or attend events. ```bash cURL theme={null} curl -X POST https://api.mufi.app/v1/users/activate \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "fan@example.com" }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.mufi.app/v1/users/activate', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.MUFI_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'fan@example.com' }) }); ``` ```python Python theme={null} response = requests.post('https://api.mufi.app/v1/users/activate', headers={ 'Authorization': f'Bearer {os.getenv("MUFI_API_KEY")}', 'Content-Type': 'application/json' }, json={'email': 'fan@example.com'} ) ``` ```json Response theme={null} { "isActivated": true, "activatedOn": "2025-03-17T12:00:00.000Z" } ``` ## Step 5: Create an Event Events are the parent entity for products. Create one to start issuing tickets, vouchers, and perks. ```bash cURL theme={null} curl -X POST https://api.mufi.app/v1/events/create \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Summer Music Festival", "description": "An unforgettable weekend of live music", "location": "Miami, FL", "address": "123 Ocean Drive, Miami, FL 33139", "start_date": 1756684800, "end_date": 1756857600, "reference_id": "festival-2025" }' ``` ```javascript JavaScript theme={null} const event = await fetch('https://api.mufi.app/v1/events/create', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.MUFI_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Summer Music Festival', description: 'An unforgettable weekend of live music', location: 'Miami, FL', address: '123 Ocean Drive, Miami, FL 33139', start_date: 1756684800, end_date: 1756857600, reference_id: 'festival-2025' }) }).then(r => r.json()); ``` ```python Python theme={null} event = requests.post('https://api.mufi.app/v1/events/create', headers={ 'Authorization': f'Bearer {os.getenv("MUFI_API_KEY")}', 'Content-Type': 'application/json' }, json={ 'name': 'Summer Music Festival', 'description': 'An unforgettable weekend of live music', 'location': 'Miami, FL', 'address': '123 Ocean Drive, Miami, FL 33139', 'start_date': 1756684800, 'end_date': 1756857600, 'reference_id': 'festival-2025' } ).json() ``` ```json Response theme={null} { "id": "event-uuid", "name": "Summer Music Festival", "description": "An unforgettable weekend of live music", "reference_id": "festival-2025", "location": "Miami, FL", "address": "123 Ocean Drive, Miami, FL 33139", "start_date": 1756684800, "end_date": 1756857600 } ``` ## Step 6: Create a Product and Issue Items Create a ticket product for your event, then issue it to your user. ```bash cURL theme={null} curl -X POST https://api.mufi.app/v1/products \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "admission", "name": "General Admission", "description": "2-day festival access", "price": "49.99", "stock": 500, "max_per_account": 2, "is_transferable": true, "event_id": "EVENT_ID_FROM_STEP_5" }' ``` ```javascript JavaScript theme={null} const product = await fetch('https://api.mufi.app/v1/products', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.MUFI_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'admission', name: 'General Admission', description: '2-day festival access', price: '49.99', stock: 500, max_per_account: 2, is_transferable: true, event_id: event.id }) }).then(r => r.json()); ``` ```python Python theme={null} product = requests.post('https://api.mufi.app/v1/products', headers={ 'Authorization': f'Bearer {os.getenv("MUFI_API_KEY")}', 'Content-Type': 'application/json' }, json={ 'type': 'admission', 'name': 'General Admission', 'description': '2-day festival access', 'price': '49.99', 'stock': 500, 'max_per_account': 2, 'is_transferable': True, 'event_id': event['id'] } ).json() ``` Then issue the ticket to your user: ```bash cURL theme={null} curl -X POST https://api.mufi.app/v1/products/PRODUCT_ID/items \ -H "Authorization: Bearer $MUFI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "PRODUCT_ID", "emails": ["fan@example.com"] }' ``` ```javascript JavaScript theme={null} const items = await fetch(`https://api.mufi.app/v1/products/${product.id}/items`, { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.MUFI_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ product_id: product.id, emails: ['fan@example.com'] }) }).then(r => r.json()); ``` ```python Python theme={null} items = requests.post(f'https://api.mufi.app/v1/products/{product["id"]}/items', headers={ 'Authorization': f'Bearer {os.getenv("MUFI_API_KEY")}', 'Content-Type': 'application/json' }, json={ 'product_id': product['id'], 'emails': ['fan@example.com'] } ).json() ``` ```json Response theme={null} { "items": [{ "id": "item-uuid", "created_at": "2025-03-17T12:05:00.000Z", "updated_at": "2025-03-17T12:05:00.000Z", "product_id": "product-uuid", "item_id": 1, "redemption_count": 0, "redemption_quantity": 1, "is_fully_redeemed": false, "redeemed_at": null, "user": { "id": "user-uuid", "email": "fan@example.com", "first_name": "Alex", "last_name": "Rivera" }, "product": { "id": "product-uuid", "name": "General Admission", "type": "admission", "redemption_quantity": 1 } }] } ``` ## What You've Built In just a few steps, you've completed the core Mufi integration flow: 1. **Set up your organization and project** with an API key 2. **Created a user** with an automatic custodial Polkadot wallet 3. **Activated them** for full platform access 4. **Created an event** with location and dates 5. **Created a product** (admission ticket) linked to your event 6. **Issued the ticket** to your user From here, you can: * [Redeem items](/docs/endpoint/engagement/redeem-product-item) at event check-in * [Transfer items](/docs/endpoint/engagement/transfer-product-item) between users * [Register attendees](/docs/endpoint/engagement/event-attendee-registration) and track check-ins * [Mint NFTs](/docs/products/introduction#nft-minting) for collectible products * [Check wallet balances](/docs/endpoint/wallets/get-wallet-balances) on-chain ## Next Steps Deep dive into user management, batch operations, and wallet provisioning. Learn about the full event lifecycle and attendee management. Explore product types, NFT minting, redemptions, and transfers. Understand how Mufi protects wallet secrets at scale. # Introduction Source: https://docs.mufi.app/docs/users/introduction Create and manage users with custodial wallets on the Polkadot network The Users API lets you create, manage, and query users associated with your project. Each user is automatically provisioned a custodial wallet on the Polkadot network using Shamir's Secret Sharing, enabling them to interact with web3 applications through a familiar web2 experience. ## Key Concepts ### User Lifecycle 1. **Creation** — Register users by email (individually or in bulk up to 1,500 per request). A custodial wallet is asynchronously generated for each user. 2. **Activation** — Activate users to enable wallet features such as holding assets, redeeming products, and attending events. 3. **Engagement** — Once active, users can receive product items, register for events, check in at venues, and hold on-chain assets. ### User Identification Users can be identified in API requests using three methods, applied in the following priority order: | Priority | Identifier | Description | | -------- | ------------- | ---------------------------------------------- | | 1 | `email` | The user's unique email address | | 2 | `referenceId` | A custom ID to link users to your own database | | 3 | `id` | The Mufi-generated UUID | This flexible lookup system means you can integrate seamlessly with your existing user database by mapping your internal IDs via the `referenceId` field. ### Wallets Each user receives a custodial Polkadot wallet upon creation. Users can also connect their own non-custodial wallets for additional security. Wallets support: * **On-chain asset balances** — Query token holdings and locked amounts across supported chains * **Custodial and non-custodial** — Both custody types are returned when fetching user profiles * **Project-level queries** — Retrieve all wallets across your entire project for reporting ### Batch Operations The Create User endpoint supports batch creation of up to **1,500 users per request**. Wallet generation happens asynchronously after creation, so users are immediately available in the system while their wallets are being provisioned in the background. ## Available Endpoints ### Users Endpoints Register new users (1–1,500 per request) with automatic wallet provisioning. Retrieve a single user's profile including wallet addresses and custody types. List multiple users with pagination and optional filtering by email, reference ID, or user ID. Activate a user to enable wallet features and product interactions. Check whether a user has been activated and when. Query on-chain asset balances across all of a user's wallets. Get the total number of active users in your project. ### Projects Endpoints Retrieve all wallets across your entire project with wallet type and custody details. # Authentication Source: https://docs.mufi.app/docs/wallet-api/authentication How to authenticate your API requests and manage API keys All Mufi API requests are authenticated using **Bearer tokens**. Your API key acts as a JWT-signed token that identifies your project and permission level. ## Getting Your API Key Go to [my.mufi.app](https://my.mufi.app) and authenticate with your email via magic link. Each project has its own users, events, products, and API keys. Navigate to the API Keys section and generate a new key. You'll receive a JWT token to use in your API requests. Don't have an account? Email [connect@mufi.app](mailto:connect@mufi.app) to request access. ## Using Your API Key Include your API key as a Bearer token in the `Authorization` header of every request: ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ```bash cURL theme={null} curl -H "Authorization: Bearer $MUFI_API_KEY" \ https://api.mufi.app/v1/version ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.mufi.app/v1/version', { headers: { 'Authorization': `Bearer ${process.env.MUFI_API_KEY}` } }); ``` ```python Python theme={null} import os, requests response = requests.get('https://api.mufi.app/v1/version', headers={ 'Authorization': f'Bearer {os.getenv("MUFI_API_KEY")}' }) ``` ## Permission Levels Each API key has one of two permission levels: | Permission | What it allows | | ---------- | -------------------------------------------------------------------------- | | **Write** | Full access — create and modify users, events, products, and all resources | | **Read** | Query-only — fetch users, list events, check balances, view products | Calling a write-only endpoint with a read-only key returns `403 Forbidden`. ## Key Management | Behavior | Detail | | ----------------- | ----------------------------------------------------------------------------------------------- | | **Expiration** | API keys do not expire automatically — they remain valid until revoked | | **Regeneration** | You can regenerate a key at any time from the Dashboard. The old key is immediately invalidated | | **Multiple keys** | Generate separate keys for different environments (staging, production) or services | ## Security Checklist Store API keys in environment variables, never in source code Use keys only on the server side — never expose them in frontend code Use read-only keys when you only need to query data Regenerate keys immediately if you suspect they've been compromised Use separate keys for staging and production environments If your API key is compromised, regenerate it immediately from the [Mufi Dashboard](https://my.mufi.app) or email [connect@mufi.app](mailto:connect@mufi.app) for emergency revocation. # Custodians Source: https://docs.mufi.app/docs/wallet-api/custodians Learn how Mufi manages your wallet secrets Custodians are multiple API services hosted across different regions to store parts of a wallet secret. The Provisioner uses Shamir's Secret Sharing to split and encrypt parts of a wallet secret and shares different parts with all Custodians, which each re-encrypt those parts with their own encryption keys before storing them. Having Custodians hosted in multiple regions has a few benefits: * Security through Isolation: By placing each custodian (with its own VPC, database, and encryption key) in different regions, we ensure physical separation. This reduces the risk of a single point of failure and makes it more difficult for an attacker to compromise all custodians at once. * Compliance: In some cases, storing sensitive data across multiple regions helps meet geographic and compliance requirements (e.g., GDPR and data sovereignty laws). * Resilience: Distributing across regions increases fault tolerance. Even if one region goes down, the rest of the custodians remain accessible and the full wallet secret can be re-created with a minimum threshold of secret parts. This does come at the cost of latency, but increased security and resilience justifies this cost. Blockchain transactions have an even greater latency due to block times so users should not feel any additional latency when re-creating their secrets to sign a transaction. Transactions should be asynchronous. ## Platform Separation Custodians are hosted on a different platform service (AWS) than Provisioner (GCP), the only privileged client of Custodians. This adds a layer of security so that even if the Custodian platform account is compromised the secret parts stored in those databases are still encrypted from a secret in GCP. All parties must cooperate to recover the full wallet secret. ## Double Encryption and Key Rotation Custodians receive encrypted parts of a wallet secret. Custodians encrypt that data once more before saving the blob to the database. At no point is the full secret stored in a single location. Custodians also use periodic encryption key rotation. ## Authentication and IP Whitelisting Custodians have their own authentication tokens and have a whitelist of allowed callers by checking the IP address. The Provisioner API is the only whitelisted caller. No MuFi member will have access in production. # Wallets API Source: https://docs.mufi.app/docs/wallet-api/introduction Custodial and non-custodial wallet management for the Polkadot network The Wallets API is the foundation of the Mufi platform. It provides custodial Polkadot wallets for your users — provisioned automatically, secured with Shamir's Secret Sharing, and managed entirely through a REST API. No blockchain knowledge required. Users can also connect their own non-custodial wallets for an even more trustless experience. ## How It Works Call the [Create User](/docs/endpoint/wallets/create-user) endpoint with an email address. Mufi creates the user record immediately. A custodial Polkadot wallet is generated asynchronously. The secret is split using Shamir's Secret Sharing and distributed across isolated custodians — no full secret is ever stored in one place. Call the [Activate User](/docs/endpoint/wallets/activate-user) endpoint. Once active, the user can hold assets, receive products, and attend events. Issue products, check balances, register for events — all through standard REST endpoints with your API key. ## Base URLs | Environment | URL | | -------------- | -------------------------- | | **Production** | `https://api.mufi.app` | | **Staging** | `https://dev.api.mufi.app` | All API Playground examples in these docs use the staging URL. When going live, simply replace `dev.api.mufi.app` with `api.mufi.app`. ## Authentication All API endpoints require a Bearer token — your API key from the [Mufi Dashboard](https://my.mufi.app). ```bash cURL theme={null} curl -H "Authorization: Bearer $MUFI_API_KEY" \ https://api.mufi.app/v1/version ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.mufi.app/v1/version', { headers: { 'Authorization': `Bearer ${process.env.MUFI_API_KEY}` } }); ``` ```python Python theme={null} import os, requests response = requests.get('https://api.mufi.app/v1/version', headers={ 'Authorization': f'Bearer {os.getenv("MUFI_API_KEY")}' }) ``` Store your API key in environment variables. Never hardcode it or expose it on the client side. See [Authentication](/docs/wallet-api/authentication) for more details. ## API Key Permissions API keys have one of two permission levels: | Permission | Access | | ---------- | ------------------------------------------------------------------ | | **Write** | Full access — create users, events, products, and modify resources | | **Read** | Query-only — fetch users, list events, check balances | Write-only endpoints will return `403 Forbidden` if called with a read-only key. ## Conventions ### Request Format * All request bodies use **JSON** with `Content-Type: application/json` * V1 endpoints use **snake\_case** for field names * Prices are **decimal strings** (e.g., `"49.99"`) to avoid floating point issues * Timestamps are **Unix seconds** (integer) * IDs are **UUIDs** (v4) ### User Identification Users can be identified by any of these fields (in priority order): | Priority | Field | Description | | -------- | ------------- | ------------------------------------------------- | | 1 | `email` | The user's unique email address | | 2 | `referenceId` | Your custom ID to link users to your own database | | 3 | `id` | The Mufi-generated UUID | ### Pagination List endpoints accept `page` (1-indexed) and `limit` parameters. Maximum limits vary by endpoint. ## Standard Errors | Status | Error | Description | | ------ | ----------------------- | ------------------------------------------------------------------- | | `400` | `invalid_request` | Missing or malformed parameter | | `401` | `unauthorized` | Missing or invalid API key | | `403` | `forbidden` | Insufficient permissions (e.g., read-only key on a write endpoint) | | `404` | `not_found` | Resource does not exist | | `422` | `unprocessable_entity` | Validation error (e.g., insufficient stock, user already activated) | | `500` | `internal_server_error` | Something went wrong on our end | ## Deep Dive API key management, permission levels, and security best practices. How Shamir's Secret Sharing, VPC isolation, and multi-region custodians protect wallet secrets. How secret parts are distributed, encrypted, and stored across isolated services. Attach self-managed non-custodial wallets to Mufi accounts. # Bring Your Own Wallet Source: https://docs.mufi.app/docs/wallet-api/noncustodial Learn how to attach your non custodial wallet The Mufi API allows users to attach their own non custodial wallets to their Mufi accounts to enable interacting with the API is an even more trustless way. To connect your wallet to your account simply log into your account at [Mufi Dashboard](https://my.mufi.app) and follow the steps to securely attach your own wallet. Once attached you will see your wallet in the dashboard and be able to manage connected wallets. Free tier users are able to attach a max of 4 non custodial wallets to their accounts. # Security Source: https://docs.mufi.app/docs/wallet-api/security Learn how Mufi keeps your assets secure MuFi aims to serve millions of users by offering a custodial wallet solution that simplifies wallet management for those who are not concerned with decentralization or managing their own wallet secrets. This solution introduces several key security challenges: * Secure Secret Generation * Secure Secret Storage * Secure Signatures ## Polkadot-First Approach with sr25519 Signatures As a Polkadot-first company, we prioritize sr25519 signatures. While threshold signature generation is still developing for many signature algorithms like ed25519, it is not yet fully established for sr25519. Therefore, we generate secrets using polkadot-js in combination with Shamir's Secret Sharing (SSS). Polkadot offers proxy accounts and multi-sig features, however both of these require 20+ DOT deposits, and each multi-sig transaction requires an additional 20+ DOT refundable deposit per transaction. These requirements do not scale to millions of users, and many users who only want to redeem a drink coupon will not be willing to deposit 20 DOT for a \$5 drink. We may consider using multi-sig and proxy accounts in the future when we support high-value assets where this makes sense. ## Shamir's Secret Sharing (SSS) SSS allows us to split a secret into n parts, requiring a threshold t/n to reconstruct the secret. This method enhances resilience, ensuring that even if some secret custodians are compromised, t parts are still sufficient to maintain system security and operation. ## Secure Polkadot Wallet Management System We have implemented a secure system for managing Polkadot wallets, ensuring the highest level of security and integrity for sr25519 signatures. Below is an overview of our architecture and security measures. ## Architecture Overview ### Shamir's Secret Sharing (SSS) Implementation We use Shamir's Secret Sharing (SSS) to split cryptographic secrets needed for sr25519 signatures into multiple parts, distributing them across isolated services. This ensures no single service holds the complete secret, providing robust protection against potential compromises. ### VPC-Protected Signer Service Our Signer service, responsible for generating sr25519 signatures and signing, operates within a secure Virtual Private Cloud (VPC), isolated from public access. Only the Gateway API can communicate with it, safeguarding sensitive operations like signing transactions from external threats. ### Gateway API with JWT Authentication The Gateway API, exposed via a public IP, serves as the entry point for B2B interactions. We have implemented JSON Web Token (JWT) authentication to ensure that only authorized clients can access the Gateway API, adding an additional layer of security against unauthorized access. ### Secure Communication and Access Control Communication between the Gateway API and the Signer service is secured with strong authentication and encrypted channels. Strict access controls allow the Gateway API the least privilege necessary to interact with the Signer service, minimizing risks even if the Gateway API is exposed. ### Secure Secret Storage in PostgreSQL For storing millions of secrets, services like KMS are limited by a max of 1 million keys and are very expensive at scale (cost per key). We employ the following approach using PostgreSQL: * Strong Encryption: Each secret is individually encrypted with a strong algorithm (e.g., AES-256) before storage in PostgreSQL. * Key Management: Encryption keys are securely managed through a dedicated KMS, with periodic rotation and secure handling. * Database Security: The PostgreSQL database is hardened, with encryption at rest and in transit, strict access controls, and regular security patches. * Isolated Services: Each service holding a part of the secret is isolated with strong access controls to mitigate risks. ## Additional Security Measures * Rate Limiting & IP Whitelisting: Rate limiting is enforced on the Gateway API to prevent abuse, and IP whitelisting restricts access to trusted partners only. * Web Application Firewall (WAF): A WAF filters out malicious traffic and protects against common web vulnerabilities. * Auditing & Monitoring: All interactions with the Signer service are logged and monitored for suspicious activities, with regular audits to ensure compliance with security best practices. ## Conclusion By integrating Shamir's Secret Sharing, a VPC-protected Signer service, and a JWT-authenticated Gateway API, alongside secure secret storage in PostgreSQL, we have created a highly secure environment for managing Polkadot wallets and generating sr25519 signatures. This architecture safeguards against unauthorized access and potential compromises, ensuring the integrity and security of the entire signing process.