Skip to main content

Merchant automation (REST)

The Node SDK is the recommended path, but every partner operation is a plain HTTP call. This page is the route reference for backends in any language. All write calls require your Partner Key (tp_sk_partner_live_… / tp_sk_partner_test_…), minted in the Partner Hub. The routes split along the platform’s two domains:
DomainBase URLProvisions
CRMhttps://api.tagada.io/api/public/v1/partnermerchants (acc_xxx) + CRM Keys (sk_crm_…)
Processinghttps://api.tagada.io/api/tagadapay/v1/partnerTPAs (tpa_xxx) + Processing Keys (tp_sk_…)
There is no cross-partner access — every call is scoped to your par_xxx.

Authentication

Authorization: Bearer tp_sk_partner_live_…
Only Partner Keys can provision merchants/TPAs or mint keys on their behalf. Scoped keys (CRM/Processing) cannot provision.
A test Partner Key can only mint test keys. Minting a live key with a test Partner Key returns 403 mode_escalation_forbidden.

CRM domain — merchants & CRM Keys

Base: /api/public/v1/partner
MethodPathDescription
POST/merchantsCreate a merchant (acc_xxx). CRM-only is valid. Idempotent on externalRef.
GET/merchantsList merchants. ?externalRef=… to look one up, ?limit=&cursor= to page.
GET/merchants/:accIdRetrieve a merchant.
POST/merchants/:accId/keysMint a CRM Key — token (sk_crm_…) returned once.
GET/merchants/:accId/keysList CRM Keys (prefix only).
DELETE/keys/:keyIdRevoke a CRM Key.
# Create a merchant
curl -X POST https://api.tagada.io/api/public/v1/partner/merchants \
  -H "Authorization: Bearer tp_sk_partner_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "legalName": "Acme SAS", "externalRef": "merchant_42", "country": "FR", "currency": "EUR" }'

# Mint a CRM Key for it
curl -X POST https://api.tagada.io/api/public/v1/partner/merchants/acc_xxx/keys \
  -H "Authorization: Bearer tp_sk_partner_live_…"
# → { "object": "crm_key", "id": "…", "merchantId": "acc_xxx", "token": "sk_crm_live_…", ... }

Processing domain — TPAs & Processing Keys

Base: /api/tagadapay/v1/partner
MethodPathDescription
POST/tpasCreate a TPA (merchantId in body). Idempotent on externalRef.
GET/tpasList TPAs. ?merchantId=&externalRef=&limit=&cursor=.
GET/tpas/:tpaIdRetrieve a TPA.
PATCH/tpas/:tpaIdRe-point the TPA to another store of the same merchant ({ storeId }). Only mutation available.
GET/tpas/:tpaId/requirementsList KYB requirements.
PATCH/tpas/:tpaId/requirements/:codeSubmit a value for a non-document requirement ({ value }). Flips it to pending_verification.
GET/tpas/:tpaId/documentsList KYB documents.
POST/tpas/:tpaId/documentsRecord a KYB document (metadata).
POST/tpas/:tpaId/keysMint a Processing Key — secret (tp_sk_…) returned once.
GET/tpas/:tpaId/keysList Processing Keys (prefix only).
DELETE/keys/:keyIdRevoke a Processing Key.
# Create a TPA for an existing merchant
curl -X POST https://api.tagada.io/api/tagadapay/v1/partner/tpas \
  -H "Authorization: Bearer tp_sk_partner_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "merchantId": "acc_xxx", "externalRef": "merchant_42_eu", "country": "FR", "currency": "EUR" }'

# Mint a Processing Key for it
curl -X POST https://api.tagada.io/api/tagadapay/v1/partner/tpas/tpa_xxx/keys \
  -H "Authorization: Bearer tp_sk_partner_live_…"
# → { "object": "processing_key", "id": "ak_xxx", "tpaId": "tpa_xxx", "secret": "tp_sk_live_…", ... }
Direct (non-partner) merchants use the same Processing routes without the /partner segment — e.g. POST /api/tagadapay/v1/tpas — authenticated with their own Processing Key. The /partner prefix is what marks an “on behalf of” call.

Target exists and belongs to you

Every mint/list/revoke validates the target before acting:
  1. The merchant/TPA exists — else 404 (merchant_not_found / tpa_not_found).
  2. It belongs to your partnership — else 403 (merchant_access_denied / tpa_access_denied).
You cannot mint keys for something you have not provisioned. Create it first, then mint on the returned id.

Common error responses

HTTPCodeWhen
401missing_api_keyNo Authorization: Bearer header
401invalid_api_keyUnknown or revoked key
403partner_scope_requiredNot a Partner Key (e.g. a scoped key used to provision)
403merchant_access_denied / tpa_access_deniedTarget belongs to another partner
403mode_escalation_forbiddenTest Partner Key minting a live key
404merchant_not_found / tpa_not_foundTarget id does not exist
404api_key_not_foundRevoke target not found or already revoked

your_merchants table:
  external_ref          → externalRef / Idempotency-Key on create
  tagada_merchant_id    → acc_xxx                (CRM)
  tagada_crm_key        → encrypted sk_crm_live_…
  tagada_tpa_id         → tpa_xxx                (Processing)
  tagada_store_id       → store_xxx
  tagada_processing_key → encrypted tp_sk_live_…
Store secrets in your vault immediately — token/secret cannot be retrieved later.

End-to-end (SDK)

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

// 1. CRM: create the merchant + a CRM Key
const merchant = await partner.partners.crm.merchants.create({
  legalName: 'Acme SAS',
  externalRef: 'merchant_42',
});
const crmKey = await partner.partners.crm.merchants.keys.create(merchant.id);

// 2. Processing: create a TPA bound to that merchant + a Processing Key
const tpa = await partner.partners.processing.tpas.create({
  merchantId: merchant.id,
  externalRef: 'merchant_42_eu',
  country: 'FR',
  currency: 'EUR',
});
const processingKey = await partner.partners.processing.tpas.keys.create(tpa.id);

// 3. Persist on your side
await yourVault.put(merchant.externalRef ?? merchant.id, {
  crmKey: crmKey.token,
  processingKey: processingKey.secret,
  storeId: tpa.storeId,
});
This is the pattern any embedded PSP, marketplace, or whitelabel partner should follow — not a one-off integration.