Customers

Plugipay portal: customers

A customer is a persistent record of someone who can pay you. The Customers page is the address book that sits underneath every payment, subscription, and invoice in your workspace — browse it, open a single customer to see their history, edit details.

You don't have to create a customer to take money — a guest checkout works fine. But the moment you want to charge the same person twice, store a card for a subscription, or send a follow-up receipt, a customer record keeps those payments hanging off one identity instead of floating around orphaned.

Rule of thumb. If someone is going to pay you more than once, give them a customer record the first time. They're free, they don't expire, and you can ignore them later.

What a customer holds

Every customer has the same shape, whether you create them from the portal or the API:

Field What it's for
id Plugipay-assigned, looks like cus_01H…. Stable forever.
externalId Your own ID for the same person — e.g. your CRM's user_id. Unique per workspace.
email Primary contact. Used on receipts and as a soft duplicate hint.
name Display name on receipts and the dashboard.
phone Optional. Used by some providers (e-wallets, OVO, GoPay) to look up the account.
taxId NPWP / VAT number. Appears on invoices when set.
defaultPaymentTokenId The stored card or e-wallet to charge by default.
metadata Up to 50 key-value string pairs of your own data.

Identifiers carry their type as a prefix — see Concepts → Identifiers for the full list.

The list view

From the dashboard sidebar, click Customers. You'll land at /dashboard/customers.

The header reads "Everyone who's ever paid you, pending, or has an active subscription." Both customers you've created manually and customers auto-created by a checkout flow show up here.

Columns

  • Customer — generated avatar (initials of name or email) plus display name. If no name is set, the cus_… ID stands in.
  • Email — primary email, or an em-dash if blank.
  • External ID — your own ID for the customer, if you set one.
  • Created — short date stamp.

Filtering and search

The list supports filtering by exact email via the ?email= query parameter — for example, /dashboard/customers?email=alice@example.com. We use this for deep-links from other portal pages.

A full search bar with fuzzy matching, sort controls, and date-range picker isn't in the portal yet. To find a customer by partial email, name, or externalId, use the API:

curl https://api.plugipay.com/v1/customers \
  -u sk_live_xxx: \
  --data-urlencode 'email=alice@example.com'

See API → Customers for the full query surface.

Pagination

The list shows 50 customers per page and paginates with a cursor (not page numbers). The footer has Next when another page is available and First page to jump back. The cursor lives in the URL, so bookmarks resume where you left off.

Creating a customer

Not currently in the portal. A "New customer" button and manual form are on the roadmap but not shipped. For now, customers arrive via auto-creation or the API.

Two paths today:

  1. Auto-creation through checkout. When a checkout session completes for a fresh email, Plugipay creates the customer record automatically — the address book fills itself.
  2. API call. For existing lists (a previous processor or your CRM), POST each record to /v1/customers. See API → Customers → Create.

Customer detail page

The detail page (history, edit, tabs for payments / subscriptions / invoices) is not currently in the portal. The data is all there via the API; the dedicated UI page is queued.

When it ships it will include a header (name, email, lifetime revenue, customer-since), tabs for Payments, Subscriptions, and Invoices, a Metadata panel, plus edit and archive actions. Until then, combine GET /v1/customers/{id} with GET /v1/payments?customerId=… and GET /v1/subscriptions?customerId=… to assemble the same view.

Editing a customer

Edits happen via PATCH /v1/customers/{id} today. Every field except id is updateable. Updates are idempotent — pass an Idempotency-Key header to make retries safe. Inline edits will land with the detail page.

Metadata

Every customer carries an optional metadata map — up to 50 key-value pairs, with string values. Use it for anything Plugipay doesn't have a column for:

{
  "metadata": {
    "crm_id": "contact_19823",
    "segment": "enterprise",
    "signup_campaign": "spring-2026",
    "referrer": "yc-batch"
  }
}

Three things to know:

  • Metadata is not searchable from the portal. It's stored, it's returned, but you can't filter on it. If you need queryable custom fields, lift them into your own database and reference the customer by id or externalId.
  • Metadata is opaque to webhooks. We pass it through unchanged in event payloads, so downstream systems can read it.
  • Setting metadata to null on update wipes the map. To remove a single key, send the whole map back with that key omitted.

Imports and exports (CSV)

CSV import and export are not currently in the portal. Until they ship, use the API:

# Export via the list endpoint + jq
curl -s https://api.plugipay.com/v1/customers?limit=100 \
  -u sk_live_xxx: \
  | jq -r '.data[] | [.id, .email, .name, .externalId] | @csv' \
  > customers.csv

For bulk import, batch records into POST /v1/customers calls. The Node and JS SDKs include customers.bulkCreate(items) helpers that batch with retry handling.

Common tasks

Find a customer

For an exact email match, use the URL query parameter:

/dashboard/customers?email=alice@example.com

For partial matches, name search, or externalId lookup, fall back to the API for now (see above).

Merge duplicates

Not currently in the portal — or the API. Merging two customer records isn't supported anywhere in Plugipay yet. The safe workaround: PATCH the canonical customer with the right details, then PATCH the duplicate's externalId to something archival like merged-into-cus_01H…. Payments stay on whichever customer they were created against — we don't move them.

If you need true merge semantics (move payments, dedupe stored cards), let us know — it's on the backlog.

Archive

Not currently in the portal. There's no archive flag or soft-delete; customers stay in the list forever. Workaround: set metadata.archived = "true" and filter client-side, or tag retired records via externalId.

Common pitfalls

Email uniqueness

Plugipay does not enforce email uniqueness on customers. You can have two customers with the same email — some businesses serve multiple legal entities through one inbox. Email is a soft hint, never a hard key.

To enforce uniqueness yourself, list by email before POST /v1/customers and skip the create on match.

externalId is unique per workspace — a duplicate fails with 409 Conflict. Use it as your dedupe key.

GDPR delete

There's no DELETE /v1/customers/{id}. Hard delete would cascade dangerously through payments, invoices, and refunds, so we don't expose it.

For an erasure request:

  1. PATCH the customer to clear email, name, and phone.
  2. Strip identifying values from metadata.
  3. Email support@plugipay.com with the customer ID. We run a backend redaction job that scrubs the same fields from related payments, invoices, and webhook payloads.

The customer record stays as a tombstone (it has to, to keep historical payments queryable) but carries no personal data afterwards.

Auto-created customers without names

A customer auto-created by a guest checkout often starts with just an email. They show up in the list with cus_… as the display name. PATCH a real name on them the next time you interact — receipts look much better with one.

See also

Next

Plugipay — Payments that don't tax your success