---
title: "Api Integration"
description: "Api Integration documentation for Ring Platform"
locale: "ru"
---
# API Integration Examples

Complete examples for integrating with Ring Platform's 77 API endpoints across 9 domains.

## 🔌 API Client Setup

### Base API Client

// lib/api-client.ts

{`import { auth } from '@/auth'

class RingAPIClient {
  private baseURL = process.env.NEXT_PUBLIC_API_URL || 'https://ring.ck.ua/api'

  private async getAuthHeaders() {
    const session = await auth()
    return {
      'Content-Type': 'application/json',
      'Authorization': session?.accessToken ? `Bearer ${session.accessToken}` : '',
    }
  }

  async request(endpoint: string, options: RequestInit = {}): Promise {
    const headers = await this.getAuthHeaders()
    
    const response = await fetch(`${this.baseURL}${endpoint}`, {
      ...options,
      headers: {
        ...headers,
        ...options.headers,
      },
    })

    if (!response.ok) {
      throw new Error(`API Error: ${response.status} ${response.statusText}`)
    }

    return response.json()
  }

  // Entity operations
  async getEntities(params?: { type?: string; limit?: number }) {
    const searchParams = new URLSearchParams(params as Record<string, string>)
    return this.request<{ entities: Entity[] }>(`/entities?${searchParams}`)
  }

  async createEntity(data: CreateEntityData) {
    return this.request('/entities', {
      method: 'POST',
      body: JSON.stringify(data),
    })
  }

  async updateEntity(id: string, data: Partial) {
    return this.request(`/entities/${id}`, {
      method: 'PUT',
      body: JSON.stringify(data),
    })
  }

  async deleteEntity(id: string) {
    return this.request<{ success: boolean }>(`/entities/${id}`, {
      method: 'DELETE',
    })
  }

  // Opportunity operations
  async getOpportunities(params?: { type?: string; entityId?: string }) {
    const searchParams = new URLSearchParams(params as Record<string, string>)
    return this.request<{ opportunities: Opportunity[] }>(`/opportunities?${searchParams}`)
  }

  async createOpportunity(data: CreateOpportunityData) {
    return this.request('/opportunities', {
      method: 'POST',
      body: JSON.stringify(data),
    })
  }

  // Messaging operations
  async getConversations() {
    return this.request<{ conversations: Conversation[] }>('/messaging/conversations')
  }

  async sendMessage(conversationId: string, content: string) {
    return this.request(`/messaging/conversations/${conversationId}/messages`, {
      method: 'POST',
      body: JSON.stringify({ content }),
    })
  }
}

export const apiClient = new RingAPIClient()`}

## 🏢 Entity Management

### Entity CRUD Operations

// components/EntityManager.tsx

