Spaces:
Sleeping
Sleeping
| openapi: 3.0.0 | |
| info: | |
| version: 1.0.0 | |
| title: Zulk API | |
| description: URL shortener API for Zulk platform | |
| servers: | |
| - url: https://api.zu.lk | |
| description: Production server | |
| - url: http://localhost:8787 | |
| description: Development server | |
| tags: | |
| - name: Authentication | |
| description: π OAuth endpoints for web app authentication (no API key required) | |
| - name: API v1 - Users | |
| description: π₯ User management endpoints (requires API key) | |
| - name: API v1 - Organizations | |
| description: π’ Organization management endpoints (requires API key) | |
| - name: API v1 - Links | |
| description: π URL shortening endpoints (requires API key) | |
| - name: API v1 - Analytics | |
| description: π Analytics and reporting endpoints (requires API key) | |
| components: | |
| securitySchemes: | |
| ApiKeyAuth: | |
| type: apiKey | |
| in: header | |
| name: X-API-KEY | |
| description: API Key for authentication | |
| ApiSecretAuth: | |
| type: apiKey | |
| in: header | |
| name: X-API-Secret | |
| description: API Secret for authentication | |
| schemas: | |
| Link: | |
| type: object | |
| properties: | |
| id: | |
| type: string | |
| example: "1" | |
| description: Link ID | |
| key: | |
| type: string | |
| example: abc123 | |
| description: Short link key | |
| url: | |
| type: string | |
| format: uri | |
| example: https://example.com | |
| description: Original URL | |
| created_at: | |
| type: string | |
| format: date-time | |
| example: 2025-01-01T00:00:00Z | |
| description: Creation timestamp | |
| owner: | |
| type: string | |
| example: org123 | |
| description: Organization ID that owns this link | |
| CreateLink: | |
| type: object | |
| required: | |
| - url | |
| properties: | |
| key: | |
| type: string | |
| example: custom-key | |
| description: Custom short key (optional) | |
| url: | |
| type: string | |
| format: uri | |
| example: https://example.com | |
| description: URL to shorten | |
| length: | |
| type: integer | |
| minimum: 3 | |
| maximum: 10 | |
| example: 6 | |
| description: "Length of generated key (3-10, default: 6)" | |
| CreateLinkResponse: | |
| type: object | |
| properties: | |
| message: | |
| type: string | |
| example: Record added successfully | |
| created_at: | |
| type: string | |
| format: date-time | |
| example: 2025-01-01T00:00:00Z | |
| shortLink: | |
| type: string | |
| example: https://zu.lk/abc123 | |
| key: | |
| type: string | |
| example: abc123 | |
| url: | |
| type: string | |
| format: uri | |
| example: https://example.com | |
| length: | |
| type: integer | |
| example: 6 | |
| Error: | |
| type: object | |
| properties: | |
| error: | |
| type: string | |
| example: Error message | |
| description: Error message | |
| User: | |
| type: object | |
| properties: | |
| id: | |
| type: string | |
| example: "123" | |
| description: User ID | |
| name: | |
| type: string | |
| example: John Doe | |
| description: User name | |
| age: | |
| type: integer | |
| example: 42 | |
| description: User age | |
| AuthUser: | |
| type: object | |
| properties: | |
| email: | |
| type: string | |
| format: email | |
| example: user@example.com | |
| description: User email (lowercased) | |
| user: | |
| type: object | |
| properties: | |
| id: | |
| type: string | |
| example: "123456789" | |
| description: Google user ID | |
| name: | |
| type: string | |
| example: John Doe | |
| description: User display name | |
| email: | |
| type: string | |
| format: email | |
| example: user@example.com | |
| description: User email from Google | |
| picture: | |
| type: string | |
| format: uri | |
| example: https://lh3.googleusercontent.com/... | |
| description: User profile picture URL | |
| description: Google OAuth user data | |
| token: | |
| type: string | |
| example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | |
| description: JWT token | |
| apiKey: | |
| type: string | |
| example: ak_1234567890abcdef | |
| description: User API key | |
| apiToken: | |
| type: string | |
| example: at_1234567890abcdef | |
| description: User API token | |
| Organization: | |
| type: object | |
| properties: | |
| id: | |
| type: number | |
| example: 1 | |
| description: Organization ID | |
| name: | |
| type: string | |
| example: Acme Corp | |
| description: Organization name | |
| role: | |
| type: string | |
| example: OWNER | |
| description: User role in the organization | |
| OrganizationMember: | |
| type: object | |
| properties: | |
| id: | |
| type: number | |
| example: 123 | |
| description: User ID | |
| name: | |
| type: string | |
| example: John Doe | |
| description: User name | |
| email: | |
| type: string | |
| format: email | |
| example: john@example.com | |
| description: User email | |
| role: | |
| type: string | |
| enum: | |
| - MANAGER | |
| - ADMIN | |
| - OWNER | |
| example: MANAGER | |
| description: User role in the organization | |
| AddMemberRequest: | |
| type: object | |
| required: | |
| properties: | |
| email: | |
| type: string | |
| format: email | |
| example: newmember@example.com | |
| description: Email of the user to add | |
| role: | |
| type: string | |
| enum: | |
| - MANAGER | |
| - ADMIN | |
| - OWNER | |
| example: MANAGER | |
| default: MANAGER | |
| description: Role to assign to the new member | |
| UpdateRoleRequest: | |
| type: object | |
| required: | |
| - role | |
| properties: | |
| role: | |
| type: string | |
| enum: | |
| - MANAGER | |
| - ADMIN | |
| - OWNER | |
| example: ADMIN | |
| description: New role for the member | |
| AnalyticsResponse: | |
| type: object | |
| properties: | |
| orgId: | |
| type: string | |
| example: "1" | |
| description: Organization ID | |
| analytics: | |
| type: object | |
| properties: | |
| totalClicks: | |
| type: number | |
| example: 1250 | |
| description: Total click count | |
| dateRange: | |
| type: object | |
| properties: | |
| from: | |
| type: string | |
| example: -7d | |
| description: Start date of the range | |
| to: | |
| type: string | |
| example: today | |
| description: End date of the range | |
| interval: | |
| type: string | |
| example: day | |
| description: Data interval | |
| data: | |
| type: array | |
| items: | |
| type: number | |
| example: | |
| - 120 | |
| - 150 | |
| - 89 | |
| - 200 | |
| - 180 | |
| - 145 | |
| - 220 | |
| description: Click data points | |
| labels: | |
| type: array | |
| items: | |
| type: string | |
| example: | |
| - 2025-08-09 | |
| - 2025-08-10 | |
| - 2025-08-11 | |
| - 2025-08-12 | |
| - 2025-08-13 | |
| - 2025-08-14 | |
| - 2025-08-15 | |
| description: Date labels for data points | |
| generatedAt: | |
| type: string | |
| format: date-time | |
| example: 2025-08-15T12:00:00Z | |
| description: Timestamp when analytics were generated | |
| UpdateLinkRequest: | |
| type: object | |
| required: | |
| - url | |
| - key | |
| properties: | |
| url: | |
| type: string | |
| format: uri | |
| example: https://updated-example.com | |
| description: Updated URL | |
| key: | |
| type: string | |
| example: updated-key | |
| description: Updated short key | |
| CreateOrganization: | |
| type: object | |
| required: | |
| - name | |
| properties: | |
| name: | |
| type: string | |
| example: Acme Corp | |
| description: Organization name | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| paths: | |
| /v1/organizations: | |
| get: | |
| summary: Get user organizations | |
| description: Retrieve organizations that the authenticated user has access to | |
| tags: | |
| - API v1 - Organizations | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| responses: | |
| "200": | |
| description: Successfully retrieved user organizations | |
| content: | |
| application/json: | |
| schema: | |
| type: array | |
| items: | |
| $ref: "#/components/schemas/Organization" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| post: | |
| summary: Create a new organization | |
| description: Create a new organization and assign the authenticated user as owner | |
| tags: | |
| - API v1 - Organizations | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/CreateOrganization" | |
| responses: | |
| "200": | |
| description: Successfully created organization | |
| content: | |
| application/json: | |
| schema: | |
| type: object | |
| properties: | |
| message: | |
| type: string | |
| example: Organization created successfully | |
| id: | |
| type: number | |
| example: 1 | |
| description: Organization ID | |
| name: | |
| type: string | |
| example: Acme Corp | |
| description: Organization name | |
| role: | |
| type: string | |
| example: OWNER | |
| description: User role in the organization | |
| "400": | |
| description: Bad request - Name is required | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "500": | |
| description: Internal server error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| /v1/organizations/{orgId}/members: | |
| get: | |
| summary: Get organization members | |
| description: Retrieve all members of a specific organization | |
| tags: | |
| - API v1 - Organizations | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| responses: | |
| "200": | |
| description: Successfully retrieved organization members | |
| content: | |
| application/json: | |
| schema: | |
| type: object | |
| properties: | |
| members: | |
| type: array | |
| items: | |
| $ref: "#/components/schemas/OrganizationMember" | |
| total: | |
| type: number | |
| example: 5 | |
| description: Total number of members | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied to this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| post: | |
| summary: Add member to organization | |
| description: Add a new member to an organization (requires ADMIN or OWNER role) | |
| tags: | |
| - API v1 - Organizations | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/AddMemberRequest" | |
| responses: | |
| "200": | |
| description: Successfully added member to organization | |
| content: | |
| application/json: | |
| schema: | |
| type: object | |
| properties: | |
| message: | |
| type: string | |
| example: Member added successfully | |
| member: | |
| $ref: "#/components/schemas/OrganizationMember" | |
| "400": | |
| description: Bad request - Email is required or invalid role | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied - Requires ADMIN or OWNER role | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "404": | |
| description: User not found - User must register first | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| example: | |
| error: User not found. User must register first. | |
| "409": | |
| description: Conflict - User is already a member | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "500": | |
| description: Internal server error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| /v1/organizations/{orgId}/members/{memberId}/role: | |
| patch: | |
| summary: Update member role | |
| description: Update the role of a specific member in an organization (requires | |
| ADMIN or OWNER role) | |
| tags: | |
| - API v1 - Organizations | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| - name: memberId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Member ID | |
| example: "123" | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/UpdateRoleRequest" | |
| responses: | |
| "200": | |
| description: Successfully updated member role | |
| content: | |
| application/json: | |
| schema: | |
| type: object | |
| properties: | |
| message: | |
| type: string | |
| example: Member role updated successfully | |
| member: | |
| type: object | |
| properties: | |
| id: | |
| type: number | |
| example: 123 | |
| name: | |
| type: string | |
| example: John Doe | |
| email: | |
| type: string | |
| example: john@example.com | |
| role: | |
| type: string | |
| example: ADMIN | |
| previousRole: | |
| type: string | |
| example: MANAGER | |
| "400": | |
| description: Bad request - Role is required or invalid | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied - Requires ADMIN or OWNER role, or cannot change own | |
| role | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "404": | |
| description: Member not found in this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| example: | |
| error: Member not found in this organization | |
| "500": | |
| description: Internal server error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| /v1/organizations/{orgId}/members/{memberId}: | |
| delete: | |
| summary: Remove member from organization | |
| description: Remove a member from an organization (requires ADMIN or OWNER | |
| role). Cannot remove yourself or the current OWNER. | |
| tags: | |
| - API v1 - Organizations | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| - name: memberId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Member ID | |
| example: "123" | |
| responses: | |
| "200": | |
| description: Successfully removed member from organization | |
| content: | |
| application/json: | |
| schema: | |
| type: object | |
| properties: | |
| message: | |
| type: string | |
| example: Member removed successfully | |
| removedMember: | |
| $ref: "#/components/schemas/OrganizationMember" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied - Requires ADMIN or OWNER role, cannot remove | |
| yourself, or cannot remove last OWNER | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "404": | |
| description: Member not found in this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| example: | |
| error: Member not found in this organization | |
| "500": | |
| description: Internal server error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| /v1/organizations/{orgId}/analytics/clicks: | |
| get: | |
| summary: Get organization click analytics | |
| description: Retrieve click analytics data for an organization's links from PostHog | |
| tags: | |
| - API v1 - Analytics | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| - name: date_from | |
| in: query | |
| required: false | |
| schema: | |
| type: string | |
| description: "Start date for analytics (default: -7d)" | |
| example: -7d | |
| - name: date_to | |
| in: query | |
| required: false | |
| schema: | |
| type: string | |
| description: "End date for analytics (default: today)" | |
| example: today | |
| - name: interval | |
| in: query | |
| required: false | |
| schema: | |
| type: string | |
| description: "Data interval (default: day)" | |
| example: day | |
| responses: | |
| "200": | |
| description: Successfully retrieved analytics data | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/AnalyticsResponse" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied to this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "500": | |
| description: Internal server error - Failed to fetch analytics data | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| /v1/organizations/{orgId}/links: | |
| get: | |
| summary: Get organization links | |
| description: Retrieve all links for a specific organization | |
| tags: | |
| - API v1 - Links | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| responses: | |
| "200": | |
| description: Successfully retrieved organization links | |
| content: | |
| application/json: | |
| schema: | |
| type: array | |
| items: | |
| $ref: "#/components/schemas/Link" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied to this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| post: | |
| summary: Create a new link in organization | |
| description: Create a new short link for the given URL in the specified organization | |
| tags: | |
| - API v1 - Links | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/CreateLink" | |
| responses: | |
| "200": | |
| description: Successfully created short link | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/CreateLinkResponse" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied to this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "500": | |
| description: Internal server error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| /v1/organizations/{orgId}/links/{id}: | |
| get: | |
| summary: Get a specific link from organization | |
| description: Retrieve a specific link by ID from the specified organization | |
| tags: | |
| - API v1 - Links | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| - name: id | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Link ID | |
| example: "1" | |
| responses: | |
| "200": | |
| description: Successfully retrieved link | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Link" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied to this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "404": | |
| description: Link not found | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| example: | |
| error: Link not found | |
| /v1/organizations/{orgId}/links/{linkId}: | |
| put: | |
| summary: Update a link in organization | |
| description: Update an existing short link for the specified organization | |
| tags: | |
| - API v1 - Links | |
| security: | |
| - ApiKeyAuth: [] | |
| ApiSecretAuth: [] | |
| parameters: | |
| - name: orgId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Organization ID | |
| example: "1" | |
| - name: linkId | |
| in: path | |
| required: true | |
| schema: | |
| type: string | |
| description: Link ID | |
| example: "1" | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/UpdateLinkRequest" | |
| responses: | |
| "200": | |
| description: Successfully updated link | |
| content: | |
| application/json: | |
| schema: | |
| type: object | |
| properties: | |
| message: | |
| type: string | |
| example: Link updated successfully | |
| id: | |
| type: string | |
| example: "1" | |
| description: Link ID | |
| key: | |
| type: string | |
| example: updated-key | |
| description: Updated short key | |
| url: | |
| type: string | |
| format: uri | |
| example: https://updated-example.com | |
| description: Updated URL | |
| shortLink: | |
| type: string | |
| example: https://zu.lk/updated-key | |
| description: Full short link URL | |
| updated_at: | |
| type: string | |
| format: date-time | |
| example: 2025-08-15T12:00:00Z | |
| description: Update timestamp | |
| previousKey: | |
| type: string | |
| example: old-key | |
| description: Previous short key | |
| "400": | |
| description: Bad request - URL and key are required | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "401": | |
| description: Unauthorized - Invalid API credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "403": | |
| description: Access denied to this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "404": | |
| description: Link not found in this organization | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| example: | |
| error: Link not found in this organization | |
| "409": | |
| description: Conflict - Key is already taken | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |
| "500": | |
| description: Internal server error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/Error" | |