diff --git a/epicardium/api/interrupt-receiver.c b/epicardium/api/interrupt-receiver.c
index 95c5038d12ee10bdc53a087ea121a568bb44d86a..c212a402d0a564375bddc193fd7ccf7c50507a81 100644
--- a/epicardium/api/interrupt-receiver.c
+++ b/epicardium/api/interrupt-receiver.c
@@ -3,33 +3,12 @@
 #include "api/common.h"
 #include "epicardium.h"
 
-void api_interrupt_handler_ctrl_c(api_int_id_t id)
-	__attribute__((weak, alias("api_interrupt_handler_default")));
-void api_interrupt_handler_bhi160(api_int_id_t id)
-	__attribute__((weak, alias("api_interrupt_handler_default")));
+void __dispatch_isr(api_int_id_t);
 
 /* Timer Interrupt used for control char notification */
 void TMR5_IRQHandler(void)
 {
 	TMR_IntClear(MXC_TMR5);
-
-	switch (API_CALL_MEM->int_id) {
-	case API_INT_CTRL_C:
-		api_interrupt_handler_ctrl_c(API_CALL_MEM->int_id);
-		break;
-	case API_INT_BHI160:
-		api_interrupt_handler_bhi160(API_CALL_MEM->int_id);
-		break;
-	}
-
+	__dispatch_isr(API_CALL_MEM->int_id);
 	API_CALL_MEM->int_id = 0;
 }
-
-__attribute__((weak)) void api_interrupt_handler_catch_all(api_int_id_t id)
-{
-}
-
-void api_interrupt_handler_default(api_int_id_t id)
-{
-	api_interrupt_handler_catch_all(id);
-}
diff --git a/epicardium/api/interrupt-sender.c b/epicardium/api/interrupt-sender.c
index fb0c65a7c189fbdfa329e8a6a8acdfb67db97c64..cabd3bcb2b96f6f79c65a0a9722bd05860cf860e 100644
--- a/epicardium/api/interrupt-sender.c
+++ b/epicardium/api/interrupt-sender.c
@@ -2,15 +2,15 @@
 #include "api/common.h"
 #include "tmr_utils.h"
 
