---
title: "Upload a company certificate"
method: POST
path: "/companies/{company}/verifactu/certificates"
tags: ["VeriFactu"]
---

# Upload a company certificate

`POST /companies/{company}/verifactu/certificates`

## Request

- Base URL: `https://api.factuarea.com/v1`
- URL: `https://api.factuarea.com/v1/companies/{company}/verifactu/certificates`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Upload an FNMT certificate (PKCS#12) as `multipart/form-data` with `certificate_file` and `certificate_password`.
- Validated by magic bytes and capped at 100 KB; the password is encrypted at rest.
- It is activated automatically (previous ones are deactivated); `Location` points to `.../verifactu/certificates/active`.

## Path parameters

- `company` string, uuid, required

## Headers

- `Idempotency-Key` string, required
- `Factuarea-Version` string, date

## Response `201`

FNMT certificate uploaded and activated successfully. The `Location` header contains the canonical (relative) URL of the active certificate.

- object
  - `data` CompanyCertificate, required: Metadata of an FNMT (PKCS#12) certificate used to sign VeriFactu transmissions. The certificate password and binary are never exposed — only X.509 metadata.
    - `id` string, required: UUID v7 of the certificate.
    - `object` 'verifactu_certificate', required
    - `subject_nif` string, required: Tax ID (NIF) of the X.509 certificate holder.
    - `subject_name` string, required: Name of the certificate holder.
    - `subject_kind` string, required: Type of holder (individual / legal entity / representative).
    - `valid_from` string, date-time, required: Certificate validity start date.
    - `valid_to` string, date-time, required: Certificate validity end date (expiration).
    - `is_active` boolean, required: Whether this is the active certificate used to sign transmissions.
    - `revoked_at` string, date-time, nullable, required: Revocation date, or `null` if not revoked.
    - `created_at` string, date-time, required: Date the certificate was uploaded.

## Other responses

- `400`: `parameter_unknown` with `subcode` `retired_active_profile_header`: the retired `X-Active-Profile` header was sent; the company goes in the path. `parameter_invalid_format` on `Factuarea-Version`: the header is not a `YYYY-MM-DD` date. `unsupported_api_version`: the `Factuarea-Version` date is not a supported version.
- `401`: Missing or invalid API key.
- `402`: The operation requires a payment that could not be completed: either no payment method is on file (`error.details.payment_setup_url` links to the Billing Portal where it can be set up), the immediate charge was declined by the payment provider, the account lacks the plan or add-on this operation bills against, the annual document limit is reached (`plan_limit_exceeded`, with `error.details.period_end` indicating the end of the period — wait until it has ended or upgrade the plan to continue now), or the account has reached its maximum usage (`storage_quota_exceeded`, raised by upload operations such as signing a delivery note or attaching a file to an expense — contact support before retrying). Nothing was created or modified — resolve the cause and retry the same request. Version note: `error.type` is `payment_required_error` from `Factuarea-Version: 2026-09-01` onwards; earlier versions receive `invalid_request_error` for the three codes that predate that cut (`payment_method_required`, `employee_seat_payment_method_required` and `employee_seat_charge_failed`; every other 402 code, such as `addon_required`, `plan_limit_exceeded` or the additional tax ID codes, is newer and always carries `payment_required_error`). `error.code` is stable across every version.
- `403`: The request is authenticated but not allowed: the API key lacks the required scope (`insufficient_scope`), the plan does not include the public API or this feature (`addon_not_active`, `feature_not_available_in_plan`), or the module is not available with a test key (`module_not_available_in_sandbox`).
- `404`: The requested resource does not exist or belongs to another company. `profile_not_found`: the company in the path does not exist, is not in the API key scope or belongs to the other environment (live or test).
- `409`: The request conflicts with data that already exists or with a request running at the same time. `resource_conflict`: another request was reserving identifiers for the same kind of record at that moment and this one could not complete its reservation. Nothing was written; send the request again after a few seconds.
- `422`: Validation failed. The `error.param` field identifies which input is invalid.
- `429`: Rate limit exceeded. Retry after the duration in `Retry-After`.
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/factuarea/apis/factuarea-public-api.md) · [All operations](https://skmtc.dev/factuarea/apis/factuarea-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/factuarea/apis/factuarea-public-api/revisions/718e77934422?raw)