{`'use client'

import { useState, useEffect } from 'react'
import { apiClient } from '@/lib/api-client'

interface Entity {
  id: string
  name: string
  type: string
  description: string
  logo?: string
  verified: boolean
  createdAt: string
}

export function EntityManager() {
  const [entities, setEntities] = useState<Entity[]>([])
  const [loading, setLoading] = useState(true)
  const [creating, setCreating] = useState(false)

  const [newEntity, setNewEntity] = useState({
    name: '',
    type: 'technology',
    description: '',
  })

  useEffect(() => {
    loadEntities()
  }, [])

  const loadEntities = async () => {
    try {
      const response = await apiClient.getEntities()
      setEntities(response.entities)
    } catch (error) {
      console.error('Failed to load entities:', error)
    } finally {
      setLoading(false)
    }
  }

  const handleCreateEntity = async (e: React.FormEvent) => {
    e.preventDefault()
    setCreating(true)

    try {
      const entity = await apiClient.createEntity(newEntity)
      setEntities([...entities, entity])
      setNewEntity({ name: '', type: 'technology', description: '' })
    } catch (error) {
      console.error('Failed to create entity:', error)
    } finally {
      setCreating(false)
    }
  }

  const handleDeleteEntity = async (id: string) => {
    if (!confirm('Are you sure you want to delete this entity?')) return

    try {
      await apiClient.deleteEntity(id)
      setEntities(entities.filter(e => e.id !== id))
    } catch (error) {
      console.error('Failed to delete entity:', error)
    }
  }

  if (loading) {
    return Loading entities...
  }

  return (
    
      Entity Management

      {/* Create Entity Form */}
      
        Create New Entity
        
           setNewEntity({ ...newEntity, name: e.target.value })}
            className="p-2 border rounded"
            required
          />
           setNewEntity({ ...newEntity, type: e.target.value })}
            className="p-2 border rounded"
          >
            Technology
            Healthcare
            Finance
            Education
            Retail
          
          
            {creating ? 'Creating...' : 'Create Entity'}
          
        
         setNewEntity({ ...newEntity, description: e.target.value })}
          className="w-full p-2 border rounded mt-2"
          rows={3}
        />
      

      {/* Entity List */}
      
        {entities.map((entity) => (
          
            
              {entity.name}
              {entity.verified && (
                
                  Verified
                
              )}
            
            {entity.type}
            {entity.description}
            
              
                Created: {new Date(entity.createdAt).toLocaleDateString()}
              
               handleDeleteEntity(entity.id)}
                className="text-red-600 hover:text-red-800 text-sm"
              >
                Delete
              
            
          
        ))}
      
    
  )
}`}

## 💼 Opportunity Management

### Opportunity Marketplace

// components/OpportunityBoard.tsx

{`'use client'

import { useState, useEffect } from 'react'
import { apiClient } from '@/lib/api-client'

interface Opportunity {
  id: string
  title: string
  type: 'job' | 'partnership' | 'volunteer' | 'mentorship' | 'resource' | 'event'
  nature: 'offer' | 'request'
  description: string
  entityId: string
  entityName: string
  deadline?: string
  confidential: boolean
  applicationsCount: number
}

export function OpportunityBoard() {
  const [opportunities, setOpportunities] = useState<Opportunity[]>([])
  const [filter, setFilter] = useState<{
    type?: string
    nature?: string
  }>({})
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    loadOpportunities()
  }, [filter])

  const loadOpportunities = async () => {
    try {
      const response = await apiClient.getOpportunities(filter)
      setOpportunities(response.opportunities)
    } catch (error) {
      console.error('Failed to load opportunities:', error)
    } finally {
      setLoading(false)
    }
  }

  const getTypeIcon = (type: string) => {
    const icons = {
      job: '💼',
      partnership: '🤝',
      volunteer: '🙋',
      mentorship: '👨‍🏫',
      resource: '📦',
      event: '📅'
    }
    return icons[type as keyof typeof icons] || '📋'
  }

  const getNatureColor = (nature: string) => {
    return nature === 'offer' 
      ? 'bg-green-100 text-green-800' 
      : 'bg-blue-100 text-blue-800'
  }

  if (loading) {
    return Loading opportunities...
  }

  return (
    
      
        Opportunity Board
        
        {/* Filters */}
        
           setFilter({ ...filter, type: e.target.value || undefined })}
            className="p-2 border rounded"
          >
            All Types
            Jobs
            Partnerships
            Volunteer
            Mentorship
            Resources
            Events
          
          
           setFilter({ ...filter, nature: e.target.value || undefined })}
            className="p-2 border rounded"
          >
            All
            Offers
            Requests
          
        
      

      
        {opportunities.map((opportunity) => (
          
            
              
                {getTypeIcon(opportunity.type)}
                
                  {opportunity.title}
                  {opportunity.entityName}
                
              
              
                
                  {opportunity.nature}
                
                {opportunity.confidential && (
                  
                    Confidential
                  
                )}
              
            

            
              {opportunity.description}
            

            
              {opportunity.applicationsCount} applications
              {opportunity.deadline && (
                Due: {new Date(opportunity.deadline).toLocaleDateString()}
              )}
            

            
              {opportunity.nature === 'offer' ? 'Apply' : 'Respond'}
            
          
        ))}
      

      {opportunities.length === 0 && (
        
          No opportunities found matching your filters.
        
      )}
    
  )
}`}

