> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tagada.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Apply for TagadaPay Processing

> Direct merchants — submit a processing application with processing.applications.create(). Full field reference (required / recommended / optional). Partners use tpas.create() instead.

# Apply for TagadaPay Processing

<Info>
  **Who this is for:** a **direct merchant** who wants TagadaPay to process their cards — the same flow as **Dashboard → New Request** at [dashboard.tagadapay.io](https://dashboard.tagadapay.io).

  **Not a partner?** You're in the right place. Authenticate with a **CRM key** (`sk_crm_…`) and call `processing.applications.create()`.

  **Building a platform for many sub-merchants?** Use the [Partners guide](/developer-tools/partners/introduction) and `partners.processing.tpas.create()` instead — partners never use this endpoint.
</Info>

A **processing application** is how you ask TagadaPay to onboard you as a processor customer. Submit it with a CRM key, it lands in our **review queue**, our team runs KYB, and provisions your TPA.

The payload mirrors the dashboard **"New Request"** form 1:1 — the exact data our acquiring network runs KYB/KYC on. **The more complete and accurate it is, the faster you are approved.**

***

## What you're applying for: a TPA

Approval gives you a **TagadaPay Account — a TPA** (id prefix `tpa_xxx`). The TPA, not your login and not your store, is the object that actually holds **one KYB-approved legal entity**, its **assigned acquirer**, its **settlement bank account**, and its own charging scope.

It sits under your **merchant** account — the thing you log into and hold a single CRM key for:

```
Merchant (acc_xxx)            your Tagada account: one login, one CRM key
  ├── TPA (tpa_xxx)           an approved legal entity that can charge cards
  └── Store (store_xxx)       checkout & payment routing (auto-created)
```

The important part: **one application provisions one TPA**, and a single merchant can own **many** of them (`acc_xxx` → 0..N `tpa_xxx`). See [One merchant, many TPAs](#one-merchant-many-tpas) for why you'd want that and how to do it.

***

## The three field tiers

Every field is one of three tiers — the SDK types tag each one, and your editor autocompletes the full set:

<CardGroup cols={3}>
  <Card title="Required" icon="asterisk">
    The API **rejects** the application without it (`400 missing_required_fields`). Non-optional in the types.
  </Card>

  <Card title="Recommended" icon="triangle-exclamation">
    Not enforced at intake, but acquirers **will** ask for it before activation. Omitting one only **delays** approval — `create()` echoes the gaps in `recommendations`, and the review queue flags every one.
  </Card>

  <Card title="Optional" icon="circle-info">
    Situational / nice-to-have. Improves risk underwriting but is never blocking.
  </Card>
</CardGroup>

<Warning>
  Only **5 fields are strictly required**: `businessInfo.businessName`, `businessInfo.country`, and the representative's `firstName`, `lastName`, `email`. Everything else is *recommended* or *optional* — but a 5-field application will bounce back from KYB. Send a complete one.
</Warning>

***

## Minimal vs complete

```ts theme={null}
import { Tagada } from '@tagadapay/node-sdk';

const tagada = new Tagada({ apiKey: process.env.TAGADA_CRM_KEY }); // sk_crm_…

// Minimal — passes intake, but our team will ask for more before activation.
// NOTE: this is NOT idempotent. Each call submits a NEW application to the
// review queue — keep `draft.id` and poll with retrieve(), don't blindly retry.
const draft = await tagada.processing.applications.create({
  businessInfo: { businessName: 'ACME COMMERCE', country: 'FR' },
  representative: { firstName: 'Jeanne', lastName: 'Dupont', email: 'jeanne@example.com' },
});

console.log(draft.recommendations);
// → ['businessInfo.email', 'businessInfo.website', 'businessInfo.registrationNumber',
//    'businessInfo.mcc', 'representative.idNumber', 'bankAccount.iban', …]
```

A **complete** application — the shape you actually want to send. The payload
is the same everywhere; only the **country-specific identifiers and settlement
rail** change. Pick your jurisdiction:

<Tabs>
  <Tab title="France (SEPA)">
    ```ts theme={null}
    const application = await tagada.processing.applications.create({
      businessInfo: {
        // ── Required ──
        businessName: 'ACME COMMERCE',
        country: 'FR',
        // ── Recommended (acquirer KYB) ──
        activityType: 'business',
        legalEntityType: 'sas',
        registrationNumber: '123456789',   // SIREN / company number (from KBIS)
        taxId: 'FR00123456789',            // VAT number
        website: 'https://example.com',
        mcc: '5734',
        email: 'ops@example.com',
        phone: '+33123456789',
        address: {
          street: '1 Rue de l’Exemple',
          city: 'Paris',
          postalCode: '75001',
          country: 'FR',
        },
        // ── Optional (risk profile) ──
        businessModel: 'SaaS (subscription)',
        businessDescription: 'Online software platform (example.com).',
        monthlyVolume: '10000',
        desiredCurrencies: ['EUR'],
      },
      representative: {
        // ── Required ──
        firstName: 'Jeanne',
        lastName: 'Dupont',
        email: 'jeanne@example.com',
        // ── Recommended (KYC) ──
        phone: '+33123456789',
        title: 'signatory',
        dateOfBirth: '1990-01-01',
        nationality: 'FR',
        idType: 'identityCard',
        idNumber: 'X0000000',
        idCountry: 'FR',
        idExpiry: '2030-01-01',
        residentialAddress: {
          street: '2 Avenue Imaginaire',
          city: 'Paris',
          postalCode: '75002',
          country: 'FR',
        },
      },
      // ── Recommended: settlement account (holder MUST match the entity) ──
      bankAccount: {
        accountHolderName: 'SAS ACME COMMERCE',
        iban: 'FR7630006000011234567890189',  // SEPA rail
        bic: 'AGRIFRPPXXX',
        currency: 'EUR',
        country: 'FR',
      },
      documents: [],
    });
    ```
  </Tab>

  <Tab title="United States (ACH)">
    ```ts theme={null}
    const application = await tagada.processing.applications.create({
      businessInfo: {
        // ── Required ──
        businessName: 'ACME COMMERCE LLC',
        country: 'US',
        // ── Recommended (acquirer KYB) ──
        activityType: 'business',
        legalEntityType: 'llc',
        registrationNumber: '98-1923816',  // EIN — the US has no separate company number
        taxId: '98-1923816',               // EIN again — identical to registrationNumber
        website: 'https://example.com',
        mcc: '5734',
        email: 'ops@example.com',
        phone: '+12025550182',
        address: {
          street: '1 Market Street',
          city: 'San Francisco',
          state: 'CA',                      // US addresses need the state
          postalCode: '94105',
          country: 'US',
        },
        // ── Optional (risk profile) ──
        businessModel: 'SaaS (subscription)',
        businessDescription: 'Online software platform (example.com).',
        monthlyVolume: '10000',
        desiredCurrencies: ['USD'],
      },
      representative: {
        // ── Required ──
        firstName: 'John',
        lastName: 'Smith',
        email: 'john@example.com',
        // ── Recommended (KYC) ──
        phone: '+12025550182',
        title: 'signatory',
        dateOfBirth: '1985-03-14',
        nationality: 'US',
        idType: 'driversLicense',
        idNumber: 'D1234567',
        idCountry: 'US',
        idState: 'CA',                      // issuing state, for US IDs
        idExpiry: '2030-01-01',
        ssnLast4: '6789',                   // US sole traders only
        residentialAddress: {
          street: '500 Howard Street',
          city: 'San Francisco',
          state: 'CA',
          postalCode: '94105',
          country: 'US',
        },
      },
      // ── Recommended: settlement account (holder MUST match the entity) ──
      bankAccount: {
        accountHolderName: 'ACME COMMERCE LLC',
        routingNumber: '021000021',         // US ACH rail (instead of IBAN/BIC)
        accountNumber: '1234567890',
        currency: 'USD',
        bankName: 'Example Bank, N.A.',
        country: 'US',
      },
      documents: [],
    });
    ```
  </Tab>
</Tabs>

Either way, `create()` returns the same shape:

```ts theme={null}
// → {
//   object: 'processing_application',
//   id: 'ent_xxx',
//   status: 'submitted',
//   accountId: 'acc_xxx',
//   tpaId: null,            // set once our team provisions your TPA
//   kycStatus: null,
//   submittedAt: '2026-06-26T…',
//   recommendations: []     // empty → nothing left to fill
// }
```

***

## Field reference

### `businessInfo`

| Field                           | Tier         | Notes                                                                                                                                                     |
| ------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `businessName`                  | **Required** | Legal entity name exactly as registered (or the person's full name for a sole trader).                                                                    |
| `country`                       | **Required** | Country of registration — ISO 3166-1 alpha-2 (`FR`).                                                                                                      |
| `activityType`                  | Recommended  | `'business'` or `'individual'`. Drives the acquirer legal-entity type.                                                                                    |
| `legalEntityType`               | Recommended  | Canonical code: `sas`, `sarl`, `sa`, `auto_entrepreneur`, `llc`, `ltd`, `inc`, `corporation`…                                                             |
| `registrationNumber`            | Recommended  | Company registration number from the registration certificate / KBIS. FR: SIREN/SIRET, UK: Companies House no., **US: the 9-digit EIN** (see note below). |
| `taxId`                         | Recommended  | Tax identifier. EU: the VAT number, e.g. `FR00123456789`. **US: the federal EIN — the same value as `registrationNumber`.**                               |
| `website`                       | Recommended  | Public URL — also used for the statement descriptor & content review.                                                                                     |
| `mcc`                           | Recommended  | Merchant Category Code, e.g. `5734`.                                                                                                                      |
| `address`                       | Recommended  | Registered business address (`street`, `city`, `postalCode` recommended; `apartment`, `state`, `country` optional).                                       |
| `email`                         | Recommended  | Business contact email (falls back to the representative's).                                                                                              |
| `phone`                         | Recommended  | Business phone, E.164 (`+33…`).                                                                                                                           |
| `businessDescription`           | Optional     | Plain-language description of what is sold.                                                                                                               |
| `businessModel`                 | Optional     | One-liner, e.g. `SaaS (subscription)`.                                                                                                                    |
| `desiredCurrencies`             | Optional     | Settlement currencies — ISO 4217, e.g. `['EUR']`.                                                                                                         |
| `mccBreakdown`                  | Optional     | Per-MCC volume split (`{ code, label?, volume?, averageTicket?, chargebackRatio?, refundRatio? }[]`).                                                     |
| `monthlyVolume`                 | Optional     | Expected monthly card volume, major units as a string (`'10000'`).                                                                                        |
| `averageTicket`                 | Optional     | Typical order value, major units as a string.                                                                                                             |
| `currentlyProcessing`           | Optional     | `boolean` — already processing elsewhere today?                                                                                                           |
| `currentProcessor`              | Optional     | Current/previous processor name.                                                                                                                          |
| `previousMonthlyVolume`         | Optional     | Volume processed elsewhere last month, as a string.                                                                                                       |
| `expectedStartDate`             | Optional     | ISO date `YYYY-MM-DD`.                                                                                                                                    |
| `supportEmail` / `supportPhone` | Optional     | Customer-support contacts shown to cardholders.                                                                                                           |

<Note>
  **US merchants — `registrationNumber` and `taxId` are the same EIN.** The US
  has no separate company registration number, so the federal EIN (e.g.
  `98-1923816`) is both your tax ID and your registration number. Send the same
  9-digit value in both fields. The acquirer requires both to be present.
</Note>

### `representative`

The legal representative — the UBO / authorised signer who is the KYC subject.

| Field                | Tier         | Notes                                                                                  |
| -------------------- | ------------ | -------------------------------------------------------------------------------------- |
| `firstName`          | **Required** | Given name.                                                                            |
| `lastName`           | **Required** | Family name.                                                                           |
| `email`              | **Required** | Contact email — also where the confirmation is sent.                                   |
| `phone`              | Recommended  | E.164 (`+33…`).                                                                        |
| `title`              | Recommended  | Role: `signatory`, `uboThroughOwnership`, `uboThroughControl`, `director`…             |
| `dateOfBirth`        | Recommended  | ISO `YYYY-MM-DD`.                                                                      |
| `nationality`        | Recommended  | ISO 3166-1 alpha-2.                                                                    |
| `idNumber`           | Recommended  | Government ID number.                                                                  |
| `idType`             | Recommended  | `passport` · `identityCard` · `driversLicense` · `nationalIdNumber`.                   |
| `idCountry`          | Recommended  | Issuing country — ISO 3166-1 alpha-2.                                                  |
| `idExpiry`           | Recommended  | ISO `YYYY-MM-DD`.                                                                      |
| `residentialAddress` | Recommended  | Home address (`street`, `city`, `postalCode` recommended) — **not** the business seat. |
| `idState`            | Optional     | Issuing state/province, where relevant (US).                                           |
| `ssnLast4`           | Optional     | Last 4 of SSN — US sole traders only.                                                  |

### `bankAccount`

Settlement (payout) account. The **account holder must match the legal entity** — acquirers reject payouts to a mismatched name. Provide **one rail**.

| Field                             | Tier        | Notes                                       |
| --------------------------------- | ----------- | ------------------------------------------- |
| `accountHolderName`               | Recommended | Must equal the legal entity name.           |
| `currency`                        | Recommended | Settlement currency — ISO 4217 (`EUR`).     |
| `iban` + `bic`                    | Recommended | SEPA rail.                                  |
| `routingNumber` + `accountNumber` | —           | US ACH rail (use instead of IBAN).          |
| `bsbNumber` + `accountNumber`     | —           | Australian BSB rail.                        |
| `bankName` / `country`            | Optional    | Bank name and country (ISO 3166-1 alpha-2). |

### `documents`

Optional at submit, but they satisfy KYB requirements early. Each entry is metadata referencing a file you've already uploaded to storage:

```ts theme={null}
documents: [
  { type: 'national_id', fileKey: 'kyc/loic-id.pdf', fileUrl: 'https://…', fileName: 'id.pdf' },
  { type: 'business_registration', fileKey: 'kyb/kbis.pdf', fileUrl: 'https://…' },
  { type: 'bank_statement', fileKey: 'kyb/rib.pdf', fileUrl: 'https://…' },
]
```

Accepted `type` values: `passport`, `drivers_license`, `national_id`, `proof_of_national_id`, `proof_of_address`, `business_registration`, `bank_statement`, `processing_history`, `id_scan`, `other`.

***

## How `recommendations` works

`create()` never fails on a missing *recommended* field. Instead it returns them so you can surface them in your own UI or fill them later:

```ts theme={null}
const app = await tagada.processing.applications.create({ businessInfo, representative });

if (app.recommendations?.length) {
  console.warn('Acquirer KYB will need these before activation:', app.recommendations);
}
```

The same gaps appear as **"Missing"** pills in the TagadaPay dashboard once your application is in review.

***

## Why the SDK asks for less than the dashboard "requires"

The dashboard form *visually* marks \~15 fields as required (red pills). Only 5 are hard gates; the rest are the **Recommended** tier above. A complete SDK application and a complete dashboard application carry **identical** data.

***

## Track the application

```ts theme={null}
const status = await tagada.processing.applications.retrieve('ent_xxx');
// { status: 'submitted' | 'in_review' | 'approved' | 'rejected' | …, tpaId, kycStatus }
```

Once approved and your TPA is provisioned, `tpaId` is populated. Then [enroll](#after-approval-one-key-for-all-your-tpas) to mint a processing key and start charging.

***

## One merchant, many TPAs

A TPA is scoped to **one legal entity with one settlement setup**. That is deliberate: KYB is run per entity, and an acquirer is assigned per entity. So whenever your reality has more than one of those, you want more than one TPA — all owned by your single merchant account.

Common reasons to run several:

| You have…                                                                        | TPAs you'd open                                                                          |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Several legal entities** (a holding with multiple LLCs, one company per brand) | One TPA per entity — each passes its own KYB                                             |
| **The same entity selling in several regions**                                   | One TPA per settlement region (e.g. an EU TPA settling in EUR, a US TPA settling in USD) |
| **Risk or volume you want to split**                                             | Several TPAs so traffic and exposure spread across different acquirers                   |

<Note>
  **One application = one TPA.** You don't get multiple TPAs from a single submission — you get them by submitting **one application per entity (or region)**. Every application you send with the **same CRM key** attaches to the **same merchant** (`acc_xxx`), so they all collect under one account you manage with one key.
</Note>

### Example: three LLCs, one merchant

Say you operate three US LLCs. Each is a separate legal entity, so each needs its own application — but you submit them all from the same CRM key:

```ts theme={null}
import { Tagada } from '@tagadapay/node-sdk';

const tagada = new Tagada({ apiKey: process.env.TAGADA_CRM_KEY }); // one CRM key

// Three LLCs you operate. Each is its own legal entity → its own TPA.
const entities = [
  {
    businessName: 'NORTHWIND APPAREL LLC',
    ein: '88-1112221', mcc: '5651', website: 'https://northwind.example',
    rep: { firstName: 'John', lastName: 'Smith', email: 'john@northwind.example' },
    accountNumber: '1000000001',
  },
  {
    businessName: 'CINDER SUPPLEMENTS LLC',
    ein: '88-3334441', mcc: '5499', website: 'https://cinder.example',
    rep: { firstName: 'John', lastName: 'Smith', email: 'john@cinder.example' },
    accountNumber: '1000000002',
  },
  {
    businessName: 'HARBOR SAAS LLC',
    ein: '88-5556661', mcc: '5734', website: 'https://harbor.example',
    rep: { firstName: 'John', lastName: 'Smith', email: 'john@harbor.example' },
    accountNumber: '1000000003',
  },
];

// One application per LLC. They all attach to the SAME merchant (acc_xxx)
// and each provisions its own TPA once approved.
for (const e of entities) {
  const app = await tagada.processing.applications.create({
    businessInfo: {
      businessName: e.businessName,
      country: 'US',
      activityType: 'business',
      legalEntityType: 'llc',
      registrationNumber: e.ein,   // US: EIN is both…
      taxId: e.ein,                // …registrationNumber and taxId
      mcc: e.mcc,
      website: e.website,
      address: { street: '1 Market Street', city: 'San Francisco', state: 'CA', postalCode: '94105', country: 'US' },
    },
    representative: e.rep,
    bankAccount: {
      accountHolderName: e.businessName,  // holder MUST match each entity
      routingNumber: '021000021',
      accountNumber: e.accountNumber,
      currency: 'USD',
      country: 'US',
    },
  });

  console.log(`${e.businessName} → application ${app.id}, merchant ${app.accountId}`);
  // Same app.accountId (acc_xxx) for all three — one merchant, three applications.
}
```

<Tip>
  **Same entity, several regions?** Use the exact same loop, but vary `businessInfo.country` and the settlement rail per region — e.g. one application with `country: 'FR'` + an EUR `iban`/`bic`, and another with `country: 'US'` + a USD `routingNumber`/`accountNumber`. You'll end up with an EU TPA and a US TPA under the same merchant.
</Tip>

### After approval: one key for all your TPAs

Once your applications are approved and their TPAs are provisioned, call **`enroll()` once**. It mints a **merchant-scoped** processing key (`tp_sk_…`) that can see and manage **every** TPA under your account — you do not enroll per TPA.

```ts theme={null}
// Build a client with your CRM key, then enroll → processing key.
// NOTE: not idempotent. One call = one NEW key. Enroll ONCE and store the
// secret; calling again just mints extra live keys you'll have to revoke.
const { key } = await tagada.processing.enroll({ mode: 'live' });
// key.secret = 'tp_sk_live_…'  (plaintext, returned ONLY here — store it)

const merchant = new Tagada({ apiKey: key.secret }); // tp_sk_live_…

// This one key lists all of your TPAs.
const { data: tpas } = await merchant.processing.tpas.list();
// → [ { id: 'tpa_aaa', … }, { id: 'tpa_bbb', … }, { id: 'tpa_ccc', … } ]
//   one TPA per approved LLC, all under your single merchant account

// Optional: mint a key scoped to a SINGLE TPA — e.g. to isolate one brand's
// charging, or hand one brand's key to a teammate.
// Also not idempotent: each call mints another key. Mint one per consumer
// (per service / per teammate) on purpose, and revoke them when unused.
const northwindKey = await merchant.processing.tpas.keys.create('tpa_aaa');
// northwindKey.secret = 'tp_sk_live_…' scoped to tpa_aaa only
```

<Info>
  **`enroll()` is activation without leaving your code.** It does the same thing as going to the TagadaPay dashboard, activating processing, and copying your key — the SDK just lets you do it (and the whole apply → KYB → charge flow) end to end, without ever opening the CRM or the dashboard.

  Because of that, treat key minting as a **one-time setup step, not application code**: run `enroll()` once in a bootstrap script (or grab the key from the dashboard), store `key.secret` in your secrets manager, and have your app read it from the environment. Minting a key inside your request path is the equivalent of re-running a seeding script on every request.
</Info>

```ts theme={null}
// ── setup.ts — run ONCE ────────────────────────────────────────────────────
const { key } = await tagada.processing.enroll({ mode: 'live' });
// → store key.secret as TAGADA_PROCESSING_KEY in your secret manager

// ── app.ts — every request ─────────────────────────────────────────────────
const tp = new Tagada({ apiKey: process.env.TAGADA_PROCESSING_KEY! }); // read it
await tp.payments.process({ /* … */ });
```

So the key model mirrors the entity model:

| Key                                     | Scope        | Minted by                            | Sees                          |
| --------------------------------------- | ------------ | ------------------------------------ | ----------------------------- |
| **CRM key** (`sk_crm_…`)                | the merchant | `tagada-init` / dashboard            | CRM data + apply + `enroll()` |
| **Merchant processing key** (`tp_sk_…`) | the merchant | `processing.enroll()`                | **all** your TPAs             |
| **Per-TPA key** (`tp_sk_…`)             | one TPA      | `processing.tpas.keys.create(tpaId)` | that one TPA                  |

<Note>
  `enroll()`'s `mode` defaults to `'test'` server-side, so a fresh enrollment can never touch live processing by accident. Pass `mode: 'live'` once you're ready to charge real cards.
</Note>

<Warning>
  **`enroll()` is not idempotent — call it once and store the secret.** Every call mints a **brand-new** merchant key; it does **not** return or rotate a previous one. Calling it repeatedly doesn't break anything (older keys keep working), but you pile up live credentials you then have to track and revoke. Treat `key.secret` like a password: persist it on first enroll, reuse it, and if you ever lose or leak one, revoke that key and enroll again. For narrower, disposable credentials, mint a per-TPA key with `processing.tpas.keys.create(tpaId)` instead.
</Warning>

***

## Calling things more than once

Networks time out and retries happen, so it pays to know what each call does the **second** time. The rule of thumb: **reads are safe to repeat, and every write here creates a new resource — none of them silently de-duplicate.** Know which is which before you wrap anything in a retry loop.

| Call                                    | What it does                           | Safe to repeat?                  | A second call…                                                                                           |
| --------------------------------------- | -------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `processing.applications.create()`      | Submits a processing application       | **No**                           | …files a **second application** in the review queue. Duplicates slow KYB and can provision an extra TPA. |
| `processing.enroll()`                   | Mints your **merchant** processing key | **No**                           | …mints **another** live key. Old ones keep working — you just accumulate secrets to track and revoke.    |
| `processing.tpas.keys.create()`         | Mints a **per-TPA** key                | **No**                           | …mints **another** key. Great on purpose (one per service), a liability by accident.                     |
| `processing.tpas.list()` / `retrieve()` | Reads your TPA(s)                      | **Yes**                          | …returns the same data. Repeat freely.                                                                   |
| `payments.process()`                    | Charges a card                         | **Only with an idempotency key** | …can **double-charge** without one; with a stable key it returns the original payment.                   |

### Retry a charge safely

`payments.process()` is the one write you legitimately need to retry (timeouts mid-charge). Pass a stable `idempotencyKey`: the first call charges, any repeat with the same key returns that same payment instead of charging again.

```ts theme={null}
const tp = new Tagada({ apiKey: key.secret }); // your stored tp_sk_…

await tp.payments.process(
  { paymentInstrumentId, paymentFlowId, amount: 4999, currency: 'EUR', paymentMethod: 'card', mode: 'purchase' },
  { idempotencyKey: 'order_42_charge_1' }, // same key on retry => at most one charge
);
```

### Don't re-submit an application

`applications.create()` has **no** server-side de-dup, so a retry creates a duplicate dossier. Keep your own "already applied?" guard, and once you have an id, **poll** instead of re-submitting:

```ts theme={null}
const app = await tagada.processing.applications.create({ businessInfo, representative });

// From here on, track it — never call create() again for the same entity.
const status = await tagada.processing.applications.retrieve(app.id);
```

***

## Common errors

| HTTP | Code                      | When                                                                 |
| ---- | ------------------------- | -------------------------------------------------------------------- |
| 400  | `missing_required_fields` | One of the 5 required fields is empty (`missing` lists them).        |
| 400  | `invalid_request`         | Body failed schema validation (`issues` has details).                |
| 401  | `invalid_api_key`         | Not a valid CRM key (`sk_crm_…`).                                    |
| 403  | `use_applications_api`    | A direct merchant tried `tpas.create()` — use this endpoint instead. |

***

## Next steps

<CardGroup cols={2}>
  <Card title="Node SDK Quick Start" icon="node-js" href="/developer-tools/node-sdk/quick-start">
    CRM setup — stores, products, funnels, payment flows
  </Card>

  <Card title="Partners — provision sub-merchants" icon="handshake" href="/developer-tools/partners/introduction">
    If you onboard merchants on their behalf, use `partners.processing.tpas.create()` instead
  </Card>
</CardGroup>
