curl --request POST \
--url https://api.gigstack.io/v2/invoices/income/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"invoices": [
{
"idempotency_key": "order-2026-09-000123",
"automation_type": "none",
"currency": "MXN",
"use": "G03",
"payment_form": "04",
"payment_method": "PUE",
"client": {
"id": "client_1234567890"
},
"items": [
{
"description": "Professional consulting services",
"product_key": "80141503",
"unit_key": "E48",
"unit_price": 1000,
"quantity": 1,
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"factor": "Tasa",
"withholding": false
}
]
}
],
"send_email": true
},
{
"idempotency_key": "order-2026-09-000124",
"automation_type": "none",
"currency": "MXN",
"use": "G03",
"payment_form": "03",
"payment_method": "PUE",
"client": {
"id": "client_0987654321"
},
"items": [
{
"description": "Annual support plan",
"product_key": "81111811",
"unit_key": "E48",
"unit_price": 2500,
"quantity": 1,
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"factor": "Tasa",
"withholding": false
}
]
}
]
}
]
}
'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
invoices: [
{
idempotency_key: 'order-2026-09-000123',
automation_type: 'none',
currency: 'MXN',
use: 'G03',
payment_form: '04',
payment_method: 'PUE',
client: {id: 'client_1234567890'},
items: [
{
description: 'Professional consulting services',
product_key: '80141503',
unit_key: 'E48',
unit_price: 1000,
quantity: 1,
taxes: [{type: 'IVA', rate: 0.16, factor: 'Tasa', withholding: false}]
}
],
send_email: true
},
{
idempotency_key: 'order-2026-09-000124',
automation_type: 'none',
currency: 'MXN',
use: 'G03',
payment_form: '03',
payment_method: 'PUE',
client: {id: 'client_0987654321'},
items: [
{
description: 'Annual support plan',
product_key: '81111811',
unit_key: 'E48',
unit_price: 2500,
quantity: 1,
taxes: [{type: 'IVA', rate: 0.16, factor: 'Tasa', withholding: false}]
}
]
}
]
})
};
fetch('https://api.gigstack.io/v2/invoices/income/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.gigstack.io/v2/invoices/income/batch"
payload = { "invoices": [
{
"idempotency_key": "order-2026-09-000123",
"automation_type": "none",
"currency": "MXN",
"use": "G03",
"payment_form": "04",
"payment_method": "PUE",
"client": { "id": "client_1234567890" },
"items": [
{
"description": "Professional consulting services",
"product_key": "80141503",
"unit_key": "E48",
"unit_price": 1000,
"quantity": 1,
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"factor": "Tasa",
"withholding": False
}
]
}
],
"send_email": True
},
{
"idempotency_key": "order-2026-09-000124",
"automation_type": "none",
"currency": "MXN",
"use": "G03",
"payment_form": "03",
"payment_method": "PUE",
"client": { "id": "client_0987654321" },
"items": [
{
"description": "Annual support plan",
"product_key": "81111811",
"unit_key": "E48",
"unit_price": 2500,
"quantity": 1,
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"factor": "Tasa",
"withholding": False
}
]
}
]
}
] }
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"success": true,
"data": {
"id": "ibatch_5d41402abc4b2a76b9719d911017c592",
"object": "invoice_batch",
"type": "income",
"livemode": true,
"status": "processing",
"result": null,
"total": 250,
"accepted": 248,
"rejected": [
{
"index": 17,
"idempotency_key": "order-2026-09-000140",
"error": {
"code": "invalid_body",
"message": "client_id: Unexpected field"
}
},
{
"index": 42,
"idempotency_key": "order-2026-09-000123",
"error": {
"code": "duplicate_idempotency_key",
"message": "idempotency_key is already used by item 0"
}
}
],
"counts": {
"queued": 131,
"stamped": 115,
"failed": 1,
"duplicate": 1,
"needs_review": 0
},
"created_at": 1790780400000,
"completed_at": null
},
"timestamp": 1790781000000
}Create a batch of income invoices
Accepts up to 1,000 income invoices in one request and stamps them in the background. Each item is
exactly the body of POST /invoices/income, and must carry its own idempotency_key, unique within the
batch. To send more than 1,000 invoices, send more batches, each with its own Idempotency-Key.
What happens in the request. Every item is validated against the POST /invoices/income body schema,
with no I/O. An invalid item is listed in rejected with its reason and the rest go ahead; only an empty
or missing invoices array, or more than 1,000 items, refuses the whole request (400). The answer is
202 with the batch in processing; the first items may already have started.
What happens after. Each accepted item is stamped by the same code as POST /invoices/income, with
the credential that created the batch, so it fails for the same reasons (a client that doesn’t exist, a
SAT rejection, the credit limit) and consumes one credit when stamped. A temporary failure (PAC
unavailable, its answer lost) is retried automatically, up to 6 attempts per item. Items run about 10 at
a time per team. Follow the batch with GET /invoices/income/batch/{id}, or subscribe a webhook to
invoice_batch.completed (body InvoiceBatchCompletedWebhookEvent, signed, sent once and never
retried; see the webhookEvent callback of POST /webhooks), then read the per-item results with
GET /invoices/income/batch/{id}/items.
Two levels of idempotency.
- The
Idempotency-Keyheader names the batch. The batch id is derived from your team, the credential’s mode and the header, so the same key with the same body returns the same batch (200), and nothing is created again. The same key with a different body is409idempotency_key_reused. Bodies are compared as sent, including key order, so resend the exact same JSON. - Each item’s
idempotency_keynames the invoice. It is the same keyPOST /invoices/incomeuses: an invoice already issued under it, by an earlier batch or a single call, is not issued again, and the item endsduplicate. So a new batch that repeats items of a previous one is safe.
gigstack Connect: create the batch for a connected team with the team parameter, and read it with the
same team.
Mode. livemode comes only from the credential: a test key creates a test batch.
Not supported here: file uploads (CSV/XLSX), egress invoices and payment complements. If most of your sales are to the general public, the monthly global invoice (factura global) that gigstack already produces may be all you need.
curl --request POST \
--url https://api.gigstack.io/v2/invoices/income/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"invoices": [
{
"idempotency_key": "order-2026-09-000123",
"automation_type": "none",
"currency": "MXN",
"use": "G03",
"payment_form": "04",
"payment_method": "PUE",
"client": {
"id": "client_1234567890"
},
"items": [
{
"description": "Professional consulting services",
"product_key": "80141503",
"unit_key": "E48",
"unit_price": 1000,
"quantity": 1,
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"factor": "Tasa",
"withholding": false
}
]
}
],
"send_email": true
},
{
"idempotency_key": "order-2026-09-000124",
"automation_type": "none",
"currency": "MXN",
"use": "G03",
"payment_form": "03",
"payment_method": "PUE",
"client": {
"id": "client_0987654321"
},
"items": [
{
"description": "Annual support plan",
"product_key": "81111811",
"unit_key": "E48",
"unit_price": 2500,
"quantity": 1,
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"factor": "Tasa",
"withholding": false
}
]
}
]
}
]
}
'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
invoices: [
{
idempotency_key: 'order-2026-09-000123',
automation_type: 'none',
currency: 'MXN',
use: 'G03',
payment_form: '04',
payment_method: 'PUE',
client: {id: 'client_1234567890'},
items: [
{
description: 'Professional consulting services',
product_key: '80141503',
unit_key: 'E48',
unit_price: 1000,
quantity: 1,
taxes: [{type: 'IVA', rate: 0.16, factor: 'Tasa', withholding: false}]
}
],
send_email: true
},
{
idempotency_key: 'order-2026-09-000124',
automation_type: 'none',
currency: 'MXN',
use: 'G03',
payment_form: '03',
payment_method: 'PUE',
client: {id: 'client_0987654321'},
items: [
{
description: 'Annual support plan',
product_key: '81111811',
unit_key: 'E48',
unit_price: 2500,
quantity: 1,
taxes: [{type: 'IVA', rate: 0.16, factor: 'Tasa', withholding: false}]
}
]
}
]
})
};
fetch('https://api.gigstack.io/v2/invoices/income/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.gigstack.io/v2/invoices/income/batch"
payload = { "invoices": [
{
"idempotency_key": "order-2026-09-000123",
"automation_type": "none",
"currency": "MXN",
"use": "G03",
"payment_form": "04",
"payment_method": "PUE",
"client": { "id": "client_1234567890" },
"items": [
{
"description": "Professional consulting services",
"product_key": "80141503",
"unit_key": "E48",
"unit_price": 1000,
"quantity": 1,
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"factor": "Tasa",
"withholding": False
}
]
}
],
"send_email": True
},
{
"idempotency_key": "order-2026-09-000124",
"automation_type": "none",
"currency": "MXN",
"use": "G03",
"payment_form": "03",
"payment_method": "PUE",
"client": { "id": "client_0987654321" },
"items": [
{
"description": "Annual support plan",
"product_key": "81111811",
"unit_key": "E48",
"unit_price": 2500,
"quantity": 1,
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"factor": "Tasa",
"withholding": False
}
]
}
]
}
] }
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"success": true,
"data": {
"id": "ibatch_5d41402abc4b2a76b9719d911017c592",
"object": "invoice_batch",
"type": "income",
"livemode": true,
"status": "processing",
"result": null,
"total": 250,
"accepted": 248,
"rejected": [
{
"index": 17,
"idempotency_key": "order-2026-09-000140",
"error": {
"code": "invalid_body",
"message": "client_id: Unexpected field"
}
},
{
"index": 42,
"idempotency_key": "order-2026-09-000123",
"error": {
"code": "duplicate_idempotency_key",
"message": "idempotency_key is already used by item 0"
}
}
],
"counts": {
"queued": 131,
"stamped": 115,
"failed": 1,
"duplicate": 1,
"needs_review": 0
},
"created_at": 1790780400000,
"completed_at": null
},
"timestamp": 1790781000000
}Authorizations
Authentication Method: HTTP Bearer token.
The runtime requires the literal Bearer prefix — a bare token in the
Authorization header is rejected with 401 unauthorized.
Header Format: Authorization: Bearer YOUR_API_KEY
Your API key is a JWT. Live keys operate on live data (livemode: true);
test keys operate on isolated test data (livemode: false).
Get your key at: app.gigstack.pro/settings?tab=api
Errors: credential failures are answered by the authentication layer with a raw
{ "message": … } body, not the standardized envelope — 401 for a missing, malformed or
expired token, 403 for a revoked key or a plan without API access. See the Unauthorized
and AuthForbidden responses.
Headers
Your identifier for this batch, 8-128 characters of A-Z a-z 0-9 . _ : -. Reusing it with the same
body returns the batch it first created; reusing it with a different body is 409 idempotency_key_reused.
8 - 128^[A-Za-z0-9._:-]{8,128}$Query Parameters
gigstack Connect: Target team ID for multi-team access.
Requires gigstack Connect enabled on your team and shared billing account.
Also requires the multipleIssuerAccounts feature on your plan. Requests targeting a
team other than the one your API key belongs to return 403 without it.
Only API keys can use it: an OAuth access token sent with another team's id is rejected with
403 Team mismatch with OAuth token.
Optional — omit it entirely unless you are acting on another team. It deliberately
carries no example value so generated snippets do not emit ?team=undefined; when the
parameter is absent, the team is derived from your API key.
Example: ?team=team_xyz789
Body
Up to 1,000 income invoices. Each item is exactly the body of POST /invoices/income, and must carry
its own idempotency_key, unique within the batch.
Items are validated one by one: an invalid item is listed in the batch's rejected and the others go
ahead. Only a body without a non-empty invoices array (invalid_body) or with more than 1,000 items
(too_many_items) refuses the whole request.
livemode, team and owner in an item are ignored (they come from the credential), and so is
return_files: a batch does not return files. Keep the whole JSON body under 10 MB.
The invoices, in the order you want them reported. An item's index is its position here (from 0).
1 - 1000 elementsShow child attributes
Show child attributes
Response
Retry of an earlier request with the same Idempotency-Key and the same body: the batch it created,
as it is now. Nothing is created again. If the first request died while writing the batch, this
request finishes creating it.
Standardized success envelope emitted by sendSuccessResponse.
true true
An income invoice batch: how many invoices it received, which were rejected up front, and the progress of the rest. Timestamps are epoch milliseconds.
Show child attributes
Show child attributes
Server time in epoch milliseconds (Luxon.now().toMillis()).
1767225600000
Human-readable summary. Present only when the handler supplies one.
"Operation completed successfully"