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

# API fundamentals

> Integration guide for API fundamentals

Start with the [quickstart](/quickstart) to create a test customer. This page explains
credentials, environments, response formats and limits. Before issuing fiscal
documents, choose the [issuing country](/concepts/shared-fields): Mexican CFDI rules
do not apply to every issuing business.

## Getting Started

### 1. Authentication

Get your API token at [app.gigstack.pro/settings?tab=api](https://app.gigstack.pro/settings?tab=api)

### 2. Base URL

```
Public API (live and test keys): https://api.gigstack.io/v2
Internal staging (staging keys only): https://gigstack-staging-9z9nnaat.uc.gateway.dev/v2
```

Test mode is selected by the key; it is not a separate public hostname. Internal
staging is a separate deployment and data store. Match the key to its environment;
a request-body `livemode` value cannot change an API key's mode. See [authentication](/authentication).

### 3. Authentication Header

Nearly every API request requires the Authorization header:

```
Authorization: Bearer YOUR_JWT_TOKEN
```

**Two exceptions:**

| Endpoint | How it authenticates |
| - | - |
| `GET /v2/{module}/health` | **Public.** No credentials at all. Returns `{ "status": "ok", "module": "…" }`. Available on `auth`, `catalogs`, `clients`, `invoices`, `payments`, `receipts`, `services`, `teams`, `users`, `webhooks` — the `documents`, `retentions` and `sat-lists` modules do not expose one. The bypass is narrow on purpose: **`GET` only**, and only at exactly `/v2/{module}/health`. `DELETE /v2/clients/health` is a normal authenticated request that treats `health` as an id. |
| `POST /v2/auth/signup` | **Not** a Bearer token. Uses a partner secret sent in the `X-Internal-API-Key` header (the alias `X-Signup-Api-Key` is also accepted). This creates the account that Bearer tokens are later issued for, so there is no token to send yet. |

Contact gigstack to be issued a signup secret — it is not something you can generate from the dashboard, and it must never be shipped in client-side code.

#### Authentication errors

Credential problems are answered by the authentication layer, before the endpoint runs. These bodies are **not** the standardized envelope — there is no `success` and no `timestamp`:

```json theme={null}
{ "message": "Unauthorized" }
```

| Status | `message` | Cause |
| - | - | - |
| `401` | `Unauthorized` | Missing header, missing `Bearer ` prefix, or a token that cannot be parsed |
| `401` | `Unauthorized, missing team in token` | The key carries no team |
| `401` | `Invalid access token`, `Access token has expired. Please refresh your token.`, `Access token has been revoked` | OAuth access tokens only. The body also has `error` (`invalid_token`, `token_expired`, `token_revoked`) and `error_description` |
| `403` | `API Key inválida.` (plus `details: "Invalid API Key"`) | The API key was revoked or disabled |
| `403` | Spanish text containing an HTML link to `app.gigstack.pro/memberships` | Your plan does not include API access |

The plan-gate `403` message is Spanish and contains HTML (`La API se encuentra disponible para un plan más grande, …`). Branch on the status code; do not show the text to end users or match on it. gigstack Connect adds its own `401` / `403` / `404` cases, listed [below](#gigstack-connect).

#### Client identification (optional)

Documents the API creates for a team are stored with `from: 'api'`. Send `X-Gigstack-Client: mcp` to store them with `from: 'mcp'` instead — this is what the gigstack MCP server does. `mcp` is the only recognised value; anything else is treated as `api`. The header changes attribution only: `mcp` documents behave exactly like `api` documents.

### 4. Creating an account programmatically

Partners with a signup secret can provision a whole gigstack account — auth user, billing account, team, plan subscription and an API key pair — in one call.

```http theme={null}
POST /v2/auth/signup
X-Internal-API-Key: YOUR_SIGNUP_SECRET
Idempotency-Key: acct-acme-2026-02-14
Content-Type: application/json
```

**The `Idempotency-Key` header is required.** It must be **8 to 128 characters** drawn from `A-Z a-z 0-9 . _ : -`. It is *not* required to be a UUID — `acct-acme-2026-02-14` is perfectly valid. A key that is missing or does not match that pattern returns `400`.

| Body field | Required | Behavior |
| - | - | - |
| `email` | yes | Must be unique across Firebase Auth and the `users` collection, otherwise `409`. |
| `name` | yes | Used as the legal name on the billing account and team. |
| `plan_id` | yes | Must exist; unknown values return `400 Unknown plan_id`. |
| `stripe_payment_method` | yes for **paid** plans | Omit only when `plan_id` is `free`, `free monthly` or `free-plus`. |
| `billing_cycle` | no (default `monthly`) | `monthly` or `annual`. |
| `rfc` | no | **Persisted as `null` when omitted.** It is *not* defaulted to a generic SAT RFC such as `XAXX010101000`. |
| `country` | no (default `MEX`) | |
| `livemode` | no (default `true`) | |
| `partner_ref` | no | Referral attribution. |
| `metadata` | no | Free-form object. |

Because an omitted `rfc` stays `null`, the new team cannot issue CFDIs until an RFC and a SAT connection are added. Everything else — clients, payments, services, receipts, webhooks — works immediately. The response's `next_steps` block spells this out.

**Replays.** Re-sending the same `Idempotency-Key` after success returns `201` with the original response body (including the same API keys). While the first attempt is still running you get `409 idempotency_in_progress` — retry shortly. If the first attempt failed you get `409 idempotency_failed`; use a **new** key to retry.

> Store the API keys from the successful response securely. A successful idempotent replay
> can return those same credentials; treat replay responses as secrets too.

If you are creating a team that will later connect to the SAT — especially a connected team under gigstack Connect — read [the RFC guidance](/guides/gigstack-connect#choose-the-right-rfc-before-you-create-the-team) before you pick the `rfc`. Getting it wrong is only discovered much later, at FIEL upload.

## Key Features

* **Mexican Tax Compliance** - Full SAT, RFC, and CFDI 4.0 support
* **Invoice Lifecycle** - Create, stamp, and cancel invoices
* **Payment Processing** - Multiple processors with refund support
* **Client Management** - Fiscal validation and EFOS checking
* **Service Catalog** - Products with tax configurations
* **gigstack Connect** - Multi-team resource management

## gigstack Connect

A **master team** can act on other teams that share its billing account by adding the `team` query parameter to a request:

```bash theme={null}
# Access team_xyz789's clients
GET /clients?team=team_xyz789

# Create invoice for team_abc123
POST /invoices/income?team=team_abc123
```

**Requirements:**

* Your API key's team must be a master team (gigstack Connect enabled)
* The target team must exist and share the same billing account
* Your plan must include the `multipleIssuerAccounts` feature
* Use an **API key**: OAuth access tokens are bound to one team, and any other `team` value is rejected with `403 Team mismatch with OAuth token`

**Errors** (raw `{ "message": … }` bodies from the authentication layer):

| Status | `message` | Cause |
| - | - | - |
| `401` | `Unauthorized, not a master team` | Your key's team does not have gigstack Connect |
| `404` | `Team not found` | The target team does not exist |
| `401` | `Unauthorized, no matched teams` | The target team could not be resolved within your billing account |
| `403` | `Tu plan no incluye múltiples cuentas emisoras. …` | Your plan lacks `multipleIssuerAccounts` |
| `403` | `Team mismatch with OAuth token` | An OAuth access token was sent with another team's id |

See the [gigstack Connect guide](/guides/gigstack-connect) for details.

## Response Format

Most endpoints return the **standardized envelope**. `timestamp` is epoch milliseconds; `message` is present only when the endpoint sets one.

### Success Response

```json theme={null}
{
    "success": true,
    "data": {},
    "message": "Description of action",
    "timestamp": 1767225600000
}
```

### Error Response

```json theme={null}
{
    "success": false,
    "error": {
        "code": "validation_failed",
        "message": "Request validation failed",
        "details": ["currency: Field is required"]
    },
    "timestamp": 1767225600000
}
```

`error.code` is a stable, machine-readable value (`validation_failed`, `invalid_request_body`, `unauthorized`, `forbidden`, `resource_not_found`, `resource_conflict`, `internal_server_error`, …). Branch on it and on the HTTP status, not on `message`.

### List Response

List endpoints put `data` and the pagination keys at the **top level**:

```json theme={null}
{
    "success": true,
    "message": "Services retrieved successfully",
    "data": [],
    "next": "cursor_for_next_page",
    "has_more": true,
    "total_results": 150,
    "timestamp": 1767225600000
}
```

Pass `next` back as the `next` query parameter to get the following page. `limit` defaults to **10** (max 100) unless an endpoint says otherwise. Search endpoints (`/search`) report `found`, `page` and `per_page` instead of a cursor.

### Exceptions

Not every endpoint uses the envelope: authentication failures (above), invoice creation and stamping (`{ "message", "error" }`), the SAT and bulk-download endpoints (`{ "success", "message", "data" }` with no `timestamp`) and the health probes return their own shapes. Each operation in the [API reference](https://docs.gigstack.io) documents the exact body it returns.

## Test Mode

Every API key is either **live** or **test**; the mode is fixed and both use the same host (`https://api.gigstack.io/v2`). Create your test key at [app.gigstack.pro/settings?tab=api](https://app.gigstack.pro/settings?tab=api).

* **Separate data.** Resources are stored with the mode of the key that created them, and list and search endpoints only return resources of your key's mode.
* **Crossing modes is refused.** For example, cancelling a live invoice with a test key answers `403` (`Livemode mismatch`).
* **Separate folios.** Live and test keep independent folio counters for each series.
* **Live-only operations.** `POST /invoices/eom/run` and `POST /teams` reject test keys.
* **Verification is scoped.** The Mexican staging recipes created test-mode documents and checked their returned mode and workflow results. This does not establish behavior for every provider or a production issuer. Do not provide test-mode output to customers as real fiscal documents. See [verification coverage](/verification).
* **Draft stamping needs an extra check.** It uses the stored draft mode. Verify that the draft itself was created in test mode; the calling key does not convert an existing live draft.

## Rate Limits

These limits answer `429`. No `Retry-After` header is sent.

| Limit | Endpoints |
| - | - |
| Team credit limit (`credit_limit` on the team) | `POST /invoices/income`, `POST /invoices/draft/{id}/stamp`, `POST /receipts` |
| 10 manual SAT download requests per team per day (resets at midnight, Mexico City) | `POST /invoices/download/request` |

A credit-limit error requires available credits or a changed limit; retrying faster
does not add credits. A daily SAT quota requires waiting for its reset. Other limits
may apply at the infrastructure level.

For `503`, inspect the operation's error code: an unavailable provider and an unknown
stamping outcome are different. Retry reads with bounded backoff. For writes,
reconcile the result and use the endpoint's documented idempotency behavior before
retrying. A timeout or `500` can occur after an external action has completed. See
[responses and retries](/responses) and [invoice errors](/guides/invoices#error-handling).

## API Resources

| Resource | Description | Guide |
| - | - | - |
| **Clients** | Manage clients with fiscal information | [clients.md](/guides/clients) |
| Services | Product/service catalog with SAT codes | [services.md](/guides/services) |
| Invoices | CFDI 4.0 compliant invoicing | [invoices.md](/guides/invoices) |
| Retentions | Withholding tax certificates (constancias de retenciones) | [retentions.md](/guides/retentions) |
| Platform Payouts | Marketplace provider payouts invoiced from two files | [platform-payouts.md](/guides/platform-payouts) |
| Descarga Masiva | Bulk-download your full SAT invoice history via FIEL | [descarga-masiva.md](/guides/descarga-masiva) |
| Payments | Payment processing and tracking | [payments.md](/guides/payments) |
| Receipts | Self-service invoice generation | [receipts.md](/guides/receipts) |
| Documents | Supporting documents for SAT compliance | [documents.md](/guides/documents) |
| SAT Lists | Screen RFCs against the SAT's 69 / 69-B / 69-B Bis lists | [sat-lists.md](/guides/sat-lists) |
| Teams | Team management and settings | [teams.md](/guides/teams) |
| Users | User account management | [users.md](/guides/users) |
| Webhooks | Real-time event notifications | [webhooks.md](/guides/webhooks) |
| gigstack Connect | Multi-team resource access via `?team=` | [gigstack-connect.md](/guides/gigstack-connect) |
| SAT Catalogs | Coded values CFDI requires | [catalogs/](/guides/catalogs/payment_forms) |

## Quick Examples

### Create a Client

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/clients \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Juan Pérez García",
    "email": "juan.perez@ejemplo.com",
    "tax_id": "PEGJ800101ABC",
    "tax_system": "601"
  }'
```

### Create an Invoice

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/invoices/income \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "automation_type": "payment",
    "client": {"id": "client_1234567890"},
    "currency": "MXN",
    "items": [{
      "description": "Consulting services",
      "quantity": 1,
      "unit_price": 1000.00,
      "product_key": "80141503",
      "unit_key": "E48",
      "taxes": [{
        "type": "IVA",
        "rate": 0.16,
        "withholding": false
      }]
    }],
    "use": "P01",
    "payment_form": "03",
    "payment_method": "PUE"
  }'
```

> **Note:** `exchange_rate` is optional. If not provided, the latest rate from our rates collection will be used automatically.

### Register a Payment

```bash theme={null}
curl -X POST https://api.gigstack.io/v2/payments/register \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client": {"id": "client_1234567890"},
    "automation_type": "pue_invoice",
    "currency": "MXN",
    "payment_form": "03",
    "items": [{
      "id": "service_1234567890",
      "quantity": 1
    }],
    "idempotency_key": "payment-12345"
  }'
```

> **Note:**
>
> * `exchange_rate` is optional. If not provided, the rate from the payment date will be fetched automatically from our rates collection.
> * `date` is optional. Use it to backdate a payment (must be in the past). Defaults to current time.

## Development Tools

* **Swagger UI**: Interactive API documentation
* **Postman Collection**: Pre-configured requests
* **Code Examples**: Available in multiple languages
* **Webhooks**: Real-time event notifications

## Support

* **Documentation**: [docs.gigstack.io](https://docs.gigstack.io)
* **Support Email**: [support@gigstack.io](mailto:support@gigstack.io)
* **API Status**: [status.gigstack.io](https://status.gigstack.io)

***

Ready to start building? Choose a resource from the guides above to begin your integration.


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