Before using the Stringee Call API for the first time, you must have a Stringee account. If you do not have a Stringee account, sign up for free here: https://developer.stringee.com/account/register
Create a Project on the Stringee Dashboard.

Buy a Number (optional)
Buy a number from Dashboard for app-to-phone and phone-to-app calling. If you only need app-to-app calling, skip this step.

Configure answer_url
For more information on answer_url, read Stringee Call API Overview. You can view answer_url sample code here: https://github.com/stringeecom/server-samples/tree/master/answer_url

If you do not have answer_url, you can use the following Project's answer_url to accelerate the process:
Project's answer_url for App-to-App call:
https://developer.stringee.com/scco_helper/simple_project_answer_url?record=false&appToPhone=false
Project's answer_url for App-to-Phone call:
https://developer.stringee.com/scco_helper/simple_project_answer_url?record=false&appToPhone=true
(Source code here: https://github.com/stringeecom/server-samples/blob/master/answer_url/php/project_answer_url.php)
When building an application, you should use your own answer_url.

If you do not have answer_url, you can use the following Number's answer_url to accelerate the process:
Number's answer_url for Phone-to-App call (The call is routed to Your App which is authenticated by USER_ID):
https://developer.stringee.com/scco_helper/simple_number_answer_url?record=true&phoneToPhone=false&to_number=USER_ID
Number's answer_url for Phone-to-Phone call (The call is routed to TO_NUMBER):
https://developer.stringee.com/scco_helper/simple_number_answer_url?record=true&phoneToPhone=true&stringeeNumber=STRINGEE_NUMBER&to_number=TO_NUMBER
(Source code here: https://github.com/stringeecom/server-samples/blob/master/answer_url/php/number_answer_url.php)
When building an application, you should use your own answer_url.
Distribution notice: Starting in June 2026, new versions of the Stringee iOS SDK are released exclusively through Swift Package Manager (SPM). CocoaPods and manual distributions are retained for legacy integrations only and no longer receive version updates.
The SPM package requires iOS 13.0 or later and Swift tools 5.9 or later.
https://github.com/stringeecom/Stringee-iOS-SDK-SPM.git
Stringee product to your app target.Swift Package Manager downloads Stringee.xcframework and its required dependencies automatically when resolving the package. For Package.swift configuration and the latest version details, see the Stringee iOS SDK SPM repository.
The simplest way to import the SDK into an iOS project is with CocoaPods. Open your project's Podfile and add this line to your app's target:
pod 'Stringee'
Then from the command line run:
pod install --repo-update
If you are new to CocoaPods, refer to their official documentation for more information on how to create and use Podfiles.
In the "Build Settings" tab -> "Other linker flags" add "$(inherited)" flag
In the "Build Settings" tab -> "Enable bitcode" select "NO"
To add the SDK in Xcode:


Add the following libraries and frameworks to Target -> "Build Phases" -> "Link Binary With Libraries":



<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) uses Camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) uses Microphone</string>
To connect to the Stringee Server, 3-party authentication is required as described here: Client authentication
For testing purpose, go to Dashboard -> Tools -> Generate Access token and generates an access_token. In production, the access_token should be generated by your server, sample code generates access token here: https://github.com/stringeecom/server-samples/tree/master/access_token
#import <Stringee/Stringee.h>
In .h file
@interface ViewController : UIViewController <StringeeConnectionDelegate>
@property(strong, nonatomic) StringeeClient * stringeeClient;
@end
In .m file
- (void)requestAccessToken:(StringeeClient *)stringeeClient {
NSLog(@"requestAccessToken");
}
- (void)didConnect:(StringeeClient *)stringeeClient isReconnecting:(BOOL)isReconnecting {
NSLog(@"Successfully connected to Stringee Server, user ID: %@", stringeeClient.userId);
}
- (void)didDisConnect:(StringeeClient *)stringeeClient isReconnecting:(BOOL)isReconnecting {
NSLog(@"didDisConnect");
}
- (void)didFailWithError:(StringeeClient *)stringeeClient code:(int)code message:(NSString *)message {
NSLog(@"Failed connection to Stringee Server with error: %@", message);
}
NSString* accessToken = @"...";
self.stringeeClient = [[StringeeClient alloc] initWithConnectionDelegate:self];
[self.stringeeClient connectWithAccessToken:accessToken];
When the client connects to Stringee Server, instantiate a StringeeCall object and call the makeCallWithCompletionHandler method:
StringeeCall * stringeeCall = [[StringeeCall alloc] initWithStringeeClient:self.stringeeClient isIncomingCall:NO from:@"+1273065979" to:@"+1909982888"];
[stringeeCall makeCallWithCompletionHandler:^(BOOL status, int code, NSString * message, NSString *data){
NSLog(@"Make call result: code=%d, message: %@", code, message);
}];
The type of the outgoing call (app-to-app or app-to-phone) is decided by Your Server via the project's answer_url. Hence, you should be able to complete it independently. However, we offer an easy method for you to implement quickly by calling:
stringeeCall.customData = @"custom";
"custom" is a customizable text that be sent to Your Server via the project's answer_url. You can set it as: {'type': 'app-to-app'}, {'type':'app-to-phone'} or any other texts you want. Your Server will check this text to determine whether the call is app-to-app or app-to-phone.
Implement the StringeeCallDelegate protocol.
#import <Stringee/Stringee.h>
@interface ViewController : UIViewController <StringeeConnectionDelegate, StringeeCallDelegate>
@property(strong, nonatomic) StringeeClient * stringeeClient;
@end
in .m file:
//----------- StringeeCallDelegate -->
- (void)didChangeSignalingState:(StringeeCall *)stringeeCall signalingState:(SignalingState)signalingState reason:(NSString *)reason sipCode:(int)sipCode sipReason:(NSString *)sipReason {
NSLog(@"signalingState: %d", signalingState);
}
- (void)didChangeMediaState:(StringeeCall *)stringeeCall mediaState:(MediaState)mediaState {
NSLog(@"mediaState: %d", mediaState);
}
- (void)didReceiveDtmfDigit:(StringeeCall *)stringeeCall digit:(NSString *)digit {
NSLog(@"didReceiveDtmfDigit: %@", digit);
}
- (void)didReceiveLocalStream:(StringeeCall *)stringeeCall {
NSLog(@"didReceiveLocalStream");
}
- (void)didReceiveRemoteStream:(StringeeCall *)stringeeCall {
NSLog(@"didReceiveRemoteStream");
}
- (void)didReceiveCallInfo:(StringeeCall *)stringeeCall info:(NSDictionary *)info {
NSLog(@"didReceiveCallInfo: %@", info);
}
- (void)didHandleOnAnotherDevice:(StringeeCall *)stringeeCall signalingState:(SignalingState)signalingState reason:(NSString *)reason sipCode:(int)sipCode sipReason:(NSString *)sipReason {
NSLog(@"didAnsweredOnOtherDevice %d", signalingState);
}
//----------- StringeeCallDelegate <--
and set delegates for stringeeCall:
stringeeCall.delegate = self;
Implement the StringeeIncomingCallDelegate protocol
#import <Stringee/Stringee.h>
@interface ViewController : UIViewController <StringeeConnectionDelegate, StringeeCallDelegate, StringeeIncomingCallDelegate>
@property(strong, nonatomic) StringeeClient * stringeeClient;
@end
in .m file:
- (void)incomingCallWithStringeeClient:(StringeeClient *)stringeeClient stringeeCall:(StringeeCall *)stringeeCall {
NSLog(@"incomingCallWithStringeeClient, from: %@, to: %@", stringeeCall.from, stringeeCall.to);
}
and set incomingCallDelegate for stringeeClient:
self.stringeeClient.incomingCallDelegate = self;
When the client receives an incoming call
- (void)incomingCallWithStringeeClient:(StringeeClient *)stringeeClient stringeeCall:(StringeeCall *)stringeeCall {
NSLog(@"incomingCallWithStringeeClient, from: %@, to: %@", stringeeCall.from, stringeeCall.to);
stringeeCall.delegate = self;
}
Call the following method to initialize resources:
[stringeeCall initAnswerCall];
Call the following method to answer and start the conversation:
[stringeeCall answerCallWithCompletionHandler:^(BOOL status, int code, NSString *message) {
NSLog(@"%@", message);
}];
Call the following method to Hang up a call.
[stringeeCall hangupWithCompletionHandler:^(BOOL status, int code, NSString *message) {
NSLog(@"%@", message);
}];
Call the following method to reject a call.
[stringeeCall rejectWithCompletionHandler:^(BOOL status, int code, NSString *message) {
NSLog(@"%@", message);
}];
stringeeCall.isVideoCall = YES;
-(void) didReceiveLocalStream:(StringeeCall *)stringeeCall {
dispatch_async(dispatch_get_main_queue(), ^{
[stringeeCall.localVideoView setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[self.view insertSubview:stringeeCall.localVideoView atIndex:0];
});
}
Implement the StringeeRemoteViewDelegate protocol
#import <Stringee/Stringee.h>
@interface ViewController : UIViewController <StringeeConnectionDelegate, StringeeCallDelegate, StringeeIncomingCallDelegate, StringeeRemoteViewDelegate>
@property(strong, nonatomic) StringeeClient * stringeeClient;
@end
in .m file:
- (void)videoView:(StringeeRemoteVideoView *)videoView didChangeVideoSize:(CGSize)size {
NSLog(@"StringeeRemoteVideoView didChangeVideoSize: %fx%f", size.width, size.height);
}
Modify the implementation code of the didReceiveRemoteStream method:
-(void) didReceiveRemoteStream:(StringeeCall *)stringeeCall {
dispatch_async(dispatch_get_main_queue(), ^{
[stringeeCall.remoteVideoView setFrame:CGRectMake(0, 0, self.containRemoteView.bounds.size.width, self.containRemoteView.bounds.size.height)];
stringeeCall.remoteVideoView.delegate = self;
[self.containRemoteView addSubview:stringeeCall.remoteVideoView];
});
}
- (void)didChangeMediaState:(StringeeCall *)stringeeCall mediaState:(MediaState)mediaState {
dispatch_async(dispatch_get_main_queue(), ^{
if (mediaState == MediaStateConnected) {
[[StringeeAudioManager instance] setLoudspeaker:YES];
}
});
}
You can view the full version of this sample app on GitHub: https://github.com/stringeecom/ios-sdk-samples