## 💬 Real-time Messaging

### Message Integration

// components/MessageCenter.tsx

{`'use client'

import { useState, useEffect, useRef } from 'react'
import { apiClient } from '@/lib/api-client'

interface Message {
  id: string
  content: string
  senderId: string
  senderName: string
  timestamp: string
  read: boolean
}

interface Conversation {
  id: string
  participants: string[]
  lastMessage?: Message
  unreadCount: number
}

export function MessageCenter() {
  const [conversations, setConversations] = useState<Conversation[]>([])
  const [activeConversation, setActiveConversation] = useState(null)
  const [messages, setMessages] = useState<Message[]>([])
  const [newMessage, setNewMessage] = useState('')
  const [loading, setLoading] = useState(true)
  const messagesEndRef = useRef(null)

  useEffect(() => {
    loadConversations()
  }, [])

  useEffect(() => {
    if (activeConversation) {
      loadMessages(activeConversation)
    }
  }, [activeConversation])

  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
  }, [messages])

  const loadConversations = async () => {
    try {
      const response = await apiClient.getConversations()
      setConversations(response.conversations)
    } catch (error) {
      console.error('Failed to load conversations:', error)
    } finally {
      setLoading(false)
    }
  }

  const loadMessages = async (conversationId: string) => {
    try {
      const response = await fetch(`/api/messaging/conversations/${conversationId}/messages`)
      const data = await response.json()
      setMessages(data.messages || [])
    } catch (error) {
      console.error('Failed to load messages:', error)
    }
  }

  const sendMessage = async (e: React.FormEvent) => {
    e.preventDefault()
    if (!newMessage.trim() || !activeConversation) return

    try {
      const message = await apiClient.sendMessage(activeConversation, newMessage)
      setMessages([...messages, message])
      setNewMessage('')
    } catch (error) {
      console.error('Failed to send message:', error)
    }
  }

  if (loading) {
    return Loading conversations...
  }

  return (
    
      {/* Conversations List */}
      
        
          Conversations
        
        
          {conversations.map((conversation) => (
             setActiveConversation(conversation.id)}
              className={`p-4 border-b cursor-pointer hover:bg-gray-100 ${
                activeConversation === conversation.id ? 'bg-blue-50' : ''
              }`}
            >
              
                
                  
                    {conversation.participants.join(', ')}
                  
                  {conversation.lastMessage && (
                    
                      {conversation.lastMessage.content}
                    
                  )}
                
                {conversation.unreadCount > 0 && (
                  
                    {conversation.unreadCount}
                  
                )}
              
            
          ))}
        
      

      {/* Messages */}
      
        {activeConversation ? (
          <>
            
              {messages.map((message) => (
                
                  
                    
                      {message.senderName.charAt(0)}
                    
                    
                      
                        {message.senderName}
                        
                          {new Date(message.timestamp).toLocaleTimeString()}
                        
                      
                      
                        {message.content}
                      
                    
                  
                
              ))}
              
            

            
              
                 setNewMessage(e.target.value)}
                  placeholder="Type a message..."
                  className="flex-1 p-2 border rounded-lg"
                />
                
                  Send
                
              
            
          </>
        ) : (
          
            Select a conversation to start messaging
          
        )}
      
    
  )
}`}

## 🔔 Notification System

### Notification Management

// components/NotificationCenter.tsx

