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

# SAT credentials — access with the taxpayer's RFC and CIEC

> Save a taxpayer's SAT password (the CIEC, or *contraseña*) on a fiscal profile, and we can fetch SAT documents for that RFC without a FIEL.

Save a taxpayer's SAT password (the **CIEC**, or *contraseña*) on a fiscal profile, and we can fetch
SAT documents for that RFC without a FIEL. The credential belongs to one fiscal profile, and a
profile holds one credential at a time.

We never store the password. It is used once to save the credential with our SAT document service,
which keeps it encrypted and gives us an opaque reference. It does not appear in our database,
logs, events, job payloads or idempotency records.

Once the credential is `verified`, [massive download](https://docs.newinvoice.dev/guides/massive-download.md) uses it automatically.

> **Test mode is simulated.** With a `sk_test_` key, or on the sandbox issuer, nothing leaves this
> API: the password is not sent anywhere and the credential is `verified` immediately. Use it to
> build the whole flow, webhooks included.

## 1. Save the credential

```bash theme={null}
curl -s -X POST https://api.newinvoice.dev/v1/fiscal_profiles/$FP_ID/sat_credential \
  -H "authorization: Bearer $API_KEY" -H 'content-type: application/json' \
  -d '{ "password": "<the taxpayer SAT password>" }' | jq
```

```json theme={null}
{
  "object": "sat_credential",
  "fiscal_profile_id": "fp_01H...",
  "rfc": "AAA010101AAA",
  "status": "pending",
  "expires_at": "2027-02-06T17:55:00.000Z",
  "remediation": null,
  "livemode": true
}
```

**Using a FIEL instead.** Send the taxpayer's e.firma in place of the password. It works for the
same documents, and SAT's e.firma login needs no CAPTCHA. Like the password, it is used once to
save the credential and we do not store it. The FIEL must be unexpired and issued to the profile's
RFC.

```bash theme={null}
curl -s -X POST https://api.newinvoice.dev/v1/fiscal_profiles/$FP_ID/sat_credential \
  -H "authorization: Bearer $API_KEY" -H 'content-type: application/json' \
  -d "{ \"fiel\": { \"cer_base64\": \"$(base64 < fiel.cer | tr -d '\n')\",
                    \"key_base64\": \"$(base64 < fiel.key | tr -d '\n')\",
                    \"password\": \"<the private-key password>\" } }" | jq
```

This is separate from a FIEL added with `PATCH /v1/fiscal_profiles/:id`, which is stored on the
profile for signing the manifiesto and for FIEL downloads.

Treat a `201` as "saved, not yet accepted". Saving again replaces the previous credential and
revokes it. If you send an `Idempotency-Key`, the password is left out of its comparison, so use a
new key when correcting a password.

## 2. Wait for verification

The login check against SAT runs in the background. Subscribe to these webhooks, or poll
`GET /v1/fiscal_profiles/:id/sat_credential`.

| `status` | Event | Meaning |
| - | - | - |
| `pending` | | The check is still running. |
| `verified` | `fiscal_profile.sat_credential_verified` | SAT accepted the password when checked. |
| `rejected` | `fiscal_profile.sat_credential_rejected` | SAT explicitly refused it. |
| `inconclusive` | `fiscal_profile.sat_credential_inconclusive` | The check could not tell, for example during an outage or a CAPTCHA problem. |
| `expired` | `fiscal_profile.sat_credential_expired` | The saved credential has passed `expires_at`. |

Only enable SAT features for a `verified` credential. It is a point-in-time check of the login, not
a guarantee that every SAT service will accept the password later.

On `rejected`, ask the taxpayer to confirm their RFC and password before saving again: do not retry
the same password automatically. On `inconclusive`, save it again later. The `remediation` field
says the same thing for an agent.

With a `verified` credential you can [request the constancia](https://docs.newinvoice.dev/guides/constancia.md).

## 3. Renew before it expires

A credential lasts **at most 90 days**; `expires_at` is authoritative. There is no renewal call:
ask the taxpayer for their password and save it again.

| Event | When |
| - | - |
| `fiscal_profile.sat_credential_expiring` | Once, 14 days before `expires_at`, with `days_remaining`. |
| `fiscal_profile.sat_credential_expired` | When `expires_at` passes. |

## 4. Remove it

```bash theme={null}
curl -s -X DELETE https://api.newinvoice.dev/v1/fiscal_profiles/$FP_ID/sat_credential \
  -H "authorization: Bearer $API_KEY"
```

It is removed here at once, and revocation with our SAT document service is retried in the
background if it cannot complete immediately. Deleting a fiscal profile revokes its credential too.

## Errors

| Code | What to do |
| - | - |
| `sat_service.not_configured` (503) | Live SAT access is not enabled on this deployment. |
| `sat_service.invalid_request` (422) | Check the RFC and the password length (1 to 256 characters). |
| `sat_service.capacity_reached` (429) | Retry later with backoff. |
| `sat_service.unavailable` (503) | Retry later with backoff. |
| `sat_credential.concurrent_update` (409) | Another request saved a credential at the same moment. Read it, then retry if needed. |

See the [error reference](https://docs.newinvoice.dev/concepts/errors.md) for the full catalog.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.