LogoLogo
  • Introduction
  • Features
  • Getting Started
    • Cortex User Guide
      • Organizations
      • Log in
      • Generate an API key
      • Make your first API request
      • Configure the org settings
      • Set up a data model
        • Create custom objects
        • Add custom properties
      • One-to-many relationships
      • Read and write data
      • Making a Request
      • Handling responses
      • Authentication
      • Two-factor authentication
      • Set third-party cookies
      • Connections
      • Upload files
      • Cortex iOS
      • Get started with Swift
      • Cortex service accounts
      • Cortex developer tools
      • Automated Account Notifications
  • Cortex API
    • Overview
    • Objects
      • Objects Overview
      • Organization
      • Account
      • Connections
      • Notifications
      • Stats
      • Logs
      • Export
      • Events
      • Room
    • Object Definition
      • Object Properties
        • Any
        • Binary
        • Boolean
        • Date
        • Document
        • File
        • Geometry
        • List
        • Number
        • ObjectId
        • Reference
        • String
    • Object Types
    • Access Control
    • Querying
      • Query Operators
      • Property Selection
      • Property Access
    • Aggregating
      • Aggregation Operators
    • Scripting
      • Script Types
      • Script Limits
      • ObjectId
      • CortexObject
        • Accounts
        • Views
      • Cursors
      • Operations
      • Script Modules
        • API Module
        • Base64 Module
        • Cache Module
        • Connections Module
        • Console Module
        • Consts Module
        • Counters Module
        • Crypto Module
        • HTTP Module
        • Logger Module
        • Notifications Module
        • Request Module
        • Response Module
        • SAML Module
        • Schemas Modules
        • Script Module
        • Session Module
        • Util.id Module
        • Util.ip Module
        • Util.paths Module
        • XML Module
        • Developer
        • Config
        • Renderer
        • SFTP
        • FTP
        • DB
          • Cursors
          • Driver
      • Static Methods
        • Accounts
        • Views
        • Cursors
      • Audit
      • Environments
      • HTTP Driver
      • Notifications
        • Firebase Cloud Messaging (FCM)
        • Tencent Push Notification Service Configuration
      • Televisit
      • Transforms
      • Localization
      • Available Javascript Libraries
    • Decorators
      • Runtime
        • Acl
        • As
        • Log
        • Profile
      • Static
        • Env
        • Job
        • Object
        • On
        • Policy
        • Route
        • Transform
        • Trigger
    • Expressions
      • Primer
      • Pipelines
      • Operators
      • Accumulators
      • Variables
      • Conditionals
      • Transforms
      • Triggers
      • On
      • Events
    • Faults
      • Fault Reference
  • Releases
    • Cortex Release Notes
      • Cortex API 2.28.3 (R3.4.6)
      • Cortex API 2.28.1 (R3.4.3)
      • Cortex API 2.27.2 (R3.4.1)
      • Cortex API 2.27.1 (R3.3.5)
      • SQL DB Connector 1.3.4 (R3.3.3)
      • Cortex API 2.26.2 (R3.3.1)
      • Cortex API 2.26.1 (R3.2.2)
      • Cortex API 2.26.0 (R3.2.1)
      • SQL DB Connector 1.3.3
      • Cortex API 2.25.0 (R3.1.1)
      • SQL DB Connector 1.3.2 (R3.1.0)
      • Cortex API 2.24.2 (R3.0.2)
      • SQL DB Connector 1.3.1 (R3.0.0)
      • Cortex API 2.24.1 (R2.3.3)
      • Cortex API 2.24.0 (R2.3.2)
      • SQL DB Connector 1.3.0 (R2.3.0)
      • Cortex API 2.23.0 (R2.2.4)
      • SQL DB Connector 1.2.0 (R2.2.0)
      • Cortex API 2.22.2 (R2.1.2)
      • Cortex API 2.22.1 and SQL DB Connector 1.1.1 (R2.0.1)
      • Cortex API 2.22.0
      • Cortex API 2.21.3
      • Cortex API 2.21.2
      • Cortex Web 4.16.0
      • Cortex Web 4.15.1
      • Cortex API 2.20.1
      • Cortex Web 4.14.0
      • Cortex Renderer 1.3.3
      • Cortex API 2.19.4
      • Cortex API 2.19.3 and Cortex Web 4.13.1
      • Cortex Renderer 1.3.2
      • Cortex API 2.19.1
      • Cortex API 2.18.0
      • Cortex API 2.17.6
      • Cortex API 2.17.5
      • Cortex API 2.17.4
      • Cortex API 2.17.3
      • Cortex API 2.17.2
      • Cortex API 2.17.1
      • Cortex API 2.16.0
      • Cortex API 2.15.9
      • Cortex API 2.15.8-1
      • Cortex 2.15.8
      • Cortex API 2.18.1
      • Cortex API 2.16.1
      • Cortex Renderer 1.3.1
      • Cortex Renderer 1.3.0
      • Cortex Renderer 1.2.2
      • Cortex Renderer 1.2.1
      • Cortex Renderer 1.2.0
    • Third-Party License Attribution