{`'use client'

import { useState, useEffect } from 'react'

interface Notification {
  id: string
  title: string
  message: string
  type: 'info' | 'success' | 'warning' | 'error'
  read: boolean
  createdAt: string
  actionUrl?: string
}

export function NotificationCenter() {
  const [notifications, setNotifications] = useState<Notification[]>([])
  const [unreadCount, setUnreadCount] = useState(0)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    loadNotifications()
    
    // Set up real-time notifications
    const eventSource = new EventSource('/api/notifications/stream')
    
    eventSource.onmessage = (event) => {
      const notification = JSON.parse(event.data)
      setNotifications(prev => [notification, ...prev])
      setUnreadCount(prev => prev + 1)
    }

    return () => eventSource.close()
  }, [])

  const loadNotifications = async () => {
    try {
      const response = await fetch('/api/notifications')
      const data = await response.json()
      setNotifications(data.notifications || [])
      setUnreadCount(data.unreadCount || 0)
    } catch (error) {
      console.error('Failed to load notifications:', error)
    } finally {
      setLoading(false)
    }
  }

  const markAsRead = async (id: string) => {
    try {
      await fetch(`/api/notifications/${id}/read`, { method: 'POST' })
      setNotifications(prev => 
        prev.map(n => n.id === id ? { ...n, read: true } : n)
      )
      setUnreadCount(prev => Math.max(0, prev - 1))
    } catch (error) {
      console.error('Failed to mark notification as read:', error)
    }
  }

  const getTypeIcon = (type: string) => {
    const icons = {
      info: 'ℹ️',
      success: '✅',
      warning: '⚠️',
      error: '❌'
    }
    return icons[type as keyof typeof icons] || 'ℹ️'
  }

  const getTypeColor = (type: string) => {
    const colors = {
      info: 'border-blue-200 bg-blue-50',
      success: 'border-green-200 bg-green-50',
      warning: 'border-yellow-200 bg-yellow-50',
      error: 'border-red-200 bg-red-50'
    }
    return colors[type as keyof typeof colors] || 'border-gray-200 bg-gray-50'
  }

  if (loading) {
    return Loading notifications...
  }

  return (
    
      
        Notifications
        {unreadCount > 0 && (
          
            {unreadCount} unread
          
        )}
      

      
        {notifications.map((notification) => (
          
            
              {getTypeIcon(notification.type)}
              
                
                  {notification.title}
                  
                    {new Date(notification.createdAt).toLocaleString()}
                  
                
                {notification.message}
                
                  {notification.actionUrl && (
                    
                      View Details →
                    
                  )}
                  {!notification.read && (
                     markAsRead(notification.id)}
                      className="text-blue-600 hover:text-blue-800 text-sm"
                    >
                      Mark as read
                    
                  )}
                
              
            
          
        ))}
      

      {notifications.length === 0 && (
        
          No notifications yet.
        
      )}
    
  )
}`}

## 🎯 Error Handling

### API Error Handler

// lib/api-error-handler.ts

{`export class APIError extends Error {
  constructor(
    public status: number,
    public statusText: string,
    public data?: any
  ) {
    super(`API Error: ${status} ${statusText}`)
  }
}

export async function handleAPIResponse(response: Response): Promise {
  if (!response.ok) {
    const errorData = await response.json().catch(() => null)
    throw new APIError(response.status, response.statusText, errorData)
  }
  
  return response.json()
}

// Usage in components
export function useAPIErrorHandler() {
  const handleError = (error: unknown) => {
    if (error instanceof APIError) {
      switch (error.status) {
        case 401:
          // Redirect to login
          window.location.href = '/login'
          break
        case 403:
          // Show permission error
          alert('You do not have permission to perform this action')
          break
        case 429:
          // Rate limit exceeded
          alert('Too many requests. Please try again later.')
          break
        default:
          alert(`Error: ${error.message}`)
      }
    } else {
      console.error('Unexpected error:', error)
      alert('An unexpected error occurred')
    }
  }

  return { handleError }
}`}

---

*Ready for more advanced integrations? Check out [Web3 Integration](/ru/docs/examples/web3-integration) or [Real World Apps](/ru/docs/examples/real-world).*
