diff --git a/README.md b/README.md
index 447b414..8b586bd 100644
--- a/README.md
+++ b/README.md
@@ -143,11 +143,11 @@ These changes improve throughput and reduce memory pressure when working with la
- [formatFileSize](#formatfilesize) - Converts a number of bytes into a human-readable file size string (B, KB, MB, GB, TB).
- [formatOrdinal](#formatordinal) - Converts a number into its ordinal string representation (e.g., 1 → "1st", 2 → "2nd").
- [formatList](#formatlist) - Formats an array of strings into a human-readable list with proper commas and "and".
+- [formatCreditCard](#formatcreditcard) - Formats a credit card number by grouping digits into readable parts.
- [formatToOctal](#formattotoctal) - Converts a decimal number to octal, optional "0o" prefix.
- [formatTemperature](#formattemperature) - Converts temperatures between Celsius, Fahrenheit, and Kelvin.
- [formatToBinary](#formattobinary) - Converts a decimal integer to a binary string with optional bit grouping.
- [formatToHexadecimal](#formattohexadecimal) - Converts temperatures between Celsius, Fahrenheit, and Kelvin.
-
- [formatToDecimal](#formattodecimal) - Converts base-2/8/16 strings to decimal.
## 📋 API Reference
@@ -1486,6 +1486,27 @@ formatList(['apple', 123]); // TypeError
| --------- | -------- | -------- | ----------------------------------------- |
| arr | string[] | required | The array of strings to format as a list. |
+#### formatCreditCard(cardNumber)
+Formats a credit card number into readable groups of digits separated by spaces.
+Supports 15-digit (AmEx) and 16-digit (Visa/MasterCard) numbers.
+Non-digit characters are automatically stripped before formatting.
+Throws an error if the input is not a string.
+
+```javascript
+import { formatCreditCard } from 'stringzy';
+
+formatCreditCard('1234567812345678'); // "1234 5678 1234 5678"
+formatCreditCard('4111111111111111'); // "4111 1111 1111 1111"
+formatCreditCard('378282246310005'); // "3782 822463 10005" (AmEx)
+formatCreditCard('4111-1111-1111-1111'); // "4111 1111 1111 1111"
+formatCreditCard('123'); // "" (invalid length)
+formatCreditCard(''); // "" (empty string)
+```
+
+| Parameter | Type | Default | Description |
+| ---------- | ------ | -------- | ------------------------------------------------------------------- |
+| cardNumber | string | required | The credit card number to format. Cannot include non-digit characters. |
+
#### formatToOctal(num, options?)
Converts a decimal number to its octal (base-8) string representation. Supports negatives and an optional `0o` prefix.
diff --git a/src/formatting/creditCard.ts b/src/formatting/creditCard.ts
new file mode 100644
index 0000000..36224ff
--- /dev/null
+++ b/src/formatting/creditCard.ts
@@ -0,0 +1,29 @@
+/**
+ * Formats a credit card number by grouping digits into readable parts.
+ *
+ * @param {string} cardNumber - The credit card number to format.
+ * @returns {string} The formatted credit card number.
+ * @throws {TypeError} If the input is not a string.
+ */
+export function formatCreditCard(cardNumber: string): string {
+ if (typeof cardNumber !== 'string') {
+ throw new TypeError('Input must be a string');
+ }
+
+ // Remove all non-digit characters
+ const cleaned = cardNumber.replace(/\D/g, '');
+
+ // Only accept 15 or 16 digit card numbers
+ if (cleaned.length !== 15 && cleaned.length !== 16) {
+ return '';
+ }
+
+ // Format based on length:
+ // 16 digits → 4-4-4-4 (Visa, MasterCard)
+ if (cleaned.length === 16) {
+ return cleaned.replace(/(\d{4})(?=\d)/g, '$1 ').trim();
+ }
+
+ // 15 digits → 4-6-5 (AmEx)
+ return cleaned.replace(/(\d{4})(\d{6})(\d{5})/, '$1 $2 $3');
+}
diff --git a/src/formatting/index.ts b/src/formatting/index.ts
index cfc69de..0fd62bc 100644
--- a/src/formatting/index.ts
+++ b/src/formatting/index.ts
@@ -8,6 +8,7 @@ export { formatPercentage } from './percentage';
export { formatFileSize } from './fileSize';
export { formatOrdinal } from './ordinal';
export { formatList } from './listToString';
+export { formatCreditCard } from './creditCard';
export { formatToOctal } from './octal';
export { formatTemperature } from './temperature';
export { formatToBinary } from './binary';
@@ -24,6 +25,7 @@ import { formatPercentage } from './percentage';
import { formatFileSize } from './fileSize';
import { formatOrdinal } from './ordinal';
import { formatList } from './listToString';
+import { formatCreditCard } from './creditCard';
import { formatToOctal } from './octal';
import { formatTemperature } from './temperature';
import { formatToBinary } from './binary';
@@ -41,6 +43,7 @@ export const formatting = {
formatFileSize,
formatOrdinal,
formatList,
+ formatCreditCard,
formatTemperature,
formatToBinary,
formatToHexadecimal,
diff --git a/src/tests/formatting/creditCard.test.ts b/src/tests/formatting/creditCard.test.ts
new file mode 100644
index 0000000..c2d20bd
--- /dev/null
+++ b/src/tests/formatting/creditCard.test.ts
@@ -0,0 +1,31 @@
+import { describe, it } from 'node:test';
+import assert from 'node:assert';
+import { formatCreditCard } from '../../formatting/creditCard';
+
+describe('formatCreditCard', () => {
+ it('formats 16-digit card numbers correctly', () => {
+ assert.strictEqual(formatCreditCard('1234567812345678'), '1234 5678 1234 5678');
+ assert.strictEqual(formatCreditCard('4111111111111111'), '4111 1111 1111 1111');
+ });
+
+ it('formats 15-digit card numbers (AmEx) correctly', () => {
+ assert.strictEqual(formatCreditCard('378282246310005'), '3782 822463 10005');
+ });
+
+ it('removes non-digit characters before formatting', () => {
+ assert.strictEqual(formatCreditCard('4111-1111-1111-1111'), '4111 1111 1111 1111');
+ assert.strictEqual(formatCreditCard('3782 8224 6310 005'), '3782 822463 10005');
+ });
+
+ it('returns empty string for invalid lengths', () => {
+ assert.strictEqual(formatCreditCard('123'), '');
+ assert.strictEqual(formatCreditCard('11112222333344445555'), '');
+ assert.strictEqual(formatCreditCard(''), '');
+ });
+
+ it('throws an error if input is not a string', () => {
+ assert.throws(() => formatCreditCard(1234567812345678 as any), /Input must be a string/);
+ assert.throws(() => formatCreditCard(null as any), /Input must be a string/);
+ assert.throws(() => formatCreditCard(undefined as any), /Input must be a string/);
+ });
+});