© 2025 Medable, Inc. All rights reserved.

On this page
  • Create your Swift Project
  • Install Medable Cortex iOS SDK
  • Initialize Medable
  • Integration Complete
  • Create Registration Form
  • Register Account
  • Password Validation
  • Mobile Number Validation
  • Registration Complete
  • Interface Builder Setup
  • Login Auth Response
  • Successful Login
  • Two-factor Authentication Required
  • Invalid email/password combination
  • Login Complete
  • Generate PEM file
  • Enable Medable Push Notifications
  • Send Medable Push
  • Xcode Setup
  • First Push Notification Successful

Was this helpful?

  1. Getting Started
  2. Cortex User Guide

Get started with Swift

Last updated 3 years ago

Was this helpful?

iOS SDK for Medable provides a wrapper for the Medable RESTful API as well as several helper tools to directly integrate those features to your iOS application.

The Medable iOS SDK is targeted to be used in apps that have a base SDK of iOS 7+ and the following instructions are targeted for Xcode 6+ users. Please consider updating if you have an older version.

To see the github repo for the Medable iOS SDK, click here.

The following articles how to get started quickly with Medable using Swift 3 and Xcode 8.

This tutorial shows one way to quickly get started using a new or existing Swift iOS project. Before you begin, you should have generated an API key. If not, .

Create your Swift Project

In Xcode, select File > New Project...

Select Single View Application and click next.

Enter your project details. For this tutorial, we'll call the app "NewHealthCo"

Install Medable Cortex iOS SDK

Integrate the SDK following the integration instructions from the README.md file in the SDK repository.

Initialize Medable

Add the Medable start function to your AppDelegate and set the logger level to Debug so you can see more detailed network responses in the console. Swift

//AppDelegate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    Medable.start()
    Medable.client().loggerLevel = MDAPIClientNetworkLoggerLevelDebug

    return true
}

Then build and run the app

Integration Complete

You've successfully connected to your Medable HIPAA compliant backend. You're ready to collect PHI.

Account registration boils down to one function

Medable.client().registerAccount...

This function takes in a number of default parameters to initialize the Account object with. But only five of them are required

  • First Name

  • Last Name

  • Email

  • Password

  • Mobile Number

Optional parameters include gender, dob, profile image, and role.

Here, we'll show you how to create a basic registration form using Swift and Interface Builder. At the end we provide a zip file containing the final result of this step-by-step tutorial.

Create Registration Form

  1. Open Interface Builder (IB) by opening Main.storyboard

  2. Drag a Navigation Controller into IB and set it as the initial view

  3. Set the table view Content setting to Static Cells

  4. Drag a UITextField into a static cell with proper struts and springs

  5. Replicate this static cell for each field you'd like to collect in this form

  6. Associate an IBOutlet for each text field

  7. Drag a UIBarButtonItem into the top bar and call it "Submit"

  8. Associate an IBAction called "submitPressed" with the "Submit" button

Build and Run to make sure that you can see the form and all its placeholder values.

Register Account

Add one function to the submitPressed function to make the form create a user in your database.

