Importació massiva de comptes gestionats
Previsualitza i aplica un CSV de clients d'una vegada: columnes, modalitats, estats per fila, límits i què fa una reimportació.
La importació massiva carrega molts clients d'una vegada des d'un fitxer CSV. Cada fila és una de dues coses, segons la seva columna mode: un compte gestionat, un compte separat que aprovisiones per a un client, o un NIF propi, un NIF que dones d'alta al teu propi compte com a NIF addicional (l'app el mostra com a «NIF al meu compte»). Primer envies el fitxer a una previsualització, que classifica i tarifa cada fila sense escriure ni cobrar res, i després envies el mateix fitxer per aplicar-lo. Aquesta guia està escrita per al compte que aprovisiona, el proveïdor de comptes gestionats: mira comptes gestionats. Explica les tres operacions, el fitxer i les seves columnes, com el llegeix el parser, els límits, els estats per fila, la previsualització i el seu cost, què fa una segona importació del mateix fitxer, els clients que pots carregar-hi, l'aplicació i la seva idempotència, i què fa una clau de proves.
La importació és declarativa i no atòmica: el fitxer diu el que ha d'existir, cada fila que es pot aplicar s'aplica per separat i una fila que falla mai no desfà les altres. No té eina MCP ni opció de sèries de documents, com explica el final d'aquesta guia.
Les tres operacions
| Operació | Scope | Idempotency-Key | Què fa |
|---|---|---|---|
GET /v1/accounts/imports/template | accounts:read | No | Descarrega la plantilla CSV del fitxer de comptes. |
POST /v1/accounts/imports/preview | accounts:write | No | Classifica i tarifa cada fila. No s'escriu, aprovisiona ni cobra res. |
POST /v1/accounts/imports | accounts:write | Obligatòria | Aplica la importació i respon 201 Created amb el resultat de l'execució. |
accounts:read i accounts:write són scopes privilegiats: * no els cobreix, i només els poden fer servir els comptes als quals hem concedit el privilegi de proveïdor. Sense el privilegi, o quan la persona que va emetre la clau ja no és titular ni administrador del teu compte, la resposta és 403 privileged_scope_required. La previsualització també necessita accounts:write, tot i que no escriu res. Cap de les tres rutes porta el segment {account}: el proveïdor és sempre el compte de la clau i l'entorn és el de la clau, i cap dels dos va a la petició.
L'ordre habitual és aquest: descarrega la plantilla, omple-la, envia-la a la previsualització, corregeix les files que surtin BLOCKED o ERROR i torna a previsualitzar, i després aplica els mateixos fitxers.
La petició
La previsualització i l'aplicació reben el mateix cos multipart/form-data.
| Camp | Obligatori | Què és |
|---|---|---|
accounts_file | Sí | El fitxer de comptes: una fila per compte gestionat o per NIF propi, fins a 100 files. |
customers_file | No | El fitxer de clients: els clients d'aquests comptes i NIF, fins a 1.000 files. |
options | No | Un objecte amb tres opcions, totes false per defecte. |
Els dos fitxers són CSV, preferiblement en UTF-8, separats per comes, punt i coma o tabuladors, i de fins a 5 MB cadascun. El parser és més tolerant que la plantilla. Per previsualitzar el fitxer de l'exemple de més avall, envia només el fitxer de comptes:
curl -X POST https://api.factuarea.com/v1/accounts/imports/preview \
-H "Authorization: Bearer $FACTUAREA_API_KEY" \
-F "accounts_file=@accounts.csv"No fixis Content-Type tu mateix: el teu client HTTP afegeix la capçalera multipart/form-data amb el seu boundary. Per aplicar, envia els mateixos camps a POST /v1/accounts/imports amb una Idempotency-Key.
Opcions
| Opció | Per defecte | Què fa |
|---|---|---|
send_email | false | Enviem l'enllaç de reclamació al titular de cada compte gestionat nou de producció, i la resposta porta claim_token i claim_url a null. Amb false, cada fila nova de producció retorna el seu val una sola vegada, al 201. Mira qui lliura el val. |
apply_customers_to_own_company | false | Importa també, a la teva pròpia empresa, els clients de customers_file que no tenen account_ref. La clau necessita contacts:write. Mira clients. |
confirm_plan_changes | false | Aplica el canvi de pla que demana una fila sobre un compte gestionat que ja existeix i que pagues tu. Sense ella, aquesta fila surt WARNING i el pla no canvia. Mira importar una altra vegada el mateix fitxer. |
options va com a camps de formulari imbricats (options[send_email]=true) o com un únic camp JSON (options={"send_email":true}), que és com un client OpenAPI serialitza un objecte a multipart/form-data. Un booleà accepta true, false, 1, 0, on, off, yes i no. Qualsevol altra clau respon 422 invalid_param_value, així que una opció mal escrita mai no s'ignora en silenci.
El fitxer de comptes
El fitxer de comptes té una fila de capçalera i una fila per compte gestionat o per NIF propi, fins a 100. Una fila porta un NIF, i un NIF apareix una sola vegada al fitxer.
La plantilla
GET /v1/accounts/imports/template retorna text/csv com a adjunt amb el nom plantilla-importacion-cuentas.csv. És la mateixa per a tots els proveïdors i no llegeix res del teu compte. El fitxer és UTF-8 amb marca d'ordre de bytes (BOM), ; com a separador i fi de línia CRLF, que és el que un full de càlcul en castellà obre bé. Porta la fila de capçalera i una fila d'exemple:
mode;external_ref;plan;tax_id;legal_name;address;postal_code;city;province;country_code;owner_email;display_name;language;access_level
# ejemplo: managed_account;CLIENTE-0001;empresario;B12345674;Cliente Ejemplo SL;Calle Mayor 1;28013;Madrid;Madrid;ES;titular@example.com;Cliente Ejemplo;es;operateLa primera cel·la de la fila d'exemple comença per # ejemplo, i la importació ignora sempre una fila així. Sense aquesta marca seria una fila managed_account vàlida, així que treu-la només quan ho pretenguis. El conjunt de columnes és tancat: una columna que no és a la plantilla deixa cada fila en ERROR en aquesta columna, i el mateix fa una columna que apareix dues vegades.
Columnes
| Columna | managed_account | own_nif | Notes |
|---|---|---|---|
mode | Obligatòria | Obligatòria | own_nif o managed_account, sense valor per defecte: un valor buit o desconegut deixa la fila en ERROR. |
external_ref | Obligatòria | No s'usa | La teva pròpia referència del client, fins a 128 caràcters, única al fitxer i al teu compte. És el que fa que una segona importació concilii en lloc de duplicar. |
plan | Obligatòria | No s'admet | emprendedor, empresario o integral. enterprise només s'assigna per contracte i la seva fila queda BLOCKED. En una fila own_nif, un plan és un ERROR: el NIF pren el pla del teu compte. |
tax_id | Obligatòria | Obligatòria | El NIF, CIF o NIE, fins a 20 caràcters, validat amb el seu caràcter de control. Un per fila, mai repetit al fitxer. |
legal_name | Obligatòria | Obligatòria | La raó social, fins a 100 caràcters, i almenys 2 en un compte gestionat. |
address, postal_code, city, province, country_code | Opcionals | Opcionals | El domicili fiscal, del client o del teu NIF propi. Fins a 255, 10, 100, 100 i 100 caràcters. |
owner_email | Obligatòria en un compte nou de producció | No s'usa | La persona que serà titular del compte i rebrà el val de reclamació, fins a 255 caràcters. Un compte de proves no la necessita. |
display_name | Opcional | Opcional | El nom visible. En un compte gestionat és també el nom del compte, de 2 a 100 caràcters. En un NIF propi són fins a 255 caràcters, i és la legal_name si està buit. |
language | Opcional | No s'usa | es, en o ca: l'idioma del compte i del seu val. |
access_level | Opcional | No s'usa | El nivell que conserva el teu compte sobre el nou compte gestionat: none, view o operate. És operate si està buit. |
mode, plan, access_level i language es llegeixen en minúscules, i cada valor es retalla. Una cel·la buida compta com a absent. owner_email, language i access_level es comproven en la seva forma a totes les files, encara que la modalitat no les faci servir.
Com llegeix el fitxer el parser
El parser llegeix el que exporta un full de càlcul, així que és més tolerant que la plantilla. Decideix el tipus del fitxer pel seu contingut i mai pel seu nom ni la seva extensió.
| Què | Com ho llegeix |
|---|---|
| Codificació | UTF-8 amb o sense BOM, UTF-16 amb BOM (el «text Unicode» d'Excel) i, si el fitxer no és UTF-8 vàlid, Windows-1252. |
| Separador | Un punt i coma, una coma o un tabulador, detectat a la fila de capçalera. Si en encaixen diversos, el que dona més columnes, i en cas d'empat el primer d'aquests tres. |
| Preàmbul | Salta fins a 20 línies abans de la fila de capçalera. La fila de capçalera és la primera línia amb una cel·la mode (account_ref al fitxer de clients). |
| Capçalera | En minúscules i retallada, amb els espais i els guions interiors convertits en _: Tax ID i external-ref es llegeixen com tax_id i external_ref. |
| Files | Es salten les línies en blanc i la fila # ejemplo. Les cel·les es retallen, espais de no separació inclosos. Un valor entre cometes dobles pot contenir el separador i salts de línia. |
| Text | Les cel·les són text literal i no s'avalua res: una fórmula es llegeix com el text que conté. |
El que no llegeix: un full de càlcul (.xlsx o .xls), un PDF, una imatge, un arxiu comprimit o qualsevol fitxer binari és 422 import_file_invalid encara que es digui .csv, i el mateix un fitxer sense fila de capçalera després del preàmbul, amb unes cometes dobles sense tancar o amb caràcters de control. Desa el full com a CSV abans de pujar-lo.
Límits
| Límit | Valor | Quan se supera |
|---|---|---|
| Mida de cada fitxer | 5 MB | 413 import_file_too_large. error.param és accounts_file o customers_file. |
| Mida de tota la petició | 11 MB | 413 payload_too_large, abans d'inspeccionar cap fitxer. |
Files de accounts_file | 100 | 422 import_row_limit_exceeded. error.param anomena el fitxer. |
Files de customers_file | 1.000 | 422 import_row_limit_exceeded. error.param anomena el fitxer. |
| Un fitxer il·legible, sense fila de capçalera o al qual li falta una columna | — | 422 import_file_invalid. |
| Bytes dels fitxers que es pugen alhora, al teu compte | — | 429 upload_in_flight_budget_exceeded, amb Retry-After. |
| Previsualitzacions | 10 per minut per clau | 429, amb Retry-After. |
| Aplicacions | 5 per minut per clau i 20 al dia al teu compte | 429, amb Retry-After. |
| Aplicacions alhora | Una al teu compte | 409 import_in_progress. |
La mida i les files es comproven abans de llegir cap fila, així que quan en falla una no es classifica, escriu ni cobra res. Les files es compten sense la capçalera, les línies en blanc ni la fila d'exemple. Per carregar més de 100 clients, parteix el fitxer i envia les parts una darrere l'altra: cada part concilia per external_ref, així que pots tornar a enviar una part.
Estats per fila
La previsualització i l'aplicació classifiquen cada fila amb les mateixes regles i li donen un de cinc estats. Només els tres primers s'apliquen.
status | S'aplica | Què vol dir |
|---|---|---|
VALID | Sí | La fila és correcta i res al teu compte ho impedeix. Aplicar-la crea el compte o dona d'alta el NIF. |
WARNING | Sí | S'aplica, però alguna cosa d'ella no canvia. code diu què. |
ALREADY_EXISTS | Sí | El compte o el NIF ja existeix. La fila el concilia: mai el duplica ni cobra dues vegades. |
BLOCKED | No | Una regla de negoci impedeix la fila. code anomena el motiu. |
ERROR | No | La fila està malament. errors anomena les columnes, o code el motiu. |
El code d'un WARNING diu què no ha canviat:
code | Què vol dir |
|---|---|
managed_account_claimed | El client ja va reclamar el compte, així que les seves dades són seves: la fila no canvia res. |
access_level_below_relation | La fila demana un nivell inferior al teu. La importació mai baixa un nivell, així que es queda. |
plan_change_not_confirmed | La fila demana un altre pla i no vas enviar confirm_plan_changes. El pla no canvia. |
plan_change_failed | Les dades es van actualitzar, però el canvi de pla confirmat va fallar. errors.plan porta el motiu. |
Les files es classifiquen en l'ordre del fitxer, així que les files vàlides anteriors a una esgoten els topalls que aquesta necessitaria: un fitxer amb més comptes nous de producció que el teu topall deixa les últimes BLOCKED. El code d'una fila és un motiu de l'informe de la importació i no sempre un codi del catàleg d'errors: els que tenen pàgina hi enllacen.
Errors per columna
Una fila mal formada surt ERROR amb code null i un objecte errors. La seva clau és la columna, o row per a un error de la fila sencera, i el seu valor és un missatge en castellà. L'objecte sempre hi és, i és {} quan la fila no té res malament. Una fila falla quan:
- una columna obligatòria està buida:
mode,tax_idilegal_name, iexternal_refiplanen un compte gestionat; modeno ésown_nifnimanaged_account;tax_idno és un NIF, CIF o NIE vàlid;planno ésemprendedor,empresarioniintegral(enterprisequedaBLOCKED, no és un error), o una filaown_nifel porta;languageno éses,ennica,access_levelno ésnone,viewnioperate, oowner_emailno és una adreça de correu;- un text és més llarg que el seu màxim, o una
legal_nameodisplay_named'un compte gestionat té menys de 2 caràcters; external_refotax_idja va aparèixer en una fila anterior del fitxer: l'error va a la segona fila i a les següents;tax_iddifereix del del compte gestionat que l'external_refja anomena;- un compte gestionat nou de producció no té
owner_email; - la capçalera té una columna que no és a la plantilla o en repeteix una (l'error va en aquesta columna, a totes les files), o una fila té més valors que columnes té la capçalera (l'error va a
row).
Un valor que el compte o el NIF rebutja mentre s'aplica la fila també és un ERROR, amb code null i el seu missatge a errors.row. Un error de la pròpia execució, com un error de la base de dades o de la passarel·la de pagament, és un ERROR amb code row_apply_failed. Cap dels dos atura la resta de la importació.
Codis dels errors
Cada entrada d'errors té el seu codi estable a error_codes, un objecte amb les mateixes claus: {columna: codi}. El missatge d'errors és en castellà i es pot reformular; el codi no es tradueix ni canvia, així que reacciona al codi, o tradueix-lo, i ensenya el missatge només a una persona. Igual que errors, sempre hi és i és {} quan la fila no té res malament; també en una importació creada abans que existís el camp. Una fila BLOCKED surt amb els dos objectes buits: el seu motiu és el code de la fila. El camp és additiu: errors no canvia.
| Codi | Clau | Quan |
|---|---|---|
required | mode, tax_id, legal_name, external_ref, plan, owner_email | Una columna obligatòria està buida. |
invalid_mode | mode | No és own_nif ni managed_account. |
invalid_plan | plan | No és emprendedor, empresario ni integral. |
plan_not_allowed | plan | Una fila own_nif porta pla. |
invalid_tax_id | tax_id | No és un NIF, CIF o NIE vàlid. |
invalid_email | owner_email | No és una adreça de correu. |
invalid_language | language | No és es, en ni ca. |
invalid_access_level | access_level | No és none, view ni operate. |
too_long | Qualsevol columna de text | El text és més llarg que el seu màxim. |
too_short | legal_name, display_name | Un compte gestionat porta menys de 2 caràcters. |
duplicate_in_file | external_ref, tax_id | Ja va aparèixer en una fila anterior. |
tax_id_mismatch | tax_id | Difereix del del compte que l'external_ref ja anomena. |
unknown_column | La columna desconeguda | La capçalera té una columna que no és a la plantilla. |
duplicate_column | La columna repetida | La capçalera repeteix una columna. |
unnamed_column | row | Una columna de la capçalera no té nom. |
column_count_mismatch | row | La fila té més valors que columnes té la capçalera. |
invalid_value | row | El compte o el NIF rebutja un valor de la fila. |
row_rejected | row | El domini rebutja la fila mentre s'aplica. El motiu és el code de la fila. |
row_apply_failed | row | Ha fallat l'execució de la fila. |
plan_change_rejected | plan | En una fila WARNING, es rebutja el canvi de pla confirmat. El motiu és el code de la fila. |
La previsualització
POST /v1/accounts/imports/preview classifica i tarifa els fitxers sense cap efecte: no escriu res, no aprovisiona cap compte i no cobra res. Per tarifar les files només consulta Stripe, pel final del teu període de facturació i, per cada canvi de pla confirmat, l'import prorratejat d'aquest canvi, així que té el seu propi límit de 10 per minut. No necessita Idempotency-Key: és una consulta que fa servir POST perquè puja fitxers.
Pren aquest fitxer de comptes:
mode;external_ref;plan;tax_id;legal_name;address;postal_code;city;province;country_code;owner_email;display_name;language;access_level
managed_account;cliente-0042;empresario;B12345674;Talleres García SL;Calle Mayor 1;28013;Madrid;Madrid;ES;laura@talleresgarcia.example;Talleres García;es;operate
own_nif;;;B87654323;Distribuciones Norte SL;;;;;;;;;
managed_account;cliente-0043;emprendedor;A58818501;Panadería Sol SA;;;;;;marta@panaderiasol.example;;es;
managed_account;cliente-0044;emprendedor;;Gráficas Levante SL;;;;;;ivan@graficaslevante.example;;;Té quatre files: un compte gestionat, un NIF propi, un segon compte gestionat que no cap al teu topall i un altre que va oblidar el seu NIF. La previsualització respon 200:
{
"data": {
"object": "managed_account_import_preview",
"rows": [
{
"line": 2,
"mode": "managed_account",
"external_ref": "cliente-0042",
"tax_id": "B12345674",
"status": "VALID",
"code": null,
"errors": {},
"error_codes": {},
"plan": "empresario",
"monthly_amount_cents": 3500,
"proration_amount_cents": 1750,
"account_id": null,
"customers_status": "none",
"customers_queued": 0,
"customers_code": null
},
{
"line": 3,
"mode": "own_nif",
"external_ref": null,
"tax_id": "B87654323",
"status": "VALID",
"code": null,
"errors": {},
"error_codes": {},
"plan": null,
"monthly_amount_cents": 1500,
"proration_amount_cents": 750,
"account_id": null,
"customers_status": "none",
"customers_queued": 0,
"customers_code": null
},
{
"line": 4,
"mode": "managed_account",
"external_ref": "cliente-0043",
"tax_id": "A58818501",
"status": "BLOCKED",
"code": "managed_accounts_limit_reached",
"errors": {},
"error_codes": {},
"plan": "emprendedor",
"monthly_amount_cents": 0,
"proration_amount_cents": 0,
"account_id": null,
"customers_status": "none",
"customers_queued": 0,
"customers_code": null
},
{
"line": 5,
"mode": "managed_account",
"external_ref": "cliente-0044",
"tax_id": null,
"status": "ERROR",
"code": null,
"errors": {
"tax_id": "La columna tax_id es obligatoria: cada fila da de alta un NIF."
},
"error_codes": {
"tax_id": "required"
},
"plan": null,
"monthly_amount_cents": 0,
"proration_amount_cents": 0,
"account_id": null,
"customers_status": "none",
"customers_queued": 0,
"customers_code": null
}
],
"totals": {
"total_rows": 4,
"valid": 2,
"warning": 0,
"already_exists": 0,
"blocked": 1,
"error": 1
},
"cost": {
"currency": "EUR",
"managed_account": {
"monthly_amount_cents": 3500,
"proration_amount_cents": 1750
},
"own_nif": {
"monthly_amount_cents": 1500,
"proration_amount_cents": 750
},
"total": {
"monthly_amount_cents": 5000,
"proration_amount_cents": 2500
}
},
"own_company_customers": null
}
}El cos té aquests camps:
| Camp | Què és |
|---|---|
object | Sempre managed_account_import_preview. |
rows | Les files del fitxer de comptes, en l'ordre del fitxer. |
totals | Les files per estat: total_rows, valid, warning, already_exists, blocked i error. Els cinc estats hi són sempre, 0 quan no n'hi ha cap. |
cost | El cost de les files que s'aplicarien, per modalitat i en total. |
own_company_customers | El resultat d'apply_customers_to_own_company, o null quan l'opció està apagada. Mira clients. |
I cada fila té aquests:
| Camp | Què és |
|---|---|
line | La línia de la fila al fitxer de comptes, comptant des d'1. |
mode | managed_account o own_nif. És null quan la fila no té un mode vàlid, i llavors és ERROR. |
external_ref | La teva referència en una fila managed_account, i null en una fila own_nif. |
tax_id | El NIF tal com es llegeix del fitxer, o null quan la fila no en té. |
status | Un dels cinc estats. |
code | El motiu d'un WARNING, un BLOCKED o un ERROR que no és un error de columna, o null. |
errors | Els errors per columna. |
error_codes | El codi de cada error d'errors, amb les mateixes claus. Mira els codis dels errors. |
plan | El pla d'una fila managed_account, i null en una fila own_nif: pren el pla del teu compte. |
monthly_amount_cents | L'import mensual que la fila afegeix a la teva subscripció, en cèntims. |
proration_amount_cents | El que cobra d'immediat aplicar la fila, en cèntims. |
account_id | L'id del compte gestionat que la fila va crear o conciliar, o null mentre no existeix. |
customers_status | none, queued o blocked. Mira clients. |
customers_queued | Els clients encuats per al NIF de la fila. |
customers_code | El motiu de customers_status: blocked, o null. |
Què costa la importació
Cada fila porta monthly_amount_cents, l'import mensual que afegeix a la teva subscripció, i proration_amount_cents, el que cobra d'immediat aplicar-la pel que queda del teu període de facturació actual. cost els suma per a les files managed_account, per a les files own_nif i a total, amb la currency. Els imports són cèntims enters de base imposable, sense IVA: el nom de la clau diu la unitat.
A l'exemple, les dues files VALID afegeixen 3500 i 1500 cèntims al mes, 50,00 EUR, i aplicar el fitxer cobra d'immediat 2500 cèntims, 25,00 EUR. El prorrateig és la meitat de l'import mensual, com quan queda la meitat del teu període de facturació. Les files BLOCKED i ERROR no afegeixen res.
- Només compta el que es cobra. Només afegeixen import mensual les files noves que són
VALID: els comptes gestionats nous, que es cobren a la subscripciómanaged-accountsdel teu compte, i els NIF propis nous, que es cobren com a NIF addicionals. Una fila que ja existeix n'afegeix 0. - Un canvi de pla confirmat només afegeix el seu prorrateig. Amb
confirm_plan_changes, la fila d'un compte existent no té import mensual, però sí el prorrateig que cobraria un canvi de pla solt. Una pujada es cobra d'immediat. Una baixada té efecte al final del teu període i afegeix 0 ara. - Algunes importacions costen 0. És 0 en una importació de proves, mentre el teu compte és al seu trial i quan al teu compte no se li cobra.
- L'aplicació cobra el que va anunciar la previsualització. El prorrateig anunciat per a un fitxer és el que cobra aplicar els mateixos fitxers. L'aplicació torna a classificar el fitxer en el moment en què l'envies, amb l'estat que tingui llavors el teu compte, així que una previsualització de fa hores pot diferir.
Files que surten BLOCKED
El code d'una fila BLOCKED és el motiu. Una fila BLOCKED no canvia res, ni camps ni pla.
code | Quan | Què fer |
|---|---|---|
managed_account_plan_not_self_serve | La fila demana enterprise, o un canvi sobre un compte amb contracte enterprise. | enterprise l'assignem per contracte: demana emprendedor, empresario o integral. |
managed_account_provider_in_trial | El teu compte és al seu trial i la fila crearia un compte gestionat de producció, que es cobra des del primer dia. | Fes servir una clau fact_test_ per crear comptes de proves, o espera a començar a pagar. Mira el teu compte en trial. |
managed_accounts_limit_reached | El teu compte és al seu topall de comptes gestionats de producció, comptant les files vàlides anteriors a aquesta. | Acaba la gestió d'un compte que ja no portes, o demana'ns que pugem el topall. |
billing_not_current | La subscripció que paga els teus comptes gestionats no està al dia, per exemple després d'una renovació fallida. | Posa la teva facturació al dia i torna a previsualitzar. |
payment_method_required | Alguna cosa de la fila es cobra i el teu compte no té mètode de pagament. La importació mai no obre un checkout. | Registra un mètode de pagament a l'app i torna a previsualitzar. |
nif_transfer_required | El NIF ja és en un compte. Un compte gestionat necessita un NIF que no sigui en cap, el teu inclòs, i un NIF propi no pot ser en un altre compte. Mai no diem en quin. | Mou el NIF amb un traspàs de NIF. |
additional_nif_not_in_plan | Una fila own_nif i el teu pla no admet NIF addicionals: comencen a empresario. | Mira la porta i els seus quatre codis. |
additional_nif_limit_reached | Una fila own_nif i el teu compte és al seu topall de NIF addicionals, comptant les files vàlides anteriors a aquesta. | Mira el topall. |
managed_account_external_ref_in_other_environment | L'external_ref pertany a un compte de l'altre entorn, producció o proves. | Fes servir una altra referència. |
managed_account_no_longer_managed | L'external_ref pertany a un compte que ja no gestiones, perquè el seu titular va assumir el pagament. | Fes servir una altra referència. |
management_ended | La gestió del compte amb aquest external_ref va acabar, i la importació no reactiva una gestió. | Abans que el client el reclami, aprovisiona aquest external_ref amb POST /v1/accounts. |
access_level_raise_forbidden | El client ja va reclamar el compte i la fila demana un nivell superior al teu. | Només el client pot pujar el teu nivell. |
access_level_above_relation | El compte no està reclamat i la fila demana un nivell superior al teu. | La importació mai puja un nivell. Mira el teu nivell d'accés. |
plan_change_not_paid_by_provider | Amb confirm_plan_changes, el client va assumir el pagament, així que ja no pagues el compte. | Només el compte que paga pot canviar el pla. |
plan_change_requires_operate | Amb confirm_plan_changes, el teu nivell sobre el compte no és operate. | Mira el teu nivell d'accés. |
forbidden_action | Una fila own_nif i la clau no arriba a l'empresa titular del teu compte, que paga els NIF addicionals. | Fes servir una clau que hi arribi. |
Una fila que el domini rebutja mentre s'aplica, per exemple un topall que s'ha omplert entre la previsualització i l'aplicació, també queda BLOCKED, amb el codi públic d'aquest rebuig. Tracta un code que no coneguis com el motiu d'una fila BLOCKED.
Una fila own_nif necessita a més companies:write a la clau, a part d'accounts:write: sense ell, la fila és ERROR amb code insufficient_scope. Si la clau està limitada a alguns NIF, cada NIF que dona d'alta la importació s'afegeix a aquest límit, com quan dones d'alta un NIF amb una sola crida.
Importar una altra vegada el mateix fitxer
Aplicar una altra vegada el mateix fitxer mai no duplica un compte ni cobra dues vegades. L'external_ref d'una fila managed_account identifica el compte, i el tax_id identifica una fila own_nif. Una fila que anomena alguna cosa que ja existeix surt ALREADY_EXISTS, o WARNING o BLOCKED quan el que demana no es pot aplicar.
| La fila tracta de… | Què fa la importació |
|---|---|
| Un NIF propi que ja és al teu compte | Res. La fila és ALREADY_EXISTS i només s'importen els seus clients. |
| Un compte gestionat que vas aprovisionar, al mateix entorn i sense reclamar | Actualitza els camps de la llista de sota que la fila porta, i res més. |
| Un compte gestionat que el seu titular ja va reclamar | WARNING managed_account_claimed. No canvia res: aquestes dades ara són del titular. |
| Un compte gestionat la gestió del qual va acabar | BLOCKED management_ended. |
Un external_ref de l'altre entorn, o d'un compte que ja no gestiones | BLOCKED, sense escriure res. |
Què actualitza una segona importació
Només s'actualitza una llista de camps, i només mentre el compte no estigui reclamat: display_name (el nom visible, que és també el nom del compte i del seu NIF), language, legal_name, address, postal_code, city, province i country_code. Un camp canvia només quan la seva cel·la té valor, i un valor igual a l'actual no es reescriu. Tota la resta queda fora del seu abast:
- El NIF d'un compte existent no pot canviar: un
tax_iddiferent és unERROR. - El nivell d'accés mai canvia. Un nivell inferior al fitxer és un
WARNINGi un de superior ésBLOCKED. - El pla canvia només com diu el paràgraf següent.
Una fila que demana un pla diferent sobre un compte existent és WARNING plan_change_not_confirmed i no canvia res, tret que enviïs confirm_plan_changes. Amb ella, el canvi s'aplica quan encara pagues el compte, el teu nivell sobre ell és operate i no té contracte enterprise. Si no, la fila és BLOCKED amb plan_change_not_paid_by_provider, plan_change_requires_operate o managed_account_plan_not_self_serve. El canvi es tarifa com un canvi de pla solt. Si el perfil es va actualitzar i el canvi de pla falla després, la fila és WARNING amb el motiu a errors.plan.
Clients
customers_file carrega els clients de cada compte i NIF a la mateixa importació. Té una fila de capçalera amb la columna account_ref i, a les altres columnes, les de la importació de contactes d'una empresa: la capçalera de la plantilla de GET /v1/companies/{company}/contacts/import/template. Cada client va a una fila del fitxer de comptes a través del seu account_ref:
| La fila del fitxer de comptes és… | Els seus clients porten un account_ref igual a… |
|---|---|
managed_account | El seu external_ref. |
own_nif | El seu tax_id. |
Amb el fitxer de comptes de dalt, aquest fitxer de clients envia tres clients a cliente-0042:
account_ref;name;kind;tax_id;email
cliente-0042;Bar La Plaza SL;company;B22222228;compras@barlaplaza.example
cliente-0042;Ferretería Ortiz SL;company;B33333337;info@ferreteriaortiz.example
cliente-0042;Hotel Mirador SA;company;A44444446;reservas@hotelmirador.exampleEls clients passen per l'importador de contactes que ja existeix, amb el rol customer i l'estratègia de conflicte reject: un client que xoca amb un contacte existent es rebutja i l'existent es queda com està. Exportar i importar explica què accepta aquest importador. Els clients s'encuen: customers_queued compta el que s'ha encuat, i els contactes es creen després, així que la xifra no prova que ja existeixin.
Els clients d'una fila s'importen només en un NIF que la fila ha aplicat i on pots escriure. L'estat de cada fila és a customers_status, que és none (la fila no té clients), queued o blocked, i en el segon cas customers_code diu per què:
customers_code | Per què no s'importen els seus clients |
|---|---|
nif_not_applied | La fila no s'ha aplicat: és BLOCKED o ERROR. |
operate_access_required | El teu compte no té operate sobre el compte gestionat. |
account_admin_required | Els clients van a un dels teus NIF propis i la persona que va emetre la clau no és titular ni administrador del teu compte. |
nif_not_in_key_scope | El teu NIF propi és fora de l'àmbit de NIF de la clau i aquesta importació no l'ha donat d'alta. |
insufficient_scope | La clau no té contacts:write. |
customers_import_failed | L'importador de contactes ha fallat. |
Amb una clau, accounts:write no n'hi ha prou per als clients: la clau necessita també contacts:write.
Clients sense compte: apply_customers_to_own_company
Els clients que no tenen account_ref no van enlloc, tret que enviïs apply_customers_to_own_company. Amb ella, s'importen a la teva pròpia empresa en focus: l'únic NIF de l'àmbit de la clau, o l'únic NIF del teu compte. La destinació és sempre un NIF real del teu propi compte, mai un que un altre compte t'hagi cedit. La clau necessita contacts:write, i el resultat és a own_company_customers:
code | status | Què vol dir |
|---|---|---|
own_company_focus_required | ERROR | El teu compte té diversos NIF i cap és en focus. |
insufficient_scope | ERROR | La clau no té contacts:write. |
live_credential_required | ERROR | La importació s'executa amb una clau de proves. |
account_admin_required o operate_access_required | BLOCKED | La persona que va emetre la clau no pot escriure en aquesta empresa. |
nif_not_in_key_scope | BLOCKED | Aquesta empresa és fora de l'àmbit de NIF de la clau. |
customers_import_failed | BLOCKED | L'importador de contactes ha fallat. |
own_company_customers té status (VALID, BLOCKED o ERROR), code, customers_queued i unmatched_customers, que compta els clients el account_ref dels quals no correspon a cap fila del fitxer de comptes: no s'importen enlloc, i així no es perden en silenci.
Aplicar la importació
POST /v1/accounts/imports rep el cos de la petició i l'aplica. Aplica per separat cada fila VALID, WARNING o ALREADY_EXISTS, en l'ordre del fitxer: una fila que falla surt BLOCKED o ERROR i les altres continuen. Mai no obre un checkout: cobra la teva subscripció existent, i una fila que no es pot cobrar surt BLOCKED amb el seu motiu.
curl -X POST https://api.factuarea.com/v1/accounts/imports \
-H "Authorization: Bearer $FACTUAREA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-F "accounts_file=@accounts.csv" \
-F "customers_file=@customers.csv" \
-F "options[confirm_plan_changes]=false"L'aplicació és síncrona: la resposta arriba quan acaba l'última fila, i amb un fitxer ple pot trigar uns minuts, així que deixa almenys 5 minuts al teu client. Suposa que vas treure les dues files que van sortir BLOCKED i ERROR i envies el fitxer de clients de dalt. La resposta és 201 Created:
{
"data": {
"id": "0199a1f0-1c22-7a10-b111-8a8b8c8d8e8f",
"object": "managed_account_import",
"status": "completed",
"stats": {
"total_rows": 2,
"valid": 2,
"warning": 0,
"already_exists": 0,
"blocked": 0,
"error": 0,
"created": 2,
"reconciled": 0,
"customers_queued": 3,
"monthly_amount_cents": 5000,
"proration_amount_cents": 2500
},
"rows": [
{
"line": 2,
"mode": "managed_account",
"external_ref": "cliente-0042",
"tax_id": "B12345674",
"status": "VALID",
"code": null,
"errors": {},
"error_codes": {},
"plan": "empresario",
"monthly_amount_cents": 3500,
"proration_amount_cents": 1750,
"account_id": "0199a1f0-1c22-7a10-b111-6a6b6c6d6e6f",
"customers_status": "queued",
"customers_queued": 3,
"customers_code": null,
"claim_token": "e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3",
"claim_url": "https://app.factuarea.com/account-claims/accept?token=e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3e3c3"
},
{
"line": 3,
"mode": "own_nif",
"external_ref": null,
"tax_id": "B87654323",
"status": "VALID",
"code": null,
"errors": {},
"error_codes": {},
"plan": null,
"monthly_amount_cents": 1500,
"proration_amount_cents": 750,
"account_id": null,
"customers_status": "none",
"customers_queued": 0,
"customers_code": null,
"claim_token": null,
"claim_url": null
}
],
"own_company_customers": null
}
}| Camp | Què és |
|---|---|
id | L'identificador de l'execució, un UUID v7. |
object | Sempre managed_account_import. |
status | L'estat de l'execució: completed quan ha acabat. failed quan no ha pogut acabar, i llavors les files ja aplicades es queden aplicades. |
stats | Les xifres de l'execució: les files per estat, created, reconciled, customers_queued, monthly_amount_cents i proration_amount_cents. |
rows | Les files de la previsualització, en l'ordre del fitxer, amb claim_token i claim_url afegits. |
own_company_customers | Com a la previsualització. |
Els imports d'stats i de cada fila són els que ha cobrat l'aplicació: el prorrateig que va anunciar la previsualització, calculat de nou en aquell moment. A l'exemple, el compte gestionat de la línia 2 retorna el seu claim_token i el seu claim_url, i el NIF propi retorna null, perquè no té val.
El val de cada fila managed_account nova de producció torna una sola vegada, en aquesta resposta. Una repetició de la mateixa petició el retorna com a null, i també una fila quan send_email és true, perquè l'enllaç va per correu, i totes les files d'una importació de proves. Si en perds un, reemet-lo. La resposta no porta capçalera Location, perquè una execució no té operació pública de lectura. L'app desa l'historial i l'informe de cada importació, a Comptes de clients, Importar, Historial d'importacions, i quan una importació acaba publiquem account.import_completed als webhooks de compte del teu compte, amb l'id de l'execució i els seus stats.
Idempotency-Key i una importació alhora
L'aplicació no es pot desfer, així que exigeix una Idempotency-Key: sense ella la resposta és 422 idempotency_key_required abans de llegir res. La previsualització no la necessita. Què fa cada protecció:
| Què | Què fa |
|---|---|
Idempotency-Key | Si es talla la connexió i repeteixes la mateixa petició amb la mateixa clau, reproduïm la primera resposta, amb Idempotent-Replayed: true, i no apliquem res dues vegades. Cada val torna com a null: mai no el desem en clar, ni tan sols a la memòria cau d'idempotència. La mateixa clau amb una altra petició és 422 idempotency_key_reused. Mira idempotència. |
external_ref i el NIF | Fan que el fitxer concilii: una nova aplicació del mateix fitxer, fins i tot amb una clau nova, no crea res dues vegades ni cobra res dues vegades. |
| Una importació alhora | Les aplicacions del teu compte es serialitzen. Mentre una s'executa, la següent respon 409 import_in_progress i no aplica res. |
Després d'un 409, espera que acabi la importació en curs i envia una altra vegada els mateixos fitxers amb una Idempotency-Key nova: les files que la primera ja va aplicar tornen ALREADY_EXISTS, mai duplicades ni cobrades dues vegades. Una importació que mai no va acabar deixa de bloquejar als 15 minuts. Un 429 no aplica res: espera el que digui Retry-After i envia la petició una altra vegada.
Amb una clau de proves
Amb una clau fact_test_ la importació treballa sobre els teus comptes de proves, i no es cobra res:
- Les files
managed_accountcreen o concilien comptes de proves: sense cobrament, sense Stripe i sense val, així queclaim_tokeniclaim_urlsónnull. Un compte de proves no compta per amax_managed_accounts. - Les files
own_nifsurtenERRORambcodelive_credential_requiredi sumen 0 al total: els NIF del teu propi compte només es donen d'alta en producció. El mateix val per als clients queapply_customers_to_own_companycarregaria a la teva pròpia empresa. - L'entorn és el de la clau. Una importació de proves només veu els teus comptes de proves: un
external_refque pertany a un compte de producció surtBLOCKEDambmanaged_account_external_ref_in_other_environment, i a l'inrevés. - El cost és 0, a cada fila i als totals.
El flux complet amb una clau de proves és a provar comptes gestionats.
Dues coses que la importació no fa, per disseny
- Sense eina MCP. Les tres operacions són privilegiades i la importació llegeix dos fitxers pujats, que el servidor MCP no transporta. L'alternativa és l'API REST, o la importació de l'app. Des d'un agent, aprovisiona els comptes d'un en un amb l'eina
provision_managed_account, que reflecteixPOST /v1/accounts: mira des del servidor MCP. - Sense sèries. El fitxer no té columna ni opció per a sèries de documents: dona d'alta comptes i NIF, no la seva numeració. Crea o canvia les sèries d'un NIF importat amb les operacions de l'eix d'empresa, per exemple
POST /v1/companies/{company}/series/bootstrap, que crea en una crida les sèries per defecte que falten i necessitaseries:write.issuing-readinesset diu si a un NIF encara li'n falta una:no_default_seriesés un dels seus bloquejos, com explica què impedeix emetre a un NIF. El{company}d'un NIF importat és acompanies[].iddeGET /v1/accounts/{account}per a un compte gestionat, el{account}del qual és l'account_idde la fila, i aGET /v1/accounts/{account}/companiesper als teus NIF propis.
Errors
Les regles que rebutjarien una provisió solta rebutgen aquí una fila, mai la petició: arriben al 201 o al 200, a l'status i el code de la fila. Aquests són els errors de la petició:
| Codi | Status | Quan |
|---|---|---|
insufficient_scope | 403 | La clau no llista accounts:write, o accounts:read per a la plantilla. * no compta. |
privileged_scope_required | 403 | El teu compte no té el privilegi de proveïdor, o la persona que va emetre la clau ja no n'és titular ni administrador. |
invalid_param_value | 422 | Falta accounts_file o no és un fitxer, o options porta una clau desconeguda o un valor que no és booleà. error.param l'anomena. |
import_file_too_large | 413 | Un fitxer supera els 5 MB. error.param l'anomena. |
payload_too_large | 413 | Tota la petició supera els 11 MB. |
import_row_limit_exceeded | 422 | accounts_file té més de 100 files, o customers_file més de 1.000. |
import_file_invalid | 422 | El fitxer no es pot llegir, no té fila de capçalera o li falta una columna. |
idempotency_key_required | 422 | L'aplicació no porta Idempotency-Key. |
idempotency_key_reused | 422 | Aquesta clau ja es va fer servir amb una petició diferent. |
import_in_progress | 409 | Una altra importació del teu compte s'està executant. |
upload_in_flight_budget_exceeded | 429 | El teu compte ja està pujant massa bytes alhora. |
Un 429 sense un codi d'aquesta taula és un límit de la importació: una previsualització per sobre de 10 per minut, o una aplicació per sobre de 5 per minut o de 20 al dia. Espera el que digui Retry-After.
Propers passos
aprovisiona un compte cada vegada, el val de reclamació, el teu nivell d'accés i el fi de la gestió.
què pagues per cada compte gestionat i com es cobra un canvi de pla.
recorre tot el flux, amb una importació, amb una clau de proves i sense cobrament.
el que costa una fila own_nif, quins plans l'admeten i el topall.
rep account.import_completed i els esdeveniments dels comptes que aprovisiones.
tots els codis del model de comptes, amb la seva causa i què fer.