Credentials
The API uses two kinds of credentials associated with an entity (RFC):
| Kind | What it is | Used for |
|---|---|---|
| CIEC | The entity's SAT portal password (8 characters) | SAT extractions (invoices, CSF, compliance opinion, certificates) |
| CSD | Certificado de Sello Digital — the .cer/.key pair issued by the SAT |
Issuing and cancelling CFDI 4.0 |
CIEC and CSD serve different purposes. You need a CIEC to pull SAT data and a CSD to stamp or cancel invoices. Both are stored on the entity record, but via different endpoints.
CIEC — entity registration and management
The CIEC password is stored when you create an entity and updated via PATCH. The SAT validates
it asynchronously; poll credential_status until it settles.
Create an entity (registers the CIEC)
POST /v1/entities
{
"tax_id": "XEXX010101000",
"name": "MI EMPRESA SA DE CV",
"ciec_password": "Pass1234"
}
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
tax_id |
string | yes | RFC of the entity, 12–13 characters. Uppercased automatically. Must be unique within your organization. |
name |
string | yes | Legal name of the entity, up to 255 characters. |
ciec_password |
string | yes | SAT portal password (CIEC), exactly 8 characters. |
Response — 201 Created
{
"id": "9b1c0e2a-4d3f-4a1b-8c2d-1e2f3a4b5c6d",
"name": "MI EMPRESA SA DE CV",
"tax_id": "XEXX010101000",
"credential_status": "pending"
}
Response fields
| Field | Type | Description |
|---|---|---|
id |
string | Entity UUID. Use this in all downstream API calls. |
name |
string | Legal name. |
tax_id |
string | RFC (always uppercase). |
credential_status |
string | CIEC validation state. See CIEC status. |
Update an entity (rotates the CIEC)
PATCH /v1/entities/{id}
Send only the fields to update. Changing ciec_password resets credential_status to pending
and triggers re-validation automatically.
{ "ciec_password": "NewPass1" }
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | no | Updated legal name. |
tax_id |
string | no | Updated RFC. Must be valid format. |
ciec_password |
string | no | New CIEC password, exactly 8 characters. Triggers re-validation. |
List entities
GET /v1/entities
Returns all entities belonging to the authenticated organization. Each item has the same shape as the create response.
Get an entity
GET /v1/entities/{id}
Returns a single entity by UUID. Returns 404 if not found or not in your organization.
Delete an entity
DELETE /v1/entities/{id} — permanently removes the entity and its related data. Returns 204 No Content.
CIEC status (credential_status)
| Value | Meaning |
|---|---|
pending |
Validation is running asynchronously |
valid |
The CIEC was accepted by the SAT — extractions can run |
invalid |
The SAT rejected the CIEC — update the password via PATCH |
error |
The SAT could not be reached after retries — try again later |
CIEC is only for extractions. Invoicing does not use the CIEC. To issue or cancel CFDI you need a CSD (see below).
CSD — certificate management for invoicing
A CSD (Certificado de Sello Digital) is a digital seal certificate issued by the SAT. It consists
of two files — a .cer (public certificate) and a .key (encrypted private key). You upload them
together with the key password. The private key is encrypted at rest and never returned through
the API.
Every entity that issues invoices must have exactly one active CSD at a time. Uploading a new CSD automatically deactivates any existing active CSD for that entity.
Upload a CSD
POST /v1/entities/{entity_id}/credentials
Send the .cer and .key file contents base64-encoded with the key password:
{
"cer": "<base64-encoded .cer bytes>",
"key": "<base64-encoded .key bytes>",
"password": "your_key_password"
}
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
cer |
string | yes | Base64-encoded contents of the .cer certificate file. |
key |
string | yes | Base64-encoded contents of the .key private key file. |
password |
string | yes | Password for the .key file. |
kind |
string | no | Credential kind. Only csd is accepted. Defaults to csd. |
Validation performed before storing:
- The
.cerand.keymust be a matching pair (the private key must belong to the certificate). - The RFC in the certificate must match the entity's
tax_id. - The certificate must be a CSD (not a FIEL/e.firma).
- The certificate must not be expired.
Response — 201 Created
{
"id": "01936a7b-4c2d-7e8f-9a0b-1c2d3e4f5a6b",
"kind": "csd",
"status": "active",
"is_active": true,
"serial_number": "30001000000500003416",
"valid_from": "2023-01-10T06:00:00+00:00",
"valid_to": "2027-01-10T06:00:00+00:00",
"created_at": "2026-07-01T12:00:00+00:00"
}
Response fields
| Field | Type | Description |
|---|---|---|
id |
string | Credential UUID. Use this to activate or delete the credential. |
kind |
string | Always csd for CSD credentials. |
status |
string | Activation status label. |
is_active |
bool | true when this CSD is the active seal for the entity. |
serial_number |
string | Certificate serial number as issued by the SAT. |
valid_from |
string | ISO 8601 timestamp of certificate validity start. |
valid_to |
string | ISO 8601 timestamp of certificate expiry. Renew before this date. |
created_at |
string | ISO 8601 timestamp when the credential record was created. |
Upload errors
Every non-2xx response carries a stable reason:
| HTTP status | reason |
What happened | What to do |
|---|---|---|---|
201 |
— | Credential stored and activated | Use the id to manage the credential |
422 |
invalid_base64 |
cer or key is not valid base64 |
Re-encode from the raw file bytes |
422 |
invalid_credential |
The .cer/.key pair is invalid or the password is wrong |
Verify files and password |
422 |
rfc_mismatch |
The certificate RFC does not match the entity's tax_id |
Use the correct certificate for this entity |
422 |
not_csd |
The certificate is not a CSD (e.g. FIEL/e.firma) | Upload a CSD, not an e.firma |
422 |
expired |
The certificate has expired | Renew the CSD at the SAT |
List credentials
GET /v1/entities/{entity_id}/credentials
Returns all CSD credentials stored for the entity, newest first. Each item has the same shape as the upload response.
[
{
"id": "01936a7b-4c2d-7e8f-9a0b-1c2d3e4f5a6b",
"kind": "csd",
"status": "active",
"is_active": true,
"serial_number": "30001000000500003416",
"valid_from": "2023-01-10T06:00:00+00:00",
"valid_to": "2027-01-10T06:00:00+00:00",
"created_at": "2026-07-01T12:00:00+00:00"
}
]
Activate or deactivate a credential
PATCH /v1/entities/{entity_id}/credentials/{id}
{ "is_active": true }
When activating a credential, all other credentials of the same kind on the entity are
deactivated first so the one-active-per-kind invariant is always maintained.
Returns the updated credential resource (200 OK).
Delete a credential
DELETE /v1/entities/{entity_id}/credentials/{id}
Removes the credential record and attempts to delete the associated stored files. File deletion
failures are silently ignored; the record is always removed. Returns 204 No Content.
Which credential does each feature need?
| Feature | Needs CIEC | Needs CSD |
|---|---|---|
| SAT invoice extractions | yes | no |
| Constancia de Situación Fiscal (CSF) | yes | no |
| Compliance opinion (32-D) | yes | no |
| Certificate lookup | yes | no |
Issue a CFDI 4.0 (POST /v1/issued-invoices) |
no | yes (active) |
Cancel a CFDI (DELETE /v1/issued-invoices/{id}) |
no | yes (active) |
CFDI verification (POST /v1/cfdi/verify) |
no | no |
Keeping credentials current
CIEC: the SAT does not expire CIEC passwords on a fixed schedule, but users may change them
at any time. If extractions start failing with invalid status, update the password via PATCH.
CSD: the SAT issues CSDs with a validity of up to 4 years. Check valid_to and re-upload
before the certificate expires to avoid stamping failures. Upload the new CSD — it will become
active automatically and deactivate the old one.