Medable.client().registerAccountWithFirstName(firstNameField.text!, lastName: lastNameField.text!, email: emailAddressField.text!, mobile: "1\(mobileNumberField.text!)", password: passwordField.text!, gender: nil, dob: nil, role: nil, profileInfo: nil, thumbImage: nil, customPropValues: nil) { (account:MDAccount?, error:MDFault?) in
    print("Callback returns account: \(account)")
    print("Callback returns error: \(error)")
}

Submit the registration form and let's see what we get in the console:

Callback returns error: Optional(kValidationError - validation - Validation error - *Subfault: kInvalidArgument - error - Invalid Argument - The chosen password does not meet the minimum Org password strength requirement. - path: password)

We got a validation error because our password strength isn't high enough.

You set the minimum password strength in your org settings. The default minimum is Good, which which maps to 2 on the 0-4 on the zxcvbn scale. We strongly advise against lowering this minimum.

Password Validation

It would be fantastic if we could immediately know whether a password will be strong enough before making an API call. Luckily, there's an open-source library that allows us to do just that.

pod 'zxcvbn-ios'
  1. Add the zxcvbn-ios pod to your Podfile

  2. Install dependencies by running pod install on your terminal

  3. Open RegistrationTableViewController.swift and import zxcvbn_ios at the top

  4. Make RegistrationTableViewController a delegate for the password text field

  5. Drag a UIView next to the UITextField for the password

  6. Set this UIView to a Custom Class called DBPasswordStrengthMeterView and drag as an IBOutlet into the controller

The final step is to implement the UITextField Delegate function so that each change in the password field is given a new strength indicator

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let password = (textField.text! as NSString).replacingCharacters(in: range, with: string)
    passwordStrengthMeter.scorePassword(password)
    return true
}

Build and Run

We want to be sure that when we submit the form, the password strength is at least as strong as our org setting minimum. The default minimum is 2 (Good). The lowest is 0 (Weakest). Add the following lines to the submitPressed function before calling register.

if DBZxcvbn().passwordStrength(passwordField.text!).score < 2 {
    print("The password is not strong enough")
    return
}

Now our password validation happens locally before making any network calls and our user isn't left guessing a million different passwords hoping they'd meet the minimum strength requirement!

Mobile Number Validation

Let's use the iOS version of phonelib to check that a number is valid before making an API call

pod 'libPhoneNumber-iOS'
  1. Add the libPhoneNumber-iOS pod into your Podfile and pod install in the terminal

  2. Open RegistrationTableViewController.swift and import libPhoneNumber_iOS at the top

  3. Add the following lines to the submitPressed function before calling register.

    let phoneUtil = NBPhoneNumberUtil() do { let myNumber = try phoneUtil.parse(mobileNumberField.text!, defaultRegion: "US") if !phoneUtil.isValidNumber(myNumber) { return } } catch let error as NSError { print(error) }

We first define the util that will parse and validate the user's mobile number. To test this, run the app with an obviously invalid phone number like 12223334444 and the function should return with an error in the console without calling register.

Note: the mobile number must be formatted with the country code included or it will be marked as invalid and registration will fail.

Registration Complete

You now have a registration form to sign up new users!

Interface Builder Setup

Logging in is done through the function .authenticateSessionWithEmail... which takes in 4 parameters

  1. Email

  2. Password

  3. Verification Token - this is an optional parameter that you only set when the user is using 2fa to verify his/her identity

  4. Single Use - having this set to false tells the Medable SDK to remember the current device for all future login attempts so that 2fa is no longer required for this specific account on this specific device

If you attempt to login on the same iOS simulator or device that you used for registration, the authentication should succeed without a verification token.Swift

Medable.client().authenticateSession(withEmail: emailAddressField.text!, password: passwordField.text!, verificationToken: nil, singleUse: false) { (account:MDAccount?, error:MDFault?) in
    print("Callback returns account: \(account)")
    print("Callback returns error: \(error)")
}

Login Auth Response

Attempting to authenticate a user results in three common scenarios

Successful Login

Callback returns account: Optional(Id: 5784279b46b010416570d2ac  Name: John Smith   eMail: test@extremail.ru)

Two-factor Authentication Required

To test this you simply register an account on one simulator/device and try to login to that same account on a different version simulator or different device. Alternatively, you could delete the app between registration and installation.

