EAS-202310715274-DimasHendr.../N8N_WEBHOOK_GUIDE.md
2026-01-14 21:13:18 +07:00

9.2 KiB

🌐 N8n Webhook Integration Guide

Endpoint Configuration

Production Endpoint

URL: https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254
Method: POST
Content-Type: application/json

Testing Endpoint

URL: https://n8n.lab.ubharajaya.ac.id/webhook-test/23c6993d-1792-48fb-ad1c-ffc78a3e6254
Method: POST
Content-Type: application/json

Switch Configuration

File: config/AppConfig.kt

// Production (default)
const val USE_WEBHOOK = N8N_WEBHOOK_PROD

// Switch ke testing
const val USE_WEBHOOK = N8N_WEBHOOK_TEST

Request Format

JSON Payload Example

{
  "npm": "12345678",
  "nama": "John Doe",
  "latitude": -6.896123,
  "longitude": 107.610056,
  "timestamp": 1704067200000,
  "foto_base64": "iVBORw0KGgoAAAANSUhEUgAAA...ABJRU5ErkJggg=="
}

Field Descriptions

Field Type Example Notes
npm String "12345678" Nomor Pokok Mahasiswa
nama String "John Doe" Nama lengkap mahasiswa
latitude Number -6.896123 Koordinat latitude (format: 6 desimal)
longitude Number 107.610056 Koordinat longitude (format: 6 desimal)
timestamp Number 1704067200000 Unix timestamp dalam milliseconds
foto_base64 String "iVBORw0K..." Foto compressed JPEG dalam Base64

Response Handling

Success Response (HTTP 200/201)

{
  "success": true,
  "message": "Attendance recorded successfully",
  "data": {
    "id": "65a7b8c9d0e1f2g3h4i5j6k7",
    "npm": "12345678",
    "nama": "John Doe",
    "timestamp": 1704067200000,
    "status": "accepted"
  }
}

App Behavior:

  • Status badge: ACCEPTED (green)
  • Message: "✓ Absensi berhasil dikirim!"
  • Database: Save with status = "accepted"

Error Response (HTTP 400+)

{
  "error": true,
  "message": "Location outside of allowed area",
  "code": "LOCATION_INVALID"
}

App Behavior:

  • Status badge: ✗ REJECTED (red)
  • Message: "✗ Gagal: Server returned code: 400"
  • Database: Save with status = "rejected"

Server Timeout (no response)

App Behavior:

  • After 10 seconds: Show error
  • Message: "✗ Gagal: timeout"
  • Database: Save with status = "rejected"

Real-World Examples

Example 1: Valid Attendance

Request:

curl -X POST https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254 \
  -H "Content-Type: application/json" \
  -d '{
    "npm": "12345678",
    "nama": "Arif Rachman Dwi",
    "latitude": -6.8961,
    "longitude": 107.6100,
    "timestamp": 1704067200000,
    "foto_base64": "[COMPRESSED_JPEG_BASE64]"
  }'

Response (Success):

HTTP/1.1 200 OK
{
  "success": true,
  "message": "Attendance recorded",
  "status": "accepted"
}

Example 2: Location Out of Area

Request:

curl -X POST https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254 \
  -H "Content-Type: application/json" \
  -d '{
    "npm": "12345678",
    "nama": "Arif Rachman Dwi",
    "latitude": -6.8, 
    "longitude": 107.5,
    "timestamp": 1704067200000,
    "foto_base64": "[COMPRESSED_JPEG_BASE64]"
  }'

Response (Out of Radius):

HTTP/1.1 400 Bad Request
{
  "error": true,
  "message": "Location is outside of allowed area",
  "code": "LOCATION_INVALID",
  "distance": 12500
}

Image Compression Details

Photo Processing in App

  1. Capture: Camera Intent mengambil JPEG thumbnail
  2. Compress: Bitmap compressed dengan quality 80%
  3. Encode: JPEG bytes di-encode ke Base64
  4. Size: Typical size ~50-100 KB (Base64 ~70-130 KB)

Configuration

File: config/AppConfig.kt

const val PHOTO_COMPRESS_QUALITY = 80  // Range: 0-100

Compression Quality Reference

Quality Use Case
50 Minimal quality, smallest size
80 Balanced (DEFAULT)
100 Maximum quality, largest size

N8n Workflow Integration

