# Campos extras

Definição de campos extras do workspace e valores por empresa.

O recurso é cross-cutting: a collection `meta_fields` define os campos do workspace, `companies.meta_fields` guarda os valores da empresa, e webhooks apenas consomem campos marcados com `send_webhook: true`. `target` e `webhook_level` só afetam a entrega quando `send_webhook` está habilitado.

## Listar campos extras

> Lista os campos extras configurados no workspace da chave autenticada.\
> \
> Campos extras são definidos pelo workspace e podem ser preenchidos por empresa em \`companies.meta\_fields\`.\
> Eles só enriquecem webhooks quando a definição estiver com \`send\_webhook: true\`.\
> Quando enviados, podem ir na raiz do body, dentro de \`payload\` ou como headers HTTP.\
> \
> Regras de escopo com \`x-api-key\`:\
> \- Chave de workspace pode listar todos os campos configurados no workspace.\
> \- Chave de empresa não pode listar campos extras.\
> \- Valores sensíveis são retornados mascarados como \`\*\*\*\*\*\*\*\*\`.

```json
{"openapi":"3.1.1","info":{"title":"API IXC E-Docs - Integração x-api-key","version":"0.1.0"},"tags":[{"name":"Campos extras","description":"Definição de campos extras do workspace e valores por empresa.\n\nO recurso é cross-cutting: a collection `meta_fields` define os campos do workspace, `companies.meta_fields` guarda os valores da empresa, e webhooks apenas consomem campos marcados com `send_webhook: true`.\n`target` e `webhook_level` só afetam a entrega quando `send_webhook` está habilitado."}],"servers":[{"url":"https://sandbox.api.edocs.ixcsoft.com.br","description":"Sandbox — simulação interna, aceita certificado self-signed, sem comunicação com a prefeitura."},{"url":"https://api.edocs.ixcsoft.com.br","description":"Produção / Homologação — ambiente real, controlado por `nfse_config.environment`."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Chave de API enviada no header `x-api-key`.\n\nExistem dois níveis de chave:\n- Workspace: permite emitir NFS-e para várias empresas do mesmo workspace e pode associar webhooks/integrações via `company_id` ou `tax_id`.\n- Empresa: permite emitir NFS-e e gerir certificados apenas para a raiz do CNPJ vinculado e autoassocia webhooks/integrações à própria empresa.\n- Se a integração tiver `allowed_ips`, o acesso só é liberado quando o IP resolvido por `request.ip` estiver dentro da allowlist configurada.\n\nPara gerar a chave de workspace, crie uma integração no painel\n(sem `company_id`) e utilize o `api_key` retornado."}},"parameters":{"AcceptLanguage":{"name":"Accept-Language","in":"header","required":false,"description":"Idioma preferencial para mensagens de erro (ex.: pt-BR).","schema":{"type":"string"}}},"schemas":{"MetaFieldListResponse":{"type":"object","additionalProperties":false,"required":["items","paginate"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/MetaFieldDefinition"}},"paginate":{"$ref":"#/components/schemas/CursorPaginateMeta"}}},"MetaFieldDefinition":{"type":"object","description":"Definição de um campo extra configurado no workspace.\n\nUm campo extra representa um campo personalizado que cada empresa do workspace pode ou deve preencher em `companies.meta_fields`.\nO valor preenchido pela empresa só é enviado em webhooks quando `send_webhook: true`.\n\nExemplo: um campo `token_erp` com `required: true`, `encrypted: true`, `send_webhook: true` e `target: header`\nexige que cada empresa informe seu token, que será enviado como header HTTP nos webhooks.","additionalProperties":false,"required":["key","label","value_type","use_company_crud","required","send_webhook","target","webhook_level","encrypted"],"properties":{"id":{"$ref":"#/components/schemas/ObjectId"},"key":{"type":"string","description":"Identificador único do campo. Usado como chave em `company.meta_fields`.","pattern":"^[A-Za-z][A-Za-z0-9_-]{0,127}$"},"label":{"type":"string","description":"Nome amigável do campo exibido no painel."},"value_type":{"type":"string","enum":["dynamic","fixed"],"description":"`dynamic`: valor preenchido por empresa no campo `company.meta_fields[key]`.\n`fixed`: valor definido na configuração do workspace, igual para todas as empresas."},"use_company_crud":{"type":"boolean","description":"Quando `true`, o campo é preenchido via cadastro da empresa (POST/PUT /companies)."},"fixed_value":{"type":["string","null"],"description":"Valor fixo usado quando `value_type` é `fixed`. Mascarado (`********`) quando `encrypted: true`."},"required":{"type":"boolean","description":"Quando `true` e `use_company_crud: true`, o campo deve ser preenchido em `company.meta_fields` ao criar ou atualizar a empresa."},"send_webhook":{"type":"boolean","description":"Quando `true`, o campo é incluído no payload do webhook."},"target":{"type":"string","enum":["body","body.payload","header"],"description":"Destino do campo no payload do webhook:\n- `body`: raiz do body JSON.\n- `body.payload`: dentro do objeto `payload`.\n- `header`: como HTTP header.\n\nSó tem efeito quando `send_webhook: true`.\nQuando o destino é `header`, o campo extra é aplicado por último e sobrescreve headers internos de forma case-insensitive."},"webhook_level":{"type":"string","enum":["company","workspace","all"],"description":"Escopo de webhooks em que o campo é enviado. Só tem efeito quando `send_webhook: true`."},"encrypted":{"type":"boolean","description":"Quando `true`, o valor é armazenado cifrado e mascarado na resposta da API."}}},"ObjectId":{"type":"string","description":"Identificador no formato ObjectId."},"CursorPaginateMeta":{"type":"object","additionalProperties":false,"required":["limit","has_next_page","has_previous_page","start_cursor","end_cursor"],"properties":{"limit":{"type":"integer","minimum":10,"maximum":100},"has_next_page":{"type":"boolean"},"has_previous_page":{"type":"boolean"},"start_cursor":{"type":["string","null"]},"end_cursor":{"type":["string","null"]}}},"ValidationErrorResponse":{"allOf":[{"$ref":"#/components/schemas/ErrorResponse"}],"description":"Erro de validação (Zod ou validador de domínio). No `POST /nfse`, `error.code` é `NFSE_VALIDATION_FAILED`; `error.details[]` carrega cada campo inválido com códigos catalogados ou `VALIDATION_*` e `params.field`."},"ErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message","status"],"properties":{"code":{"type":"string","description":"Código machine-readable do erro. Detalhes em `docs/ERRORS.md`."},"message":{"type":"string","description":"Mensagem traduzida conforme Accept-Language."},"status":{"type":"integer","description":"HTTP status code."},"params":{"type":"object","description":"Dados estruturados do erro (campos referenciados, identificadores, contexto técnico). Reflete a interpolação `{{var}}` aplicada ao template da mensagem.","additionalProperties":true},"details":{"type":"array","description":"Lista de falhas estruturadas adicionais (presente quando há múltiplas falhas, ex.: validação Zod, múltiplas empresas inválidas).","items":{"$ref":"#/components/schemas/ErrorDetail"}}}}}},"ErrorDetail":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Código machine-readable do detalhe."},"message":{"type":"string","description":"Mensagem traduzida do detalhe conforme Accept-Language."},"params":{"type":"object","description":"Dados estruturados do detalhe (campo referenciado, identificadores, etc.).","additionalProperties":true}}}},"responses":{"ValidationError":{"description":"Erro de validação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"UnauthorizedError":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ForbiddenError":{"description":"Não autorizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Erro interno inesperado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ServiceUnderMaintenance":{"description":"Sistema em manutenção programada","headers":{"Retry-After":{"description":"Data e hora prevista para o fim da manutenção no formato HTTP-date (RFC 7231).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/meta-fields":{"get":{"operationId":"listMetaFields","tags":["Campos extras"],"summary":"Listar campos extras","description":"Lista os campos extras configurados no workspace da chave autenticada.\n\nCampos extras são definidos pelo workspace e podem ser preenchidos por empresa em `companies.meta_fields`.\nEles só enriquecem webhooks quando a definição estiver com `send_webhook: true`.\nQuando enviados, podem ir na raiz do body, dentro de `payload` ou como headers HTTP.\n\nRegras de escopo com `x-api-key`:\n- Chave de workspace pode listar todos os campos configurados no workspace.\n- Chave de empresa não pode listar campos extras.\n- Valores sensíveis são retornados mascarados como `********`.","parameters":[{"$ref":"#/components/parameters/AcceptLanguage"},{"name":"cursor","in":"query","required":false,"description":"Cursor opaco de paginação.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Quantidade de itens por página (10 a 100).","schema":{"type":"integer","minimum":10,"maximum":100,"default":10}},{"name":"fields","in":"query","required":false,"description":"Seleção de campos, separados por vírgula.","schema":{"type":"string"}}],"responses":{"200":{"description":"Lista de campos extras","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetaFieldListResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnderMaintenance"}}}}}}
```

## Criar campo extra

> Cria um campo extra no workspace da chave autenticada.\
> \
> Regras:\
> \- Chave de workspace pode criar campos extras.\
> \- Chave de empresa não pode criar campos extras.\
> \- A chave é única por workspace de forma case-insensitive.\
> \- O workspace pode ter no máximo 50 campos extras.\
> \- Campos \`fixed\` exigem \`fixed\_value\`.\
> \- \`target\` e \`webhook\_level\` só têm efeito quando \`send\_webhook: true\`.

```json
{"openapi":"3.1.1","info":{"title":"API IXC E-Docs - Integração x-api-key","version":"0.1.0"},"tags":[{"name":"Campos extras","description":"Definição de campos extras do workspace e valores por empresa.\n\nO recurso é cross-cutting: a collection `meta_fields` define os campos do workspace, `companies.meta_fields` guarda os valores da empresa, e webhooks apenas consomem campos marcados com `send_webhook: true`.\n`target` e `webhook_level` só afetam a entrega quando `send_webhook` está habilitado."}],"servers":[{"url":"https://sandbox.api.edocs.ixcsoft.com.br","description":"Sandbox — simulação interna, aceita certificado self-signed, sem comunicação com a prefeitura."},{"url":"https://api.edocs.ixcsoft.com.br","description":"Produção / Homologação — ambiente real, controlado por `nfse_config.environment`."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Chave de API enviada no header `x-api-key`.\n\nExistem dois níveis de chave:\n- Workspace: permite emitir NFS-e para várias empresas do mesmo workspace e pode associar webhooks/integrações via `company_id` ou `tax_id`.\n- Empresa: permite emitir NFS-e e gerir certificados apenas para a raiz do CNPJ vinculado e autoassocia webhooks/integrações à própria empresa.\n- Se a integração tiver `allowed_ips`, o acesso só é liberado quando o IP resolvido por `request.ip` estiver dentro da allowlist configurada.\n\nPara gerar a chave de workspace, crie uma integração no painel\n(sem `company_id`) e utilize o `api_key` retornado."}},"parameters":{"AcceptLanguage":{"name":"Accept-Language","in":"header","required":false,"description":"Idioma preferencial para mensagens de erro (ex.: pt-BR).","schema":{"type":"string"}}},"schemas":{"MetaFieldRequest":{"type":"object","additionalProperties":false,"required":["key","label"],"properties":{"key":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_-]{0,127}$","description":"Identificador único por workspace, case-insensitive."},"label":{"type":"string","minLength":1,"maxLength":120},"value_type":{"type":"string","enum":["dynamic","fixed"],"default":"dynamic"},"use_company_crud":{"type":"boolean","default":true,"description":"Quando `true`, campos dinâmicos podem ser preenchidos em `company.meta_fields`."},"fixed_value":{"type":["string","null"],"maxLength":1024,"description":"Obrigatório quando `value_type` é `fixed`. Pode vir mascarado como `********` em atualização para preservar valor sensível existente."},"required":{"type":"boolean","default":false,"description":"Só torna o campo obrigatório quando `value_type=dynamic` e `use_company_crud=true`."},"send_webhook":{"type":"boolean","default":true},"target":{"type":"string","enum":["body","body.payload","header"],"default":"body","description":"Destino usado na entrega de webhook quando `send_webhook: true`."},"webhook_level":{"type":"string","enum":["company","workspace","all"],"default":"all","description":"Escopo usado na entrega de webhook quando `send_webhook: true`."},"encrypted":{"type":"boolean","default":false}}},"MetaFieldDefinition":{"type":"object","description":"Definição de um campo extra configurado no workspace.\n\nUm campo extra representa um campo personalizado que cada empresa do workspace pode ou deve preencher em `companies.meta_fields`.\nO valor preenchido pela empresa só é enviado em webhooks quando `send_webhook: true`.\n\nExemplo: um campo `token_erp` com `required: true`, `encrypted: true`, `send_webhook: true` e `target: header`\nexige que cada empresa informe seu token, que será enviado como header HTTP nos webhooks.","additionalProperties":false,"required":["key","label","value_type","use_company_crud","required","send_webhook","target","webhook_level","encrypted"],"properties":{"id":{"$ref":"#/components/schemas/ObjectId"},"key":{"type":"string","description":"Identificador único do campo. Usado como chave em `company.meta_fields`.","pattern":"^[A-Za-z][A-Za-z0-9_-]{0,127}$"},"label":{"type":"string","description":"Nome amigável do campo exibido no painel."},"value_type":{"type":"string","enum":["dynamic","fixed"],"description":"`dynamic`: valor preenchido por empresa no campo `company.meta_fields[key]`.\n`fixed`: valor definido na configuração do workspace, igual para todas as empresas."},"use_company_crud":{"type":"boolean","description":"Quando `true`, o campo é preenchido via cadastro da empresa (POST/PUT /companies)."},"fixed_value":{"type":["string","null"],"description":"Valor fixo usado quando `value_type` é `fixed`. Mascarado (`********`) quando `encrypted: true`."},"required":{"type":"boolean","description":"Quando `true` e `use_company_crud: true`, o campo deve ser preenchido em `company.meta_fields` ao criar ou atualizar a empresa."},"send_webhook":{"type":"boolean","description":"Quando `true`, o campo é incluído no payload do webhook."},"target":{"type":"string","enum":["body","body.payload","header"],"description":"Destino do campo no payload do webhook:\n- `body`: raiz do body JSON.\n- `body.payload`: dentro do objeto `payload`.\n- `header`: como HTTP header.\n\nSó tem efeito quando `send_webhook: true`.\nQuando o destino é `header`, o campo extra é aplicado por último e sobrescreve headers internos de forma case-insensitive."},"webhook_level":{"type":"string","enum":["company","workspace","all"],"description":"Escopo de webhooks em que o campo é enviado. Só tem efeito quando `send_webhook: true`."},"encrypted":{"type":"boolean","description":"Quando `true`, o valor é armazenado cifrado e mascarado na resposta da API."}}},"ObjectId":{"type":"string","description":"Identificador no formato ObjectId."},"ValidationErrorResponse":{"allOf":[{"$ref":"#/components/schemas/ErrorResponse"}],"description":"Erro de validação (Zod ou validador de domínio). No `POST /nfse`, `error.code` é `NFSE_VALIDATION_FAILED`; `error.details[]` carrega cada campo inválido com códigos catalogados ou `VALIDATION_*` e `params.field`."},"ErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message","status"],"properties":{"code":{"type":"string","description":"Código machine-readable do erro. Detalhes em `docs/ERRORS.md`."},"message":{"type":"string","description":"Mensagem traduzida conforme Accept-Language."},"status":{"type":"integer","description":"HTTP status code."},"params":{"type":"object","description":"Dados estruturados do erro (campos referenciados, identificadores, contexto técnico). Reflete a interpolação `{{var}}` aplicada ao template da mensagem.","additionalProperties":true},"details":{"type":"array","description":"Lista de falhas estruturadas adicionais (presente quando há múltiplas falhas, ex.: validação Zod, múltiplas empresas inválidas).","items":{"$ref":"#/components/schemas/ErrorDetail"}}}}}},"ErrorDetail":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Código machine-readable do detalhe."},"message":{"type":"string","description":"Mensagem traduzida do detalhe conforme Accept-Language."},"params":{"type":"object","description":"Dados estruturados do detalhe (campo referenciado, identificadores, etc.).","additionalProperties":true}}}},"responses":{"ValidationError":{"description":"Erro de validação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"UnauthorizedError":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ForbiddenError":{"description":"Não autorizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Erro interno inesperado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ServiceUnderMaintenance":{"description":"Sistema em manutenção programada","headers":{"Retry-After":{"description":"Data e hora prevista para o fim da manutenção no formato HTTP-date (RFC 7231).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/meta-fields":{"post":{"operationId":"createMetaField","tags":["Campos extras"],"summary":"Criar campo extra","description":"Cria um campo extra no workspace da chave autenticada.\n\nRegras:\n- Chave de workspace pode criar campos extras.\n- Chave de empresa não pode criar campos extras.\n- A chave é única por workspace de forma case-insensitive.\n- O workspace pode ter no máximo 50 campos extras.\n- Campos `fixed` exigem `fixed_value`.\n- `target` e `webhook_level` só têm efeito quando `send_webhook: true`.","parameters":[{"$ref":"#/components/parameters/AcceptLanguage"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetaFieldRequest"}}}},"responses":{"201":{"description":"Campo extra criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetaFieldDefinition"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"409":{"description":"Campo extra já existe no workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Limite de campos extras atingido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnderMaintenance"}}}}}}
```

## Consultar campo extra

> Retorna um campo extra do workspace da chave autenticada, com valores sensíveis mascarados.

```json
{"openapi":"3.1.1","info":{"title":"API IXC E-Docs - Integração x-api-key","version":"0.1.0"},"tags":[{"name":"Campos extras","description":"Definição de campos extras do workspace e valores por empresa.\n\nO recurso é cross-cutting: a collection `meta_fields` define os campos do workspace, `companies.meta_fields` guarda os valores da empresa, e webhooks apenas consomem campos marcados com `send_webhook: true`.\n`target` e `webhook_level` só afetam a entrega quando `send_webhook` está habilitado."}],"servers":[{"url":"https://sandbox.api.edocs.ixcsoft.com.br","description":"Sandbox — simulação interna, aceita certificado self-signed, sem comunicação com a prefeitura."},{"url":"https://api.edocs.ixcsoft.com.br","description":"Produção / Homologação — ambiente real, controlado por `nfse_config.environment`."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Chave de API enviada no header `x-api-key`.\n\nExistem dois níveis de chave:\n- Workspace: permite emitir NFS-e para várias empresas do mesmo workspace e pode associar webhooks/integrações via `company_id` ou `tax_id`.\n- Empresa: permite emitir NFS-e e gerir certificados apenas para a raiz do CNPJ vinculado e autoassocia webhooks/integrações à própria empresa.\n- Se a integração tiver `allowed_ips`, o acesso só é liberado quando o IP resolvido por `request.ip` estiver dentro da allowlist configurada.\n\nPara gerar a chave de workspace, crie uma integração no painel\n(sem `company_id`) e utilize o `api_key` retornado."}},"parameters":{"MetaFieldId":{"name":"meta_field_id","in":"path","required":true,"description":"ID do campo extra no workspace.","schema":{"$ref":"#/components/schemas/ObjectId"}},"AcceptLanguage":{"name":"Accept-Language","in":"header","required":false,"description":"Idioma preferencial para mensagens de erro (ex.: pt-BR).","schema":{"type":"string"}}},"schemas":{"ObjectId":{"type":"string","description":"Identificador no formato ObjectId."},"MetaFieldDefinition":{"type":"object","description":"Definição de um campo extra configurado no workspace.\n\nUm campo extra representa um campo personalizado que cada empresa do workspace pode ou deve preencher em `companies.meta_fields`.\nO valor preenchido pela empresa só é enviado em webhooks quando `send_webhook: true`.\n\nExemplo: um campo `token_erp` com `required: true`, `encrypted: true`, `send_webhook: true` e `target: header`\nexige que cada empresa informe seu token, que será enviado como header HTTP nos webhooks.","additionalProperties":false,"required":["key","label","value_type","use_company_crud","required","send_webhook","target","webhook_level","encrypted"],"properties":{"id":{"$ref":"#/components/schemas/ObjectId"},"key":{"type":"string","description":"Identificador único do campo. Usado como chave em `company.meta_fields`.","pattern":"^[A-Za-z][A-Za-z0-9_-]{0,127}$"},"label":{"type":"string","description":"Nome amigável do campo exibido no painel."},"value_type":{"type":"string","enum":["dynamic","fixed"],"description":"`dynamic`: valor preenchido por empresa no campo `company.meta_fields[key]`.\n`fixed`: valor definido na configuração do workspace, igual para todas as empresas."},"use_company_crud":{"type":"boolean","description":"Quando `true`, o campo é preenchido via cadastro da empresa (POST/PUT /companies)."},"fixed_value":{"type":["string","null"],"description":"Valor fixo usado quando `value_type` é `fixed`. Mascarado (`********`) quando `encrypted: true`."},"required":{"type":"boolean","description":"Quando `true` e `use_company_crud: true`, o campo deve ser preenchido em `company.meta_fields` ao criar ou atualizar a empresa."},"send_webhook":{"type":"boolean","description":"Quando `true`, o campo é incluído no payload do webhook."},"target":{"type":"string","enum":["body","body.payload","header"],"description":"Destino do campo no payload do webhook:\n- `body`: raiz do body JSON.\n- `body.payload`: dentro do objeto `payload`.\n- `header`: como HTTP header.\n\nSó tem efeito quando `send_webhook: true`.\nQuando o destino é `header`, o campo extra é aplicado por último e sobrescreve headers internos de forma case-insensitive."},"webhook_level":{"type":"string","enum":["company","workspace","all"],"description":"Escopo de webhooks em que o campo é enviado. Só tem efeito quando `send_webhook: true`."},"encrypted":{"type":"boolean","description":"Quando `true`, o valor é armazenado cifrado e mascarado na resposta da API."}}},"ErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message","status"],"properties":{"code":{"type":"string","description":"Código machine-readable do erro. Detalhes em `docs/ERRORS.md`."},"message":{"type":"string","description":"Mensagem traduzida conforme Accept-Language."},"status":{"type":"integer","description":"HTTP status code."},"params":{"type":"object","description":"Dados estruturados do erro (campos referenciados, identificadores, contexto técnico). Reflete a interpolação `{{var}}` aplicada ao template da mensagem.","additionalProperties":true},"details":{"type":"array","description":"Lista de falhas estruturadas adicionais (presente quando há múltiplas falhas, ex.: validação Zod, múltiplas empresas inválidas).","items":{"$ref":"#/components/schemas/ErrorDetail"}}}}}},"ErrorDetail":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Código machine-readable do detalhe."},"message":{"type":"string","description":"Mensagem traduzida do detalhe conforme Accept-Language."},"params":{"type":"object","description":"Dados estruturados do detalhe (campo referenciado, identificadores, etc.).","additionalProperties":true}}}},"responses":{"UnauthorizedError":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ForbiddenError":{"description":"Não autorizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Erro interno inesperado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ServiceUnderMaintenance":{"description":"Sistema em manutenção programada","headers":{"Retry-After":{"description":"Data e hora prevista para o fim da manutenção no formato HTTP-date (RFC 7231).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/meta-fields/{meta_field_id}":{"get":{"operationId":"getMetaField","tags":["Campos extras"],"summary":"Consultar campo extra","description":"Retorna um campo extra do workspace da chave autenticada, com valores sensíveis mascarados.","parameters":[{"$ref":"#/components/parameters/MetaFieldId"},{"$ref":"#/components/parameters/AcceptLanguage"}],"responses":{"200":{"description":"Campo extra encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetaFieldDefinition"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Campo extra não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnderMaintenance"}}}}}}
```

## Atualizar campo extra

> Atualiza um campo extra do workspace da chave autenticada.\
> \
> Chave de empresa não pode alterar campos extras. Quando \`fixed\_value\` vier\
> mascarado como \`\*\*\*\*\*\*\*\*\`, o valor fixo sensível já persistido deve ser\
> preservado.

```json
{"openapi":"3.1.1","info":{"title":"API IXC E-Docs - Integração x-api-key","version":"0.1.0"},"tags":[{"name":"Campos extras","description":"Definição de campos extras do workspace e valores por empresa.\n\nO recurso é cross-cutting: a collection `meta_fields` define os campos do workspace, `companies.meta_fields` guarda os valores da empresa, e webhooks apenas consomem campos marcados com `send_webhook: true`.\n`target` e `webhook_level` só afetam a entrega quando `send_webhook` está habilitado."}],"servers":[{"url":"https://sandbox.api.edocs.ixcsoft.com.br","description":"Sandbox — simulação interna, aceita certificado self-signed, sem comunicação com a prefeitura."},{"url":"https://api.edocs.ixcsoft.com.br","description":"Produção / Homologação — ambiente real, controlado por `nfse_config.environment`."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Chave de API enviada no header `x-api-key`.\n\nExistem dois níveis de chave:\n- Workspace: permite emitir NFS-e para várias empresas do mesmo workspace e pode associar webhooks/integrações via `company_id` ou `tax_id`.\n- Empresa: permite emitir NFS-e e gerir certificados apenas para a raiz do CNPJ vinculado e autoassocia webhooks/integrações à própria empresa.\n- Se a integração tiver `allowed_ips`, o acesso só é liberado quando o IP resolvido por `request.ip` estiver dentro da allowlist configurada.\n\nPara gerar a chave de workspace, crie uma integração no painel\n(sem `company_id`) e utilize o `api_key` retornado."}},"parameters":{"MetaFieldId":{"name":"meta_field_id","in":"path","required":true,"description":"ID do campo extra no workspace.","schema":{"$ref":"#/components/schemas/ObjectId"}},"AcceptLanguage":{"name":"Accept-Language","in":"header","required":false,"description":"Idioma preferencial para mensagens de erro (ex.: pt-BR).","schema":{"type":"string"}}},"schemas":{"ObjectId":{"type":"string","description":"Identificador no formato ObjectId."},"MetaFieldRequest":{"type":"object","additionalProperties":false,"required":["key","label"],"properties":{"key":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_-]{0,127}$","description":"Identificador único por workspace, case-insensitive."},"label":{"type":"string","minLength":1,"maxLength":120},"value_type":{"type":"string","enum":["dynamic","fixed"],"default":"dynamic"},"use_company_crud":{"type":"boolean","default":true,"description":"Quando `true`, campos dinâmicos podem ser preenchidos em `company.meta_fields`."},"fixed_value":{"type":["string","null"],"maxLength":1024,"description":"Obrigatório quando `value_type` é `fixed`. Pode vir mascarado como `********` em atualização para preservar valor sensível existente."},"required":{"type":"boolean","default":false,"description":"Só torna o campo obrigatório quando `value_type=dynamic` e `use_company_crud=true`."},"send_webhook":{"type":"boolean","default":true},"target":{"type":"string","enum":["body","body.payload","header"],"default":"body","description":"Destino usado na entrega de webhook quando `send_webhook: true`."},"webhook_level":{"type":"string","enum":["company","workspace","all"],"default":"all","description":"Escopo usado na entrega de webhook quando `send_webhook: true`."},"encrypted":{"type":"boolean","default":false}}},"MetaFieldDefinition":{"type":"object","description":"Definição de um campo extra configurado no workspace.\n\nUm campo extra representa um campo personalizado que cada empresa do workspace pode ou deve preencher em `companies.meta_fields`.\nO valor preenchido pela empresa só é enviado em webhooks quando `send_webhook: true`.\n\nExemplo: um campo `token_erp` com `required: true`, `encrypted: true`, `send_webhook: true` e `target: header`\nexige que cada empresa informe seu token, que será enviado como header HTTP nos webhooks.","additionalProperties":false,"required":["key","label","value_type","use_company_crud","required","send_webhook","target","webhook_level","encrypted"],"properties":{"id":{"$ref":"#/components/schemas/ObjectId"},"key":{"type":"string","description":"Identificador único do campo. Usado como chave em `company.meta_fields`.","pattern":"^[A-Za-z][A-Za-z0-9_-]{0,127}$"},"label":{"type":"string","description":"Nome amigável do campo exibido no painel."},"value_type":{"type":"string","enum":["dynamic","fixed"],"description":"`dynamic`: valor preenchido por empresa no campo `company.meta_fields[key]`.\n`fixed`: valor definido na configuração do workspace, igual para todas as empresas."},"use_company_crud":{"type":"boolean","description":"Quando `true`, o campo é preenchido via cadastro da empresa (POST/PUT /companies)."},"fixed_value":{"type":["string","null"],"description":"Valor fixo usado quando `value_type` é `fixed`. Mascarado (`********`) quando `encrypted: true`."},"required":{"type":"boolean","description":"Quando `true` e `use_company_crud: true`, o campo deve ser preenchido em `company.meta_fields` ao criar ou atualizar a empresa."},"send_webhook":{"type":"boolean","description":"Quando `true`, o campo é incluído no payload do webhook."},"target":{"type":"string","enum":["body","body.payload","header"],"description":"Destino do campo no payload do webhook:\n- `body`: raiz do body JSON.\n- `body.payload`: dentro do objeto `payload`.\n- `header`: como HTTP header.\n\nSó tem efeito quando `send_webhook: true`.\nQuando o destino é `header`, o campo extra é aplicado por último e sobrescreve headers internos de forma case-insensitive."},"webhook_level":{"type":"string","enum":["company","workspace","all"],"description":"Escopo de webhooks em que o campo é enviado. Só tem efeito quando `send_webhook: true`."},"encrypted":{"type":"boolean","description":"Quando `true`, o valor é armazenado cifrado e mascarado na resposta da API."}}},"ValidationErrorResponse":{"allOf":[{"$ref":"#/components/schemas/ErrorResponse"}],"description":"Erro de validação (Zod ou validador de domínio). No `POST /nfse`, `error.code` é `NFSE_VALIDATION_FAILED`; `error.details[]` carrega cada campo inválido com códigos catalogados ou `VALIDATION_*` e `params.field`."},"ErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message","status"],"properties":{"code":{"type":"string","description":"Código machine-readable do erro. Detalhes em `docs/ERRORS.md`."},"message":{"type":"string","description":"Mensagem traduzida conforme Accept-Language."},"status":{"type":"integer","description":"HTTP status code."},"params":{"type":"object","description":"Dados estruturados do erro (campos referenciados, identificadores, contexto técnico). Reflete a interpolação `{{var}}` aplicada ao template da mensagem.","additionalProperties":true},"details":{"type":"array","description":"Lista de falhas estruturadas adicionais (presente quando há múltiplas falhas, ex.: validação Zod, múltiplas empresas inválidas).","items":{"$ref":"#/components/schemas/ErrorDetail"}}}}}},"ErrorDetail":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Código machine-readable do detalhe."},"message":{"type":"string","description":"Mensagem traduzida do detalhe conforme Accept-Language."},"params":{"type":"object","description":"Dados estruturados do detalhe (campo referenciado, identificadores, etc.).","additionalProperties":true}}}},"responses":{"ValidationError":{"description":"Erro de validação","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"UnauthorizedError":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ForbiddenError":{"description":"Não autorizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Erro interno inesperado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ServiceUnderMaintenance":{"description":"Sistema em manutenção programada","headers":{"Retry-After":{"description":"Data e hora prevista para o fim da manutenção no formato HTTP-date (RFC 7231).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/meta-fields/{meta_field_id}":{"put":{"operationId":"updateMetaField","tags":["Campos extras"],"summary":"Atualizar campo extra","description":"Atualiza um campo extra do workspace da chave autenticada.\n\nChave de empresa não pode alterar campos extras. Quando `fixed_value` vier\nmascarado como `********`, o valor fixo sensível já persistido deve ser\npreservado.","parameters":[{"$ref":"#/components/parameters/MetaFieldId"},{"$ref":"#/components/parameters/AcceptLanguage"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetaFieldRequest"}}}},"responses":{"200":{"description":"Campo extra atualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetaFieldDefinition"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Campo extra não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Nova chave já existe em outro campo extra do workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnderMaintenance"}}}}}}
```

## Excluir campo extra

> Remove um campo extra do workspace da chave autenticada. Chave de empresa não pode remover campos extras.

```json
{"openapi":"3.1.1","info":{"title":"API IXC E-Docs - Integração x-api-key","version":"0.1.0"},"tags":[{"name":"Campos extras","description":"Definição de campos extras do workspace e valores por empresa.\n\nO recurso é cross-cutting: a collection `meta_fields` define os campos do workspace, `companies.meta_fields` guarda os valores da empresa, e webhooks apenas consomem campos marcados com `send_webhook: true`.\n`target` e `webhook_level` só afetam a entrega quando `send_webhook` está habilitado."}],"servers":[{"url":"https://sandbox.api.edocs.ixcsoft.com.br","description":"Sandbox — simulação interna, aceita certificado self-signed, sem comunicação com a prefeitura."},{"url":"https://api.edocs.ixcsoft.com.br","description":"Produção / Homologação — ambiente real, controlado por `nfse_config.environment`."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Chave de API enviada no header `x-api-key`.\n\nExistem dois níveis de chave:\n- Workspace: permite emitir NFS-e para várias empresas do mesmo workspace e pode associar webhooks/integrações via `company_id` ou `tax_id`.\n- Empresa: permite emitir NFS-e e gerir certificados apenas para a raiz do CNPJ vinculado e autoassocia webhooks/integrações à própria empresa.\n- Se a integração tiver `allowed_ips`, o acesso só é liberado quando o IP resolvido por `request.ip` estiver dentro da allowlist configurada.\n\nPara gerar a chave de workspace, crie uma integração no painel\n(sem `company_id`) e utilize o `api_key` retornado."}},"parameters":{"MetaFieldId":{"name":"meta_field_id","in":"path","required":true,"description":"ID do campo extra no workspace.","schema":{"$ref":"#/components/schemas/ObjectId"}},"AcceptLanguage":{"name":"Accept-Language","in":"header","required":false,"description":"Idioma preferencial para mensagens de erro (ex.: pt-BR).","schema":{"type":"string"}}},"schemas":{"ObjectId":{"type":"string","description":"Identificador no formato ObjectId."},"ErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message","status"],"properties":{"code":{"type":"string","description":"Código machine-readable do erro. Detalhes em `docs/ERRORS.md`."},"message":{"type":"string","description":"Mensagem traduzida conforme Accept-Language."},"status":{"type":"integer","description":"HTTP status code."},"params":{"type":"object","description":"Dados estruturados do erro (campos referenciados, identificadores, contexto técnico). Reflete a interpolação `{{var}}` aplicada ao template da mensagem.","additionalProperties":true},"details":{"type":"array","description":"Lista de falhas estruturadas adicionais (presente quando há múltiplas falhas, ex.: validação Zod, múltiplas empresas inválidas).","items":{"$ref":"#/components/schemas/ErrorDetail"}}}}}},"ErrorDetail":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","description":"Código machine-readable do detalhe."},"message":{"type":"string","description":"Mensagem traduzida do detalhe conforme Accept-Language."},"params":{"type":"object","description":"Dados estruturados do detalhe (campo referenciado, identificadores, etc.).","additionalProperties":true}}}},"responses":{"UnauthorizedError":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ForbiddenError":{"description":"Não autorizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalServerError":{"description":"Erro interno inesperado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ServiceUnderMaintenance":{"description":"Sistema em manutenção programada","headers":{"Retry-After":{"description":"Data e hora prevista para o fim da manutenção no formato HTTP-date (RFC 7231).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/meta-fields/{meta_field_id}":{"delete":{"operationId":"deleteMetaField","tags":["Campos extras"],"summary":"Excluir campo extra","description":"Remove um campo extra do workspace da chave autenticada. Chave de empresa não pode remover campos extras.","parameters":[{"$ref":"#/components/parameters/MetaFieldId"},{"$ref":"#/components/parameters/AcceptLanguage"}],"responses":{"204":{"description":"Campo extra removido"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Campo extra não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnderMaintenance"}}}}}}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ixc-soft.gitbook.io/e-docs/campos-extras.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