-static bool enabled[API_INT_MAX + 1];
+static bool int_enabled[EPIC_INT_NUM];
 
 int api_interrupt_trigger(api_int_id_t id)
 {
-	if (id > API_INT_MAX) {
+	if (id >= EPIC_INT_NUM) {
 		return -EINVAL;
 	}
 
-	if (enabled[id]) {
+	if (int_enabled[id]) {
 		while (API_CALL_MEM->int_id)
 			;
 		API_CALL_MEM->int_id = id;
@@ -21,30 +21,29 @@ int api_interrupt_trigger(api_int_id_t id)
 
 void api_interrupt_init(void)
 {
-	int i;
 	API_CALL_MEM->int_id = 0;
 
-	for (i = 0; i <= API_INT_MAX; i++) {
-		enabled[i] = false;
+	for (int i = 0; i < EPIC_INT_NUM; i++) {
+		int_enabled[i] = false;
 	}
 }
 
 int epic_interrupt_enable(api_int_id_t int_id)
 {
-	if (int_id > API_INT_MAX) {
+	if (int_id >= EPIC_INT_NUM) {
 		return -EINVAL;
 	}
 
-	enabled[int_id] = true;
+	int_enabled[int_id] = true;
 	return 0;
 }
 
 int epic_interrupt_disable(api_int_id_t int_id)
 {
-	if (int_id > API_INT_MAX) {
+	if (int_id >= EPIC_INT_NUM) {
 		return -EINVAL;
 	}
 
-	enabled[int_id] = false;
+	int_enabled[int_id] = false;
 	return 0;
 }
diff --git a/epicardium/api/interrupt-sender.h b/epicardium/api/interrupt-sender.h
index 4f690167ceff8622418b4983da17b29085a446f4..419993c72388d15a234d4887a4a71d0a00ccd6d7 100644
--- a/epicardium/api/interrupt-sender.h
+++ b/epicardium/api/interrupt-sender.h
@@ -1,4 +1,5 @@
 #pragma once
 #include "api/common.h"
+
 void api_interrupt_init(void);
 int api_interrupt_trigger(api_int_id_t id);
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index c32120e87399e7ca455d2b00ad0b20579df5d1f2..485cb2e1b19bc47af0ee31192cd43cb9470d2fb8 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -11,18 +11,22 @@
 typedef unsigned int size_t;
 #endif /* __SPHINX_DOC */
 
-/* clang-format off */
-#define API_INT_CTRL_C  1
-#define API_INT_BHI160  2
-#define API_INT_MAX     API_INT_BHI160
-
 /*
  * These definitions are required for the code-generator.  Please don't touch!
  */
 #ifndef API
 #define API(id, def) def
 #endif
+#ifndef API_ISR
+#define API_ISR(id, isr) void isr(void);
+#endif
 
+/*
+ * IDs for all defined API calls.  These IDs should not be needed in application
+ * code on any side.
+ */
+
+/* clang-format off */
 #define API_UART_WRITE         0x1
 #define API_UART_READ          0x2
 #define API_LEDS_SET           0x3
@@ -31,9 +35,53 @@ typedef unsigned int size_t;
 #define API_STREAM_READ        0x6
 #define API_INTERRUPT_ENABLE   0x7
 #define API_INTERRUPT_DISABLE  0x8
+/* clang-format on */
+
+typedef uint32_t api_int_id_t;
+
+/**
+ * Interrupts
+ * ==========
+ * Next to API calls, Epicardium API also has an interrupt mechanism to serve
+ * the other direction.  These interrupts can be enabled/disabled
+ * (masked/unmasked) using :c:func:`epic_interrupt_enable` and
+ * :c:func:`epic_interrupt_disable`.
+ */
+
+/**
+ * Enable/unmask an API interrupt.
+ *
+ * :param int_id: The interrupt to be enabled
+ */
+API(API_INTERRUPT_ENABLE, int epic_interrupt_enable(api_int_id_t int_id));
+
+/**
+ * Disable/mask an API interrupt.
+ *
+ * :param int_id: The interrupt to be disabled
+ */
+API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id));
+
+/**
+ * The following interrupts are defined:
+ */
 
+/* clang-format off */
+/** Reset Handler? **TODO** */
+#define EPIC_INT_RESET                  0
+/** ``^C`` interrupt. See :c:func:`epic_isr_ctrl_c` for details.  */
+#define EPIC_INT_CTRL_C                 1
+/* Debug interrupt, please ignore */
+#define EPIC_INT_BHI160_TEST            2
+API_ISR(EPIC_INT_BHI160_TEST, epic_isr_bhi160_test);
+
+/* Number of defined interrupts. */
+#define EPIC_INT_NUM                    3
 /* clang-format on */
 
+API_ISR(EPIC_INT_RESET, epic_isr_reset);
+
+
 /**
  * UART/Serial Interface
  * =====================
@@ -60,6 +108,21 @@ API(API_UART_WRITE, void epic_uart_write_str(const char *str, intptr_t length));
  */
 API(API_UART_READ, char epic_uart_read_chr(void));
 
+/**
+ * **Interrupt Service Routine**
+ *
+ * A user-defineable ISR which is triggered when a ``^C`` (``0x04``) is received
+ * on any serial input device.  This function is weakly aliased to
+ * :c:func:`epic_isr_default` by default.
+ *
+ * To enable this interrupt, you need to enable :c:data:`EPIC_INT_CTRL_C`:
+ *
+ * .. code-block:: cpp
+ *
+ *    epic_interrupt_enable(EPIC_INT_CTRL_C);
+ */
+API_ISR(EPIC_INT_CTRL_C, epic_isr_ctrl_c);
+
 /**
  * LEDs
  * ====
@@ -156,23 +219,4 @@ API(API_VIBRA_SET, void epic_vibra_set(int status));
  */
 API(API_VIBRA_VIBRATE, void epic_vibra_vibrate(int millis));
 
-/**
- * API interrupt type
- */
-typedef uint32_t api_int_id_t;
-
-/**
- * Enable/unmask an API interrupt
- *
- * :param int_id: The interrupt to be enabled
- */
-API(API_INTERRUPT_ENABLE, int epic_interrupt_enable(api_int_id_t int_id));
-
-/**
- * Disable/mask an API interrupt
- *
- * :param int_id: The interrupt to be disabled
- */
-API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id));
-
 #endif /* _EPICARDIUM_H */
diff --git a/epicardium/modules/serial.c b/epicardium/modules/serial.c
index bb9c325ce3933287307093d3e4caefc28ef3a0e8..bf341fe79f1d36242481c150e6dd56dfcae119c6 100644
--- a/epicardium/modules/serial.c
+++ b/epicardium/modules/serial.c
@@ -57,12 +57,12 @@ static void enqueue_char(char chr)
 {
 	if (chr == 0x3) {
 		/* Control-C */
-		api_interrupt_trigger(API_INT_CTRL_C);
+		api_interrupt_trigger(EPIC_INT_CTRL_C);
 	}
 
 	if (chr == 0x0e) {
 		/* Control-N */
-		api_interrupt_trigger(API_INT_BHI160);
+		api_interrupt_trigger(EPIC_INT_BHI160_TEST);
 	}
 
 	if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) {
diff --git a/pycardium/modules/interrupt.c b/pycardium/modules/interrupt.c
index b45680c723a8150fd440665065ff8170f8e3e6bc..510efa313f2299b36cf4b99214103094d348e224 100644
--- a/pycardium/modules/interrupt.c
+++ b/pycardium/modules/interrupt.c
@@ -6,15 +6,15 @@
 #include "mphalport.h"
 
 // TODO: these should be intialized as mp_const_none
-mp_obj_t callbacks[API_INT_MAX + 1] = {
+mp_obj_t callbacks[EPIC_INT_NUM] = {
 	0,
 };
 
-void api_interrupt_handler_catch_all(api_int_id_t id)
+void epic_isr_default_handler(api_int_id_t id)
 {
 	// TODO: check if id is out of rante
 	// TOOD: check against mp_const_none
-	if (id <= API_INT_MAX) {
+	if (id < EPIC_INT_NUM) {
 		if (callbacks[id]) {
 			mp_sched_schedule(
 				callbacks[id], MP_OBJ_NEW_SMALL_INT(id)
@@ -32,7 +32,7 @@ STATIC mp_obj_t mp_interrupt_set_callback(mp_obj_t id_in, mp_obj_t callback_obj)
 	}
 
 	// TODO: throw error if id is out of range
-	if (id <= API_INT_MAX) {
+	if (id < EPIC_INT_NUM) {
 		callbacks[id] = callback_obj;
 	}
 
diff --git a/pycardium/mphalport.c b/pycardium/mphalport.c
index 4ca84e13027f55c434ece35cf741447284498450..95d4bffa90089570d4e26ab5f098345b646c8dab 100644
--- a/pycardium/mphalport.c
+++ b/pycardium/mphalport.c
@@ -62,7 +62,7 @@ long _write(int fd, const char *buf, size_t cnt)
 	return cnt;
 }
 
-void api_interrupt_handler_ctrl_c(void)
+void epic_isr_ctrl_c(void)
 {
 	/* Taken from lib/micropython/micropython/lib/utils/interrupt_char.c */
 	MP_STATE_VM(mp_pending_exception) =
@@ -83,9 +83,9 @@ void mp_hal_set_interrupt_char(char c)
 	}
 
 	if (c == 0x03) {
-		epic_interrupt_enable(API_INT_CTRL_C);
+		epic_interrupt_enable(EPIC_INT_CTRL_C);
 	} else {
-		epic_interrupt_disable(API_INT_CTRL_C);
+		epic_interrupt_disable(EPIC_INT_CTRL_C);
 	}
 }