{"openapi":"3.1.0","info":{"title":"Threecom e-Invoice Middleware","version":"1.0.0","description":"Submit e-Invoices to LHDN MyInvois from any POS or accounting system.\n\nWe act as your registered intermediary: you send a plain document, we map it to UBL 2.1, sign it, submit it, chase the validation result, and hand you back a status and a validation link.\n\nSubmission is asynchronous. POST returns 202 immediately; poll for the outcome. Never block a sale on this API."},"servers":[{"url":"https://einvoice.threecomcloud.com"}],"paths":{"/api/v1/documents":{"post":{"summary":"Submit one or more documents","description":"Idempotent on traceId — retrying a timed-out call returns the original document rather than creating a duplicate. Derive traceId deterministically from your own document key so this property actually protects you.","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Document"},{"type":"object","properties":{"documents":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/Document"}}}}]}}}},"responses":{"202":{"description":"Accepted for submission","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"integer"},"documents":{"type":"array","items":{"type":"object","properties":{"traceId":{"type":"string"},"docNo":{"type":"string"},"documentType":{"type":"string"},"status":{"type":"string","enum":["Pending","Submitted","Valid","Invalid","Cancelled","Failed"],"description":"Pending: accepted by us, not yet at LHDN. Submitted: LHDN accepted it, validating. Valid / Invalid / Cancelled: terminal. Failed: we could not deliver it; retrying unless retryStopped."},"uuid":{"type":"string","nullable":true,"description":"LHDN document identifier."},"submissionUid":{"type":"string","nullable":true},"longId":{"type":"string","nullable":true},"validationLink":{"type":"string","nullable":true,"description":"Public LHDN validation URL. Print this as a QR code on the invoice."},"issueDateTime":{"type":"string","format":"date-time"},"submittedAt":{"type":"string","format":"date-time","nullable":true},"validatedAt":{"type":"string","format":"date-time","nullable":true},"cancelledAt":{"type":"string","format":"date-time","nullable":true},"cancelReason":{"type":"string","nullable":true},"totalPayable":{"type":"number"},"currency":{"type":"string"},"buyerTin":{"type":"string","nullable":true},"buyerName":{"type":"string","nullable":true},"attemptCount":{"type":"integer"},"retryStopped":{"type":"boolean","description":"True when we have given up. Requires a fix and a new traceId."},"lastError":{"type":"string","nullable":true}}}}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"},"detail":{}}}}}}}},"422":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"},"detail":{}}}}}}}}}},"get":{"summary":"List documents","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"docNo","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"},"detail":{}}}}}}}}}}},"/api/v1/documents/status":{"post":{"summary":"Batch status lookup","description":"Refresh a screen full of documents in one call. Note that 'status' is a reserved traceId because of this route.","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"traceIds":{"type":"array","items":{"type":"string"},"maxItems":500},"docNos":{"type":"array","items":{"type":"string"},"maxItems":500}}}}}},"responses":{"200":{"description":"OK"},"422":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"},"detail":{}}}}}}}}}}},"/api/v1/documents/{traceId}":{"get":{"summary":"Get one document","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."},{"name":"traceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"include","in":"query","schema":{"type":"string","enum":["payload"]},"description":"include=payload returns the exact UBL and signed JSON we sent to LHDN — what you need when a document is rejected and nobody agrees on what was submitted."}],"responses":{"200":{"description":"OK"},"404":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"},"detail":{}}}}}}}}}}},"/api/v1/documents/{traceId}/cancel":{"post":{"summary":"Cancel a validated document","description":"Only a Valid document can be cancelled, and only within 72 hours of validation. After that, issue a credit or refund note instead. Synchronous.","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."},{"name":"traceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","maxLength":300}}}}}},"responses":{"200":{"description":"Cancelled"},"409":{"description":"Outside the window, or not Valid","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"},"detail":{}}}}}}}}}}},"/api/v1/taxpayers/validate":{"get":{"summary":"Validate a TIN against a registration number","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."},{"name":"tin","in":"query","required":true,"schema":{"type":"string"}},{"name":"idType","in":"query","required":true,"schema":{"type":"string","enum":["NRIC","BRN","PASSPORT","ARMY"]}},{"name":"idValue","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/api/v1/taxpayers/search":{"get":{"summary":"Find a TIN by name or registration number","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."},{"name":"taxpayerName","in":"query","schema":{"type":"string"}},{"name":"idType","in":"query","schema":{"type":"string"}},{"name":"idValue","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/api/v1/pos/qr":{"post":{"summary":"Mint a signed receipt QR link","description":"Print the returned URL as a QR code on the receipt. A walk-in customer scans it and supplies their tax details, which you collect from /api/v1/pos/requests. Stateless and signed, so it is safe to call on every sale.","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["docNo","docDate","amount"],"properties":{"docNo":{"type":"string"},"docDate":{"type":"string","format":"date-time"},"amount":{"type":"number"}}}}}},"responses":{"200":{"description":"OK"}}}},"/api/v1/pos/requests":{"get":{"summary":"Collect customer e-Invoice requests","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."},{"name":"status","in":"query","schema":{"type":"string","enum":["New","Collected","Fulfilled","Rejected"]}},{"name":"markCollected","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Flip the returned requests to Collected in the same call. A POS that crashes mid-loop re-reads them next time rather than losing them."}],"responses":{"200":{"description":"OK"}}},"patch":{"summary":"Close a request after raising the document","parameters":[{"name":"CompanyId","in":"header","required":true,"schema":{"type":"string"},"description":"Your company code, issued at onboarding."},{"name":"KeyId","in":"header","required":true,"schema":{"type":"string"},"description":"Identifies which API key you are presenting."},{"name":"ApiKey","in":"header","required":true,"schema":{"type":"string"},"description":"The secret half of the key pair. Never log or embed this in a client binary."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["Collected","Fulfilled","Rejected"]},"traceId":{"type":"string"}}}}}},"responses":{"200":{"description":"OK"}}}},"/api/v1/codes":{"get":{"summary":"LHDN reference code lists","description":"Unauthenticated. Populate your dropdowns from here rather than hard-coding lists that go stale when LHDN publishes an update.","responses":{"200":{"description":"OK"}}}},"/api/v1/health":{"get":{"summary":"Service status","description":"Unauthenticated. Reports whether signing is configured — the difference between emitting compliant v1.1 documents and silently downgrading to v1.0.","responses":{"200":{"description":"OK"}}}}},"components":{"schemas":{"StatusView":{"type":"object","properties":{"traceId":{"type":"string"},"docNo":{"type":"string"},"documentType":{"type":"string"},"status":{"type":"string","enum":["Pending","Submitted","Valid","Invalid","Cancelled","Failed"],"description":"Pending: accepted by us, not yet at LHDN. Submitted: LHDN accepted it, validating. Valid / Invalid / Cancelled: terminal. Failed: we could not deliver it; retrying unless retryStopped."},"uuid":{"type":"string","nullable":true,"description":"LHDN document identifier."},"submissionUid":{"type":"string","nullable":true},"longId":{"type":"string","nullable":true},"validationLink":{"type":"string","nullable":true,"description":"Public LHDN validation URL. Print this as a QR code on the invoice."},"issueDateTime":{"type":"string","format":"date-time"},"submittedAt":{"type":"string","format":"date-time","nullable":true},"validatedAt":{"type":"string","format":"date-time","nullable":true},"cancelledAt":{"type":"string","format":"date-time","nullable":true},"cancelReason":{"type":"string","nullable":true},"totalPayable":{"type":"number"},"currency":{"type":"string"},"buyerTin":{"type":"string","nullable":true},"buyerName":{"type":"string","nullable":true},"attemptCount":{"type":"integer"},"retryStopped":{"type":"boolean","description":"True when we have given up. Requires a fix and a new traceId."},"lastError":{"type":"string","nullable":true}}},"Address":{"type":"object","required":["line0","city","state"],"properties":{"line0":{"type":"string","maxLength":150},"line1":{"type":"string","maxLength":150},"line2":{"type":"string","maxLength":150},"city":{"type":"string","maxLength":50},"postalZone":{"type":"string","maxLength":50},"state":{"type":"string","description":"LHDN state code, e.g. 14 for Kuala Lumpur. Use 17 for non-Malaysian."},"country":{"type":"string","default":"MYS","description":"ISO 3166-1 alpha-3."}}},"Party":{"type":"object","required":["name","tin","idType","idValue","phone","address"],"properties":{"name":{"type":"string","maxLength":300},"tin":{"type":"string","description":"Use EI00000000010 with idValue 000000000000 for a consolidated general-public document."},"idType":{"type":"string","enum":["BRN","NRIC","PASSPORT","ARMY","TIN"]},"idValue":{"type":"string"},"sstNo":{"type":"string"},"ttxNo":{"type":"string"},"msic":{"type":"string","description":"Supplier only. 5-digit MSIC code."},"msicDesc":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"address":{"$ref":"#/components/schemas/Address"}}},"Tax":{"type":"object","required":["category","taxAmount"],"properties":{"category":{"type":"string","enum":["01","02","03","04","05","06","E"],"description":"01 Sales, 02 Service, 03 Tourism, 04 HVGT, 05 LVG, 06 N/A, E Exempt."},"rate":{"type":"number","description":"Percentage, e.g. 8 for 8%."},"taxableAmount":{"type":"number"},"taxAmount":{"type":"number"},"exemptionReason":{"type":"string","description":"Required when category is E."},"exemptionAmount":{"type":"number"}}},"Line":{"type":"object","required":["description","classificationCode","unitPrice"],"properties":{"id":{"type":"string"},"description":{"type":"string","maxLength":300},"classificationCode":{"type":"string","description":"LHDN classification, e.g. 022 Others, 004 Consolidated e-Invoice."},"itemCode":{"type":"string","description":"Your own code. Passed through, not sent to LHDN."},"quantity":{"type":"number","default":1},"unitCode":{"type":"string","description":"UN/ECE Rec 20, e.g. C62, KGM. Defaults to C62."},"unitPrice":{"type":"number"},"subtotal":{"type":"number","description":"Derived from quantity × unitPrice if omitted."},"discountAmount":{"type":"number","default":0},"discountReason":{"type":"string"},"chargeAmount":{"type":"number","default":0},"chargeReason":{"type":"string"},"taxes":{"type":"array","items":{"$ref":"#/components/schemas/Tax"}},"originCountry":{"type":"string"}}},"Document":{"type":"object","required":["traceId","sourceSystem","docNo","documentType","issueDateTime","buyer","lines"],"properties":{"traceId":{"type":"string","maxLength":80,"description":"Idempotency key. Derive it from your own document key."},"sourceSystem":{"type":"string","description":"e.g. AUTOCOUNT_POS, IRS_POS, CUSTOM."},"docNo":{"type":"string","maxLength":50},"documentType":{"type":"string","enum":["01","02","03","04","11","12","13","14"],"description":"01 Invoice, 02 Credit Note, 03 Debit Note, 04 Refund Note, 11-14 self-billed equivalents."},"issueDateTime":{"type":"string","format":"date-time"},"currency":{"type":"string","default":"MYR"},"exchangeRate":{"type":"number","description":"Required when currency is not MYR."},"supplier":{"allOf":[{"$ref":"#/components/schemas/Party"}],"description":"Omit to use your registered profile. Supply it only for self-billed documents, where the supplier is the third party."},"buyer":{"$ref":"#/components/schemas/Party"},"lines":{"type":"array","minItems":1,"maxItems":500,"items":{"$ref":"#/components/schemas/Line"}},"totals":{"type":"object","description":"Derived from lines if omitted. Supply it to assert your own figures — we will not silently correct them, because the e-Invoice must agree with the customer's receipt.","properties":{"totalExcludingTax":{"type":"number"},"totalIncludingTax":{"type":"number"},"totalPayable":{"type":"number"},"totalNetAmount":{"type":"number"},"totalDiscount":{"type":"number"},"totalCharges":{"type":"number"},"rounding":{"type":"number"}}},"taxes":{"type":"array","items":{"$ref":"#/components/schemas/Tax"}},"payment":{"type":"object","properties":{"means":{"type":"array","items":{"type":"string"},"description":"01 Cash, 02 Cheque, 03 Bank Transfer, 04 Credit Card, 06 e-Wallet…"},"terms":{"type":"string"},"prepaidAmount":{"type":"number"},"prepaidDate":{"type":"string","format":"date-time"},"prepaidReference":{"type":"string"},"payeeBankAccount":{"type":"string"}}},"references":{"type":"object","description":"Credit/debit/refund notes must reference the original document.","properties":{"originalDocNo":{"type":"string"},"originalUuid":{"type":"string"},"billingReference":{"type":"string"},"customsImportFormNo":{"type":"string"},"freeTradeAgreementInfo":{"type":"string"},"k2FormNo":{"type":"string"},"incoterms":{"type":"string"}}},"invoicePeriod":{"type":"object","properties":{"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"description":{"type":"string","description":"e.g. Monthly."}}},"note":{"type":"string","maxLength":1000}}}}}}