Callback returns error: Optional(kNewLocation - location - A new location has been added to the account. Please verify it -)

Or, if the user was already sent a verification code but still tries to login without passing in a verification code

Callback returns error: Optional(kUnverifiedLocation - location - Access by this location is pending account holder verification -)

So if the callback returns either of these error messages, we prompt the user to enter the 6-digit verification code that Medable automatically sends to the mobile number associated with the account (via SMS). Create an instance of UIAlertController to collect this information and call authorize again with the code passed in as a parameter (instead of nil)

if let code = error?.code {
    if code == kMDAPIErrorNewLocation || code == kMDAPIErrorUnverifiedLocation {
        self.present(self.verificationCodeController, animated: true, completion: nil)
    }
}

Invalid email/password combination

For security reasons, the Medable API will never indicate whether the email doesn't exist in the database or the password was incorrect for an existing email. Instead the API simply accepts or denies a given combination of email/password.

Callback returns error: Optional(kInvalidCredentials - auth - Invalid email/password combination -)

Add a "Reset Password" button to the tab bar and corresponding IBAction

@IBAction func passwordResetPressed(_ sender: UIBarButtonItem) {
    self.present(self.passwordResetController, animated: true, completion: nil)
}

Here's the setup code for the two UIAlertController.

Swift

var verificationCodeController = UIAlertController(title: "Verification Code", message: "Enter the 6-digit code that was sent to your mobile device", preferredStyle: .alert)
var passwordResetController = UIAlertController(title: "Password Reset", message: "Enter the email address you used to register and we'll email you a password reset link.", preferredStyle: .alert)

override func viewDidLoad() {
  super.viewDidLoad()

  verificationCodeController.addTextField { (textField:UITextField) in
    textField.keyboardType = .numberPad
  }
  verificationCodeController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
  verificationCodeController.addAction(UIAlertAction(title: "Submit", style: .default, handler: { (action:UIAlertAction) in
    if let verificationCode = self.verificationCodeController.textFields?.first?.text {
        Medable.client().authenticateSession(withEmail: self.emailAddressField.text!, password: self.passwordField.text!, verificationToken: verificationCode, singleUse: false) { (account:MDAccount?, error:MDFault?) in
            print("Callback returns account: \(account)")
            print("Callback returns error: \(error)")
        }
    }
  }))

  passwordResetController.addTextField { (textField:UITextField) in
    textField.keyboardType = .emailAddress
  }
  passwordResetController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
  passwordResetController.addAction(UIAlertAction(title: "Submit", style: .default, handler: { (action:UIAlertAction) in
  if let email = self.passwordResetController.textFields?.first?.text {
    Medable.client().requestPasswordReset(withEmail: email, callback: { (error:MDFault) in })
  }
  }))

}

Login Complete

Once login is successful, the Medable.client().currentUser object is defined for you to access details regarding the logged-in user from any file in the project.

In this tutorial, we'll demo the built-in push notification feature of Medable. The setup involves a 4-step configuration:

  1. Generate PEM file

  2. Enable Medable Push Notifications

  3. Send Medable Push

  4. Xcode Setup

Generate PEM file

Start by navigating to developer.apple.com

Go to "Certificates, Identifiers & Profiles" -> "Identifiers" -> "App IDs"

Select your app ID -> Click Edit -> Enable Push Notifications -> Under Development SSL Certificate, Click Create Certificate

Follow Apple's instructions to create a certificate named Apple Development IOS Push Services: APP ID HERE in your Keychain Access app

Name it something like MedableDevPushCertificate -> Change format to .p12 -> Click Save

If you don't see the .p12 option in the dropdown, navigate to the "Certificates" section in the left navigation and right click on the certificate from there

Open Terminal -> cd into the folder that contains MedableDevPushCertificate.p12 -> copy paste the following command

    $ openssl pkcs12 -in MedableDevPushCertificate.p12 -out MedableDevPushCertificate.pem -nodes -clcerts

🚧IMPORTANT

DO NOT enter a password when prompted after issuing the above command in the terminal - just press enter to continue

Open MedableDevPushCertificate.pem in the text editor of your choice, from the Terminal or Finder

You should see a bunch of mumbo jumbo clearly delineated by -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- and -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----

