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

# Resolve Cancellation

> Timbrix cannot query SAT in real time for the receptor's response — call this once you've confirmed the outcome via the SAT portal. Session callers must be an owner/admin of the invoice's organization; API key callers are scoped by the `write:invoices` scope instead.

Manually confirms the outcome of a cancellation that required receptor approval (`requiresApproval: true`, `cancellationStatus: "pendiente"`). Timbrix cannot query the SAT in real time for the receptor's response — call this endpoint once you've verified the actual outcome on the SAT portal.

This is a **flat** route, same pattern as [Cancel Invoice](/api-reference/invoices/cancel) — no `/organizations/{organizationId}/` prefix.

## Authentication

Accepts **either**:

* A Supabase Bearer session (`Authorization: Bearer <token>`) — the authenticated user must be an **owner or admin** of the invoice's organization. Plain members can request a cancellation via [Cancel Invoice](/api-reference/invoices/cancel), but cannot resolve one, mirroring the same restriction in the Timbrix dashboard, since resolving can flip a CFDI's `status` to `cancelado`.
* An API key (`X-API-Key: sk_...`) with the `write:invoices` scope — the key's own organization must match the invoice's organization. API keys are scoped by the `write:invoices` scope rather than per-member roles, so the owner/admin restriction only applies to session-authenticated callers.

## Path Parameters

| Parameter        | Type          | Required | Description                                                                                                                                                                                   |
| ---------------- | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uuid`           | string (UUID) | Yes      | Folio fiscal UUID of the invoice                                                                                                                                                              |
| `cancellationId` | string (UUID) | Yes      | ID of the cancellation request to resolve — the `id` returned by [Cancel Invoice](/api-reference/invoices/cancel) or [List Invoice Cancellations](/api-reference/invoices/list-cancellations) |

## Request Body

| Field     | Type   | Required | Description                                                                     |
| --------- | ------ | -------- | ------------------------------------------------------------------------------- |
| `outcome` | string | Yes      | `aceptada` or `rechazada` — the confirmed result you observed on the SAT portal |

## What happens

* `outcome: "aceptada"` — the invoice's `status` transitions to `cancelado`. The cancellation is now final.
* `outcome: "rechazada"` — the invoice stays `vigente`. A rejected attempt does not block retries — you can request a new cancellation for the same invoice via [Cancel Invoice](/api-reference/invoices/cancel).

## Example Request

```bash cURL theme={null}
curl -X POST https://api.timbrix.mx/invoices/d3bfbc57-44af-4390-a064-f0afab85e5df/cancellations/6a1b2c3d-4e5f-4890-9abc-def012345678/resolve \
  -H "Authorization: Bearer <your_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "outcome": "aceptada"
  }'
