Skip to main content

CRM provisioning (merchants)

A merchant (acc_xxx) is the CRM organization: it owns stores, products, orders, customers, subscriptions, and CRM Keys. This page covers provisioning merchants and minting CRM Keys on the CRM domain (/api/public/v1/partner/*).
CRM-only is valid. A merchant does not need a TPA. If your product only uses the merchant control plane (catalog, orders, customers, subscriptions) and processes payments elsewhere, you never have to touch the Processing domain. When you do want TagadaPay to process cards, provision a TPA for the merchant afterwards.

Create a merchant

const partner = new Tagada(process.env.TAGADA_PARTNER_KEY!);

const merchant = await partner.partners.crm.merchants.create({
  legalName: 'Acme SAS',
  country: 'FR',                // ISO 3166-1 alpha-2 (optional)
  currency: 'EUR',              // ISO 4217 (optional)
  externalRef: 'merchant_42',   // YOUR id — used for idempotency
  metadata: { plan: 'pro' },
});

// →
// {
//   object: 'merchant',
//   id: 'acc_xxx',
//   legalName: 'Acme SAS',
//   externalRef: 'merchant_42',
//   country: null,        // not stored on the merchant — see note below
//   currency: null,
//   managementMode: 'partner_managed',
//   createdAt: '2026-04-29T…',
// }
Creating a merchant also auto-provisions a default store (store_xxx) so the CRM is immediately usable.
country / currency you pass on create() are provisioning inputscurrency sets the auto-created store’s base currency. They are not stored on the merchant object itself, so the response always returns country: null and currency: null. Read per-store currency back via the CRM stores API.

Idempotency

A second create() with the same externalRef returns the same merchant — retries are safe:
const a = await partner.partners.crm.merchants.create({ legalName: 'Acme', externalRef: 'merchant_42' });
const b = await partner.partners.crm.merchants.create({ legalName: 'Acme', externalRef: 'merchant_42' });
console.log(a.id === b.id); // true
The idempotency key is the (partnerId, externalRef) pair and is permanent. You can also pass it via the Idempotency-Key header — the body value wins.

Retrieve / list

const merchant = await partner.partners.crm.merchants.retrieve('acc_xxx');
const byRef = await partner.partners.crm.merchants.retrieveByExternalRef('merchant_42'); // null if none

const { data, hasMore } = await partner.partners.crm.merchants.list({
  limit: 50,
  cursor: '…',
  externalRef: 'merchant_42', // optional filter
});

Mint a CRM Key

A CRM Key (sk_crm_…) grants access to /api/public/v1/* for this one merchant.
const key = await partner.partners.crm.merchants.keys.create('acc_xxx');
// {
//   object: 'crm_key',
//   id: '…',
//   accountId: 'acc_xxx',
//   prefix: 'sk_crm_live_a1b2…',
//   token: 'sk_crm_live_a1b2c3…',   // RETURNED ONCE — store immediately
//   name: 'Your Partner — merchant_42',
//   createdAt: '2026-04-29T…',
// }

const keys = await partner.partners.crm.merchants.keys.list('acc_xxx');
await partner.partners.crm.merchants.keys.revoke(key.id);
The token is returned only on creation. Store it in your secret manager immediately. Existing UUID tokens keep working — only newly minted keys use the sk_crm_… format.
Use the token as a normal merchant client:
const merchantClient = new Tagada(key.token);    // sk_crm_live_…
const orders = await merchantClient.orders.list();
const customers = await merchantClient.customers.list();
See API keys & authentication for rotation patterns and the full three-key model.

Common errors

HTTPCodeWhen
401missing_api_key / invalid_api_keyNo / unknown / revoked key
403partner_scope_requiredNot a Partner Key (e.g. a CRM/Processing key used to provision)
403merchant_access_deniedMerchant exists but belongs to another partner
404merchant_not_foundacc_xxx does not exist

Next step

Add card processing (TPA)

When this merchant needs to take payments through TagadaPay, provision a TPA bound to its acc_xxx and mint a Processing Key.