Expected Workflow Steps

  1. Webhook Trigger

    • Menerima POST request dengan JSON payload
    • Validasi format & required fields
  2. Data Validation

    • Check NPM format
    • Validate coordinates (lat/lon ranges)
    • Validate timestamp (not in future)
    • Check foto_base64 format
  3. Location Validation

    • Calculate distance from campus center
    • Check if within allowed radius
    • Return error if out of bounds
  4. Photo Processing

    • Decode Base64 image
    • Optional: Save to storage
    • Optional: Run face detection
    • Optional: Save metadata
  5. Database Storage

    • Insert into attendance table
    • Record timestamp & location
    • Update student statistics
  6. Response

    • Return HTTP 200 + success message
    • Or HTTP 400 + error message

Sample N8n Workflow JSON

See n8n-workflow-EAS.json in project root for complete workflow configuration.


Monitoring & Testing

Monitoring URL

https://ntfy.ubharajaya.ac.id/EAS

Monitor real-time webhook notifications:

  • New attendance submissions
  • Errors & rejections
  • System alerts

Spreadsheet Tracking

https://docs.google.com/spreadsheets/d/1jH15MfnNgpPGuGeid0hYfY7fFUHCEFbCmg8afTyyLZs/

Track all recorded attendance data:

  • Student information
  • Location & timestamp
  • Photo references
  • Status & notes

Testing Endpoint

https://n8n.lab.ubharajaya.ac.id/webhook-test/23c6993d-1792-48fb-ad1c-ffc78a3e6254

Use for testing before production:

  • Simulates webhook behavior
  • Doesn't actually save to production database
  • Useful for app development & testing

Implementation Code Reference

Sending Request (AttendanceRepository.kt)

fun sendToN8n(
    onSuccess: () -> Unit,
    onError: (String) -> Unit,
    attendance: Attendance,
    foto: Bitmap
) {
    thread {
        try {
            val url = URL(AppConfig.USE_WEBHOOK)
            val conn = url.openConnection() as HttpURLConnection
            
            conn.requestMethod = "POST"
            conn.setRequestProperty("Content-Type", "application/json")
            conn.doOutput = true
            conn.connectTimeout = 10000
            conn.readTimeout = 10000
            
            // Create JSON payload
            val json = JSONObject().apply {
                put("npm", attendance.npm)
                put("nama", attendance.nama)
                put("latitude", attendance.latitude)
                put("longitude", attendance.longitude)
                put("timestamp", attendance.timestamp)
                put("foto_base64", bitmapToBase64(foto))
            }
            
            // Send request
            conn.outputStream.use {
                it.write(json.toString().toByteArray())
                it.flush()
            }
            
            // Handle response
            val responseCode = conn.responseCode
            if (responseCode == 200 || responseCode == 201) {
                onSuccess()
            } else {
                onError("Server returned code: $responseCode")
            }
            
            conn.disconnect()
        } catch (e: Exception) {
            onError(e.message ?: "Unknown error")
        }
    }
}

Troubleshooting

1. Connection Timeout

Error: "✗ Gagal: timeout"
Solution:
- Check internet connection
- Verify URL is correct
- Test network connectivity
- Increase timeout if needed

2. Invalid JSON Response

Error: "✗ Gagal: JSON parsing error"
Solution:
- Verify payload format
- Check all required fields present
- Validate Base64 string
- Check JSON syntax

3. 400 Bad Request

Error: "✗ Gagal: Server returned code: 400"
Possible causes:
- Invalid NPM format
- Coordinates out of valid range
- Missing required fields
- Malformed Base64 image

4. 401 Unauthorized

Error: "✗ Gagal: Server returned code: 401"
Solution:
- Check webhook URL is correct
- Verify webhook is active in N8n
- Check authentication headers if required

5. 403 Forbidden

Error: "✗ Gagal: Server returned code: 403"
Solution:
- Verify webhook permissions
- Check if webhook is enabled
- Verify IP whitelist settings

6. 500 Server Error

Error: "✗ Gagal: Server returned code: 500"
Solution:
- Check N8n workflow logs
- Verify database connection
- Check N8n service status
- Contact system administrator

Security Considerations

Data Protection

  • All data sent over HTTPS
  • No sensitive data stored in logs
  • Base64 photo cannot be directly viewed
  • Timestamp validation prevents replay attacks

Rate Limiting

  • Consider implementing rate limiting on N8n
  • Prevent duplicate submissions
  • Monitor for unusual activity

Validation

  • Server should validate all inputs
  • Reject invalid coordinates
  • Verify photo file integrity
  • Check timestamp within reasonable window

API Contract

Version Information

API Version: v1
Last Updated: 2025-01-14
Endpoint Status: Active

Backward Compatibility

  • Current version: 1.0
  • No breaking changes planned
  • All fields are required
  • Response format is stable

Future Enhancements

  • Support for batch submissions
  • Webhook signature verification
  • Custom error codes
  • Rate limiting headers
  • API versioning in URL

Document Version: 1.0
Last Updated: 2025-01-14
Status: Complete & Current