Congrats! Part 1 is done. But keep this .pem file open - we'll be copy pasting some of this into your Medable App Settings

Enable Medable Push Notifications

  1. Go to your Medable Admin Portal- app.dev.medable.com/

  2. Settings => Apps => Select your app

  3. Check APNs Debug Gateway Option - only do this if you're inputting a development certificate.

  4. Copy everything from begin certificate to end certificate (including markers) into the APNs Certificate field

  5. Copy everything from begin RSA private key to end RSA private key (including markers) into the APNs Private Key field

Send Medable Push

Remember that in this example, we'll be sending a push notification once a user logs in successfully. Create a trigger script to achieve this behavior.

Create a custom notification by going to Settings -> Notifications -> Custom Notifications -> New Notification

Click Add Endpoint

Create the custom notification with the Push Notification Endpoint and now you can send trigger this notification in your custom script.

  1. Go to Settings -> Scripts -> New Script

  2. Create a trigger than runs upon Account login

The notification code corresponds to the custom notification we created. The name set to the principal's name in order to be able to use it in the notification template to personalize the message with the receiver's name. A third parameter can be set in the notif.send() function to specify who gets the push notif. But if not, it will default to whoever is the run-time caller.

Xcode Setup

Ensure that your device is registered under this provisioning profile. This is done by going to developer.apple.com -> Devices -> click + button -> specify name and UDID of device -> click register. Then select this device when creating your provisioning profile.

Setting up your application to receive push notifications is simple. Just a few more lines of code to our existing tutorial project that already has registration and login built in.

In the App Delegate after application has launched, let's request permission from the user to send push notifications

let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted:Bool, error:Error?) in }
application.registerForRemoteNotifications()

In order for UNUserNotificationCenter to function, we need to import UserNotifications at the top of the AppDelegate

Once permission is granted, let's send the device token to Medable so the system knows where to send the push notifications.

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    Medable.client().setPushNotificationToken(deviceToken)
}

If the push notification is received while the user isn't using the app, the device will show the alert text on the lock screen or as a popup banner. But if the user is in the app, a separate AppDelegate function gets called:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    print(userInfo)
}

Run the app and login. In seconds, you'll receive a push notification logged in your console. Lock your device, login from the web console and you'll see the push notification show up on your device's lock screen.

First Push Notification Successful

Nice job!

The app shows a blank screen but you should see proper console outputs

Great, we've got our setup and we're ready to rock and roll.

This tutorial will make use of the Account Registration route which is disabled by default in your Organization Settings. You'll want to enable registration under Settings > Organization in order for it to work. See for more details.

This function simply passes in all data entered into the form as parameters for the registration function. As an example, let's suppose we input the following into our simulator:

Medable uses the password strength estimator to evaluate how strong a password is

I've turned off secure text entry to show that the meter does indeed adjust to the complexity of the password

Another type of error you might get when trying to call register is kInvalidPhoneNumberFormat. This means the entered mobile number is probably not a real number. Medable uses to validate numbers.

We've finished and now it's time to allow registered users to log back in. First, add screens to the IB for login.

Link the form fields and submit button actions just as we did for the registration view

For security reasons, Medable enforces two-factor authentication. Learn more

When the button is pressed, we present a UIAlertController once again to collect the email address that the user is trying to login with.

Right click on this certificate and select the export option.

It will prompt you to enter a password - DO NOT enter any password - simply click OK with the fields empty

If you're having trouble getting to this point, there's a more detailed guide if you scroll down to "Creating an and PEM file"

By the way, I selected a custom Login Successful template I created in the Settings -> Templates tab

Xcode 8 makes it easier than ever to enable push notifications on your project. If you followed instructions correct to this point, you shoud just be able to switch on Push Notifications in the Capabilities section of your project settings.

Now navigate to your Project Settings and uncheck the Automatically manage signing option. We'll upload a provisioning profile specific to this app instead. We didn't cover how to get a provisioning profile from the apple dev center but you can find instructions on how to do this from other online resources.

New Project
Configuring Org Settings
Download Project Snapshot
zxcvbn
Download Project Snapshot
Google's phonelib
Registration
here
here
SSL Certificate
do this first