FIZ Invoicing은(는) 무엇을 하나요?
FIZ 공개 API(https://api.fiz.co)를 통해 인보이스를 발행합니다.
이 스킬은 전체 라이프사이클(고객 조회/생성, 품목 조회/생성, 초안 인보이스 작성, 발행(법적 구속력이 있는 단계), 그리고 선택적 PDF 다운로드)을 안내합니다.
설정
모든 요청은 클라이언트의 API 키를 x-api-key 헤더에 포함해야 합니다. **https://app.fiz.co/settings/integrations**에서 키를 발급받으세요.
API 키를 환경 변수에 저장하여 명령어에 하드코딩되지 않도록 하세요:
export FIZ_API_KEY="fiz_api_..." # app.fiz.co에서 발급받은 사용자 키
export FIZ_API_URL="https://api.fiz.co" # 선택 사항; 기본값입니다.
아래 모든 예제는 $FIZ_API_KEY와 $FIZ_API_URL을 사용합니다. FIZ_API_URL이 설정되지 않은 경우 https://api.fiz.co를 사용하세요. FIZ_API_KEY가 설정되지 않은 경우, 사용자에게 환경 변수 설정을 요청하고 중단하십시오(쉘에서 export FIZ_API_KEY=… 또는 비밀 관리자 사용) — 채팅에 키를 붙여넣도록 요청하지 말고, 키 값을 출력하거나 에코하지 마십시오. API 키는 자격 증명이므로 대화 기록에 남지 않도록 해야 합니다.
재사용 가능한 curl 헬퍼가 scripts/fiz.sh에 제공됩니다. 명령어는 세션의 작업 디렉토리(프로젝트 루트)에서 실행되며, 스킬 디렉토리가 아닙니다. 따라서 ${CLAUDE_SKILL_DIR}의 절대 경로를 통해 헬퍼를 소스하세요(Claude Code는 이 변수를 스킬 디렉토리로 설정합니다):
source "${CLAUDE_SKILL_DIR}/scripts/fiz.sh" # 모든 작업 디렉토리에서 해석됨
fiz GET /invoices
CLAUDE_SKILL_DIR을 제공하지 않는 런타임에서는 해당 런타임에 맞는 스킬 디렉토리 경로로 대체하세요(상대 경로 scripts/fiz.sh는 프로젝트 루트에서 해석되지 않습니다).
헬퍼는 HTTP 상태 코드를 출력하고 4xx/5xx에서 0이 아닌 값을 반환하므로, 오류 응답이 성공으로 오인되지 않습니다 — 아래 "오류 처리"를 참조하세요. 일반 curl 예제도 인라인으로 표시됩니다. 원시 curl을 사용하는 경우 명령어의 종료 코드(0)뿐만 아니라 항상 HTTP 상태를 확인하세요.
개념 이해
- 인보이스는 고객(ID 기준)과 하나 이상의 품목(ID 기준)을 참조합니다. 따라서 인보이스를 작성하기 전에 고객과 품목이 존재해야 합니다.
POST /invoices는 초안을 생성합니다. 초안은 아직 법적 문서가 아닙니다 — 세무 당국에 전송되지 않으며 자유롭게 편집하거나 삭제할 수 있습니다.POST /invoices/:id/issue는 인보이스를 발행합니다 — 공식 번호와 ATCUD를 할당하고, 포르투갈 세무 당국(AT)과 동기화하며, 최종 상태로 만듭니다. 발행은 되돌릴 수 없습니다. 발행 전에 사용자에게 확인을 받으십시오. 발행된 인보이스는 삭제할 수 없으며, 되돌리는 유일한 방법은 신용 메모(credit note)입니다.- "생성 후 발행" 규칙의 유일한 예외:
INVOICE_RECEIPT또는SIMPLIFIED_INVOICE유형에 대해 생성 시payment객체를 전달하면 문서에 결제가 기록됩니다 — 그러나 최종 확정을 위해서는 여전히 발행해야 합니다.
쓰기 전 확인
이 엔드포인트들은 사용자 계정의 상태를 변경합니다. 두 단계의 주의가 필요합니다:
- 계획을 세우고, 첫 번째 쓰기 전에 모든 쓰기 작업을 미리 보여주십시오. 요청에 필요한 것이 무엇인지 파악한 후, 이 작업에 대해 수행하려는 모든 쓰기 작업(각 엔드포인트와 해당 JSON 페이로드(생성할 고객, 각 품목, 초안 인보이스))을 나열하고, 해당 배치를 한 번에 사용자에게 미리 보여주십시오. 사용자가 계획을 승인하면 쓰기 작업을 진행하십시오. 실행 중에 계획이 변경되면(예: 품목 조회 실패로 새 품목을 생성해야 하는 경우), 전송하기 전에 새로운 쓰기 작업을 미리 보여주십시오. 고객 데이터, 세금 필드 또는 금액을 임의로 만들어 내지 마십시오 — 사용자가 제공한 정보만 사용하십시오.
POST /invoices/:id/issue전 — 이는 되돌릴 수 없으며 세무 당국에 보고됩니다. 항상 명시적이고 별도의 확인(위의 계획 승인과는 별도로)을 받고, 초안의 고객, 라인 품목, VAT 및 총액을 표시하십시오. 임의로 발행하지 마십시오.
호출 정책 (의도적): 이 스킬은 모델 자동 호출을 활성화된 상태로 유지합니다 — description이 검색 표면이고, 실제 안전 장치는 위의 모든 쓰기 미리보기 + 별도 발행 확인이며, 검색을 제한하지 않습니다. Codex 매니페스트(agents/openai.yaml)는 일치하도록 설정되어 있습니다(allow_implicit_invocation: true). 수동 전용 사용을 원하는 운영자는 frontmatter에서 disable-model-invocation: true를 설정할 수 있습니다(/fiz-invoicing에서만 로드됩니다).
이것은 포르투갈 세금 인보이스입니다 — 정확성이 중요한 이유
FIZ는 포르투갈 세무 당국(Autoridade Tributária, "AT")에 보고되는 법적 구속력이 있는 세금 문서를 발행합니다. 잘못된 VAT 세율이나 누락된 면제 사유는 단순한 외관상 버그가 아닙니다 — 발행된 후에는 신용 메모로만 수정할 수 있는 잘못된 세금 문서를 생성합니다. 발행 전에 세금 필드를 올바르게 설정하십시오.
가장 흔히 잘못될 수 있는 두 가지 사항과 이를 처리하는 방법:
1. VAT 세율(vatRate on each item) — 절대 추측하지 마십시오. 세율 구간(NORMAL | INTERMEDIATE | REDUCED | EXEMPT)과 해당 백분율은 지역(포르투갈 본토 / 아소르스 / 마데이라)에 따라 다릅니다. NORMAL을 기본값으로 사용하십시오 — REDUCED/INTERMEDIATE는 법적으로 정의된 특정 범주(일부 식품, 레스토랑, 문화 행사 등)에만 적용됩니다. 사용자가 그러한 범주를 언급하지 않은 경우 NORMAL을 사용하고 그 이유를 설명하거나, 사용자에게 물어보십시오. 절대 묵시적으로 감면 세율을 적용하지 마십시오. 지역별 백분율 표는 domain.md에 있습니다.
2. VAT 면제에는 사유 코드(vatExemptionReason)가 필요합니다.
vatRate가 EXEMPT인 경우, 포르투갈 법률은 motivo de isenção — 법적 근거를 명시하는 M-코드를 요구합니다. 항상 설정하십시오. 유효한 사유 없는 면제 품목은 유효하지 않은 문서이며 발행 시 거부될 수 있습니다. 코드는 실제 사유를 반영해야 합니다: 소기업 체제 → M10, 본질적으로 면제되는 활동(의료/교육) → M07, EU B2B / 역과세 → M40/M16/M19. 사용자가 면제 대상이지만 코드를 모르는 경우, 이유를 묻고 매핑하십시오 — 임의로 선택하지 마십시오. 전체 코드 목록과 법적 참조는 domain.md에 있습니다.
알아두면 유용한 기타 도메인 규칙 (자세한 내용은 domain.md에 있음):
- CAE는 사업자가 등록한 5자리 포르투갈 경제 활동 코드입니다. 임의로 만들지 마십시오 — 사용자에게 물어보거나 이전 인보이스의 CAE를 재사용하십시오. 최신(Rev. 4) 코드여야 합니다.
- NIF(
taxpayerNumber)는 체크섬이 있는 9자리 포르투갈 세금 번호입니다. B2B에는 필수, 최종 소비자에게는 선택 사항입니다. EU B2B의 경우 역과세 처리를 위해 고객의 VAT 번호가 중요합니다. - 원천징수세(retenção na fonte: IRS/IRC/IS)는 품목에 구성됩니다. 자영업 서비스의 일반 세율은 25%입니다. 지급인이 원천징수하여 실제 지급 금액을 줄입니다.
- 문서 유형은 규칙에 영향을 미칩니다:
SIMPLIFIED_INVOICE는 소매 판매용이며 전체 고객 데이터를 생략할 수 있습니다. €1,000 이상인 사업체에 대한INVOICE는 고객 NIF가 필요합니다.
워크플로우
다음 단계를 따르십시오. 사용자가 이미 고객 ID와 품목 ID를 제공한 경우 1~2단계를 건너뛰십시오.
1단계 — 고객 확인
중복을 피하기 위해 먼저 검색한 후, 필요하면 생성합니다.
예제는 fiz 헬퍼(설정 참조)를 사용합니다. 이 헬퍼는 HTTP 상태를 자동으로 확인합니다. 동등한 원시 curl은 부록에 있습니다.
검색어(이름, 세금 번호, 이메일)로 검색:
fiz GET "/customers?search=Joao"
고객 생성(name만 필수):
fiz POST /customers '{
"name": "João Silva",
"email": "[email protected]",
"taxpayerNumber": "303741791",
"country": "PT"
}'
반환된 id를 보관하십시오 — 이것이 인보이스의 customerId가 됩니다.
2단계 — 품목(제품/서비스) 확인
기존 품목 검색:
fiz GET "/items?search=consulting"
세금 필드가 판매 내용과 일치하는 경우에만 기존 품목을 재사용하십시오. 이름이 일치하는 검색 결과만으로는 충분하지 않습니다 — 세금 문서의 경우 품목의
vatRate,vatTerritory,vatExemptionReason,taxRate및 원천징수 필드가 이 고객 및 판매에 대해 의도한 처리 방식과 일치해야 합니다. 이 중 하나라도 다른 경우(예: 동일한 서비스이지만 고객이 면제 대상이거나, 다른 지역에 있거나, 원천징수 대상인 경우), 일치하지 않는 품목을 재사용하지 말고 올바른 필드로 새 품목을 생성하십시오. 확실하지 않은 경우, 찾은 품목의 필드를 검토하고 사용자에게 확인하십시오.
품목 생성. 필수: name, type (PRODUCT | SERVICE), unitPrice, vatRate (NORMAL | INTERMEDIATE | REDUCED | EXEMPT):
fiz POST /items '{
"name": "Consulting hour",
"type": "SERVICE",
"unitPrice": 80,
"vatRate": "NORMAL"
}'
각각 반환된 id를 보관하십시오 — 이것이 인보이스의 품목 ID가 됩니다.
unitPrice는 단가입니다. 라인별 총액은 인보이스에서 제공하는quantity를 기반으로 FIZ가 계산합니다.vatRate는 신중하게 선택하십시오 — 위의 도메인 섹션을 참조하세요. 범주가 명확히 감면 세율을 정당화하지 않는 한NORMAL을 기본값으로 사용하십시오.vatRate가EXEMPT인 경우, 판매가 면제되는 이유와 일치하는vatExemptionReasonM-코드를 항상 설정하십시오(예: 소기업 체제의 경우M10). 이 필드는 품목 생성 시 기술적으로 선택 사항이지만, 유효한 사유 없는 면제 품목은 부정확하며 나중에 인보이스 발행 시 거부될 수 있습니다. 전체 코드 목록은domain.md를 참조하십시오.
3단계 — 초안 인보이스 생성
필수 필드: dueDate (ISO 8601), cae (포르투갈 경제 활동 코드), type, customerId, 및 items (최소 하나의 { id, quantity }).
fiz POST /invoices '{
"dueDate": "2026-07-18T00:00:00.000Z",
"cae": "62010",
"type": "INVOICE",
"customerId": "6863b1513117c5892ff55296",
"items": [
{ "id": "68483e978073231c3947077c", "quantity": 10 }
]
}'
응답에는 새 인보이스 id(발행에 필요)와 status(DRAFT)가 포함됩니다. 인보이스 date는 현재 시간으로 설정되고 currency는 API에 의해 EUR로 설정됩니다 — 이러한 필드는 전송하지 않습니다.
선택 사항 — 전역 할인 (summary):
"summary": { "globalDiscountType": "PERCENT", "globalDiscountPercent": 10 }
고정 금액 할인을 위해 "AMOUNT"를 globalDiscountAmount와 함께 사용하십시오.
선택 사항 — 생성 시 결제 (payment): type이 INVOICE_RECEIPT 또는 SIMPLIFIED_INVOICE인 경우에만 허용됩니다. 그렇지 않으면 API는 400을 반환합니다.
"payment": { "method": "mbWay", "date": "2026-07-18T00:00:00.000Z" }
method는 cash, card, bankTransfer, mbWay, multibanco, spin, other 중 하나입니다.
4단계 — 인보이스 발행
이는 법적 구속력이 있는 단계입니다. 사용자에게 확인을 받은 후:
fiz POST /invoices/{id}/issue
응답에는 공식 number, status: ISSUED, 그리고 syncWithAt 블록이 포함됩니다. syncWithAt.status를 확인하십시오 — FAILED인 경우 인보이스는 로컬로 생성되었지만 세무 당국과 동기화되지 않은 것입니다. 성공을 주장하지 말고 atMessage와 isRetriable이 true인지 여부를 사용자에게 보고하십시오.
5단계 — PDF 다운로드 (선택 사항)
fiz GET /invoices/{id}/pdf
{ id, name, url }을 반환합니다. url은 PDF에 대한 다운로드 가능한 링크입니다. ?format=A4 또는 ?format=RECEIPT를 추가하여 레이아웃을 선택하십시오.
문서 유형 (type)
값: INVOICE · INVOICE_RECEIPT · SIMPLIFIED_INVOICE · RECEIPT · CREDIT_NOTE · DEBIT_NOTE. 사용자가 영수증 또는 간이 인보이스를 요청하지 않는 한 INVOICE를 기본값으로 사용하십시오. INVOICE_RECEIPT 및 SIMPLIFIED_INVOICE만 생성 시 payment 객체를 허용합니다. 각 유형의 의미와 사용 시기는 domain.md를 참조하십시오.
일반 작업 참조
| 작업 | 메서드 및 경로 |
|---|---|
| 고객 목록/검색 | GET /customers?search=… |
| 고객 생성 | POST /customers |
| 품목 목록/검색 | GET /items?search=… |
| 품목 생성 | POST /items |
| 초안 생성 | POST /invoices |
| 발행 | POST /invoices/:id/issue |
| 인보이스 목록 | GET /invoices |
| 단일 인보이스 조회 | GET /invoices/:id |
| PDF 다운로드 | GET /invoices/:id/pdf |
| 삭제 (초안) | DELETE /invoices/:id |
오류 처리
명령어가 실행되었는지뿐만 아니라 항상 HTTP 상태를 확인하십시오. 오류 발생 시 API는 일반적인 JSON 본문({ "statusCode": 400, "message": "...", "timestamp": "..." })을 일치하는 HTTP 상태와 함께 반환합니다. 원시 curl -s를 사용하면 해당 본문이 출력되고 curl은 여전히 0으로 종료되므로 오류를 결과로 착각하기 쉽습니다. fiz 헬퍼는 이에 대해 보호합니다: HTTP <code> 라인을 출력하고 4xx/5xx에서 0이 아닌 값을 반환합니다. 원시 curl을 사용해야 하는 경우 -w '\n%{http_code}'(또는 -o body -w '%{http_code}')를 추가하고 코드를 검사하십시오.
일반적인 상태:
- 401 — API 키 누락/유효하지 않음. 사용자에게 환경(채팅 아님)에서
FIZ_API_KEY를 설정하도록 알리십시오. - 400 — 유효성 검사 오류.
message에 해당 필드가 명시됩니다. 일반적인 경우: 빈items, 지원되지 않는type에 대한payment, 알 수 없거나 추가된 필드(엄격한 화이트리스트), 잘못된 형식의dueDate(시간대를 포함한 전체 ISO 8601이어야 함, 예:2026-07-18T00:00:00.000Z). - 5xx — 백엔드/AT 문제. 사용자에게 표시하고, 동일한 쓰기를 맹목적으로 재시도하지 마십시오(생성이 부분적으로 성공했을 수 있음 — 먼저
GET으로 확인하십시오).
맹목적으로 재시도하는 대신 항상 API의 message를 사용자에게 다시 전달하십시오.
전체적이고 권위 있는 요청/응답 계약은 라이브 Swagger UI(**https://api.fiz.co/**)에 있습니다. 여기 있는 필드가 오래된 것 같으면 해당 사이트를 참조하십시오.
더 자세한 정보가 필요한 경우
이 스킬 디렉토리에 있는 두 개의 동반 파일:
domain.md— 포르투갈 세금 도메인: 지역별 VAT 세율, 전체 면제 (M) 코드 목록 및 각 코드의 적용 시기, 문서 유형, CAE/NIF 규칙, 원천징수세, AT 동기화/발행 불가역성 작동 방식. 세금 결정이 명확하지 않은 경우(특히vatRate또는 면제 사유 선택 시) 항상 이 파일을 읽으십시오.reference.md— 필드별 전체 API 참조(모든 고객/품목/인보이스 필드, 모든 열거형 값, 전체 요청/응답 형태).
부록 — 원시 curl (헬퍼 없이)
위의 fiz 헬퍼를 선호하십시오. HTTP 상태를 확인합니다. 헬퍼를 사용할 수 없는 경우 원시 curl을 -w '\n%{http_code}'와 함께 사용하고(또는 -o /dev/null -w '%{http_code}') 종료 코드뿐만 아니라 HTTP 상태 코드를 확인하십시오.
# 고객 검색
curl -s -H "x-api-key: $FIZ_API_KEY" "https://api.fiz.co/customers?search=Joao"
# 고객 생성
curl -s -X POST -H "x-api-key: $FIZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "João Silva", "email": "[email protected]", "taxpayerNumber": "303741791", "country": "PT" }' \
"https://api.fiz.co/customers"
# 품목 생성
curl -s -X POST -H "x-api-key: $FIZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Consulting hour", "type": "SERVICE", "unitPrice": 80, "vatRate": "NORMAL" }' \
"https://api.fiz.co/items"
# 초안 인보이스 생성
curl -s -X POST -H "x-api-key: $FIZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "dueDate": "2026-07-18T00:00:00.000Z", "cae": "62010", "type": "INVOICE", "customerId": "...", "items": [{ "id": "...", "quantity": 10 }] }' \
"https://api.fiz.co/invoices"
# 발행
curl -s -X POST -H "x-api-key: $FIZ_API_KEY" \
"https://api.fiz.co/invoices/{id}/issue"
# PDF 다운로드
curl -s -o invoice.pdf -H "x-api-key: $FIZ_API_KEY" \
"https://api.fiz.co/invoices/{id}/pdf"