Meimo
Integration guide

Integrating Meimo Cards as a payment method

Your Meimo Business account has a Live API key. This is the complete path from that key to a real customer holding a Meimo Card and spending it down in your product — issuing your own cards, listing what customers can buy in-app, and charging a card at checkout. Four endpoints, no OAuth dance, no separate developer account.

Base URL api.meimopay.comAuth: Bearer API keySDK @meimopay/sdk-node

1. What a Meimo Card is

A Meimo Card is a bearer stored-value instrument — a 16-digit card number and a 4-digit PIN are the entire access credential. Anyone holding both can check its balance and spend it down at checkout, no session or account required, exactly like a gift card.

Private card

Issued by your API key — spendable only through your own business, never at anyone else's.

Global card

Issued by Meimo itself — spendable at any business that opts into accepting global cards.

There's no separate template, brand, or entitlement model to configure — a card just has a tier (Meimo Card, Silver, Gold, Platinum, Black) and a starting balance you set at issuance.

2. Your Live API key

Every Meimo Business account has exactly one sign-in and can hold any number of API keys, in two environments.

  1. 1Sign in to your Business account at app.meimopay.com
    The same phone/KYB-verified sign-in you already use — no separate developer account.
  2. 2Open API Keys
    Generate a key and choose LIVE or SANDBOX. The raw key is shown exactly once — store it in your secrets manager immediately.
  3. 3Use it as a Bearer token
    Every Partner API call is Authorization: Bearer <your key>. No client id/secret or OAuth exchange for server-to-server calls.
A revoked key fails every subsequent request with 401immediately — revoking is the right move the moment a key leaks, not a softer “disable” state.

3. Authenticating requests

Which environment a call touches is decided entirely by which key you send — not a URL flag or request field.

curl
curl https://api.meimopay.com/v1/listings \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxx"

A LIVE key only ever creates and sees real cards; a SANDBOX key's cards are tagged isSandbox: true and fully isolated from your live view. Build and test your whole integration on a sandbox key first — the request/response shapes are identical.

4. Issuing a card

Mint a fresh private card, locked to your own business. The raw card number and PIN are only ever returned here, once — hand them to whoever will use the card (a gift, a physical card, an SMS).

Node SDK
import { MeimoPayClient } from "@meimopay/sdk-node";

const meimo = new MeimoPayClient({ apiKey: process.env.MEIMO_LIVE_KEY! });

const card = await meimo.issueCard({ tier: "MEIMO_CARD", balanceCents: 2000 });
// card.cardNumber and card.pin are shown here, once — save or hand them off now
curl
curl -X POST https://api.meimopay.com/v1/cards \
  -H "Authorization: Bearer sk_live_xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "tier": "MEIMO_CARD",
    "balanceCents": 2000
  }'

A card issued through the API is the exact same row your Business Portal and the Meimo admin panel see — there's no separate “API card” bucket. It shows up immediately under Cards → Cards you've issued.

5. What you can sell in-app

A listing is a price sheet, not inventory — buying one mints a brand-new card on the spot with that listing's tier and balance. This call returns your own listings, plus every active global listing if your business has opted into accepting global cards.

CallReturns
GET/v1/listingsYour own active listings, plus global listings if you accept global cards
Node SDK
const listings = await meimo.listListings();
// each listing: { id, title, tier, balanceCents, priceCents, isGlobal, ... }

Listings themselves are managed from the Business Portal's Cards page (create, price, activate/deactivate) — the Partner API only reads them, since a listing is a storefront concern, not something you'd script per-request.

6. Charging a card at checkout

Your customer hands you a card number + PIN at checkout — from a gift, a purchase, or a card they already hold. Debit it directly; the merchant charging is always resolved from your own API key, never from the request body.

Node SDK
const result = await meimo.pay({
  cardNumber: "6602000000000017",
  pin: "4821",
  amountCents: 1840,
  idempotencyKey: "order_9931-pay", // safe to retry with the same key
});
// result.remainingBalanceCents is the balance AFTER this charge
curl
curl -X POST https://api.meimopay.com/v1/cards/pay \
  -H "Authorization: Bearer sk_live_xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "cardNumber": "6602000000000017",
    "pin": "4821",
    "amountCents": 1840,
    "idempotencyKey": "order_9931-pay"
  }'

Rejects with CARD_NOT_ACCEPTED if the card is neither yours nor a global card you accept, INSUFFICIENT_FUNDS if the balance is too low, and CARD_EXPIRED past its validity window. Always pass a stable idempotencyKey — a repeated call with the same key returns the original result instead of double-charging.

7. Checking a balance

A pure bearer lookup — card number + PIN is the entire auth, no API key required. Handy for showing a balance before a customer commits to checkout.

CallNotes
POST/cards/balancePublic — no Authorization header at all, just the card number + PIN in the body
Node SDK
const balance = await meimo.checkBalance("6602000000000017", "4821");
// { tier, balanceCents, currency, status, isGlobal, businessId, expiresAt }

8. Sandbox vs Live

One account, one API, two key types — not two separate systems to keep in sync.

Sandbox key

Every card issued is tagged isSandbox: true and invisible in your live dashboards.

Live key

Real cards, real customers, real balances. Nothing about the request shape changes — only which key you send.

Recommended order: build the whole flow (issue → pay → balance check) against a sandbox key, confirm it behaves the way you expect, then swap in the live key with zero code changes.

9. Errors

Every non-2xx response is JSON with a message field; the SDK throws MeimoPayApiError with the status and body attached.

StatusMeaning
401Missing, invalid, or revoked API key — or an incorrect PIN on a balance/pay lookup
402INSUFFICIENT_FUNDS — the card's balance is too low for the requested amount
403CARD_NOT_ACCEPTED — the card is neither yours nor a global card you accept
404Unknown card number
410CARD_EXPIRED — past its validity window
409Card is not ACTIVE (already blocked, depleted, or closed)

10. Go-live checklist

The section to hand your engineer directly.

Full API reference

Every endpoint, request/response shape, and error code — generated straight from the live API, always current.

Open the API docs →

Questions building something? Get in touch or back to Developers.