```

```typescript TypeScript theme={null}
// Not yet available in @timbrix/sdk — call the REST endpoint directly
// until SDK support for cancellations ships.
const response = await fetch(
  "https://api.timbrix.mx/invoices/d3bfbc57-44af-4390-a064-f0afab85e5df/cancellations/6a1b2c3d-4e5f-4890-9abc-def012345678/resolve",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer <your_token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ outcome: "aceptada" }),
  }
)
const cancellation = await response.json()
console.log(cancellation.cancellationStatus)
```

## Example Response

```json theme={null}
{
  "id": "6a1b2c3d-4e5f-4890-9abc-def012345678",
  "invoiceId": "0f2a1c3e-1a2b-4c3d-9e8f-1234567890ab",
  "motivo": "02",
  "folioSustitucion": null,
  "requiresApproval": true,
  "respondBy": "2026-08-12T15:50:03.412Z",
  "cancellationStatus": "aceptada",
  "requestedBy": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
  "resolvedBy": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
  "resolvedAt": "2026-08-11T10:15:00.000Z",
  "createdAt": "2026-08-09T15:50:03.412Z"
}
```

See [Cancel Invoice](/api-reference/invoices/cancel#example-response) for the full field reference on this `InvoiceCancellationDto` shape.

## Common Errors

### 400 Bad Request

The cancellation was already resolved (`cancellationStatus` is not `pendiente`).

```json theme={null}
{
  "statusCode": 400,
  "message": "Esta solicitud de cancelación ya fue resuelta",
  "error": "BAD_REQUEST"
}
```

### 401 Unauthorized

Missing or invalid Bearer token / API key.

### 403 Forbidden

The authenticated user is not a member of the invoice's organization, is a member but not an owner/admin, or the API key does not have the `write:invoices` scope / belongs to a different organization than the one that owns the invoice.

### 404 Not Found

`uuid` does not match any invoice, or `cancellationId` does not match a cancellation request for that invoice.


## OpenAPI

````yaml POST /invoices/{uuid}/cancellations/{cancellationId}/resolve
openapi: 3.1.0
info:
  title: Timbrix API
  description: >-
    REST API with OAuth2 server for managing organizations, members, and
    webhooks
  version: '1.0'
  contact: {}
servers:
  - url: https://api.timbrix.mx
    description: Production
security: []
tags:
  - name: organizations
    description: Organization management endpoints
  - name: oauth
    description: OAuth2 authentication and authorization
  - name: webhooks
    description: Webhook configuration and delivery
  - name: users
    description: User information endpoints
  - name: api-keys
    description: API Keys management and validation
  - name: invoices
    description: CFDI 4.0 invoice creation, listing, and cancellation
paths:
  /invoices/{uuid}/cancellations/{cancellationId}/resolve:
    post:
      tags:
        - invoices
      summary: Manually confirm the outcome of a pending cancellation
      description: >-
        Timbrix cannot query SAT in real time for the receptor's response — call
        this once you've confirmed the outcome via the SAT portal. Session
        callers must be an owner/admin of the invoice's organization; API key
        callers are scoped by the `write:invoices` scope instead.
      operationId: InvoicesController_resolve
      parameters:
        - name: uuid
          required: true
          in: path
          description: Folio fiscal UUID of the invoice
          schema:
            type: string
        - name: cancellationId
          required: true
          in: path
          description: ID of the cancellation request to resolve
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResolveCancellationDto'
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceCancellationDto'
        '400':
          description: The cancellation was already resolved
        '403':
          description: >-
            Caller does not belong to the invoice's organization, or session
            caller is not an owner/admin
        '404':
          description: uuid or cancellationId not found
      security:
        - apiKey: []
        - bearer: []
components:
  schemas:
    ResolveCancellationDto:
      type: object
      properties:
        outcome:
          type: string
          example: aceptada
          enum:
            - aceptada
            - rechazada
          description: >-
            Resultado confirmado manualmente por el usuario tras verificar el
            estatus real en el portal del SAT — Timbrix no puede consultarlo en
            tiempo real.
      required:
        - outcome
    InvoiceCancellationDto:
      type: object
      properties:
        id:
          type: string
          example: 6a1b2c3d-4e5f-4890-9abc-def012345678
        invoiceId:
          type: string
          description: Timbrix invoice record ID
          example: 0f2a1c3e-1a2b-4c3d-9e8f-1234567890ab
        motivo:
          type: string
          enum:
            - '01'
            - '02'
            - '03'
            - '04'
          example: '02'
        folioSustitucion:
          type: string
          nullable: true
          example: null
        requiresApproval:
          type: boolean
          example: false
        respondBy:
          type: string
          format: date-time
          nullable: true
          example: null
        cancellationStatus:
          type: string
          enum:
            - pendiente
            - aceptada
            - rechazada
          example: aceptada
        requestedBy:
          type: string
          nullable: true
          example: 9f8e7d6c-5b4a-3210-fedc-ba9876543210
        resolvedBy:
          type: string
          nullable: true
          example: null
        resolvedAt:
          type: string
          format: date-time
          nullable: true
          example: null
        createdAt:
          type: string
          format: date-time
          example: '2026-08-09T15:50:03.412Z'
      required:
        - id
        - invoiceId
        - motivo
        - requiresApproval
        - cancellationStatus
        - createdAt
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: 'API Key for authentication (format: sk_...)'
    bearer:
      scheme: bearer
      bearerFormat: JWT
      type: http

````