NAV
shell

Introduction

Welcome to the Savvy API! You can use our API to access Savvy API endpoints, which helps you create any mutual funds usecase you like. Savvy is your one stop shop, no signups for any other external services are required.

We have language bindings in Shell only for now. We don't have readymade clients as of now, but they'll be coming soon! You can view shell (curl) code examples in the dark area to the right.

Authentication

To authorize, you must pass a Base64 encoded combination of your access key and password. Use this code:

# With shell, you can just pass the correct header with each request
# encoded_key = Base64.encode("ACCESS_KEY:PASSWORD")
curl -XPOST "https://surface.thesavvyapp.in/secure/tokens" \
  -H "Authorization: Basic <encoded_key>"
Response:
{
  "token": "abcdeabcdeacbde"
}
# Use above token as Bearer token for secure paths:
curl "api_endpoint_here" \
  -H "Authorization: Bearer <token>"

Savvy has 2 ways of authenticating, depending on how the API is being used:

  1. Secure paths using Basic auth + Bearer token: Using your API keys, you can request a new Bearer token that will give you access to partner level APIs (all investors under your partner account). You can register a new Savvy API key combination by sending us an email at hello@savvyapp.in.

  2. Individual paths using Bearer token: Using your secure token in the previous step, you can request a Bearer token that will access to investor specific APIs. Refer to the investors section for information on how to get a token for an individual investor.

Savvy expects a Bearer token to be included in all API requests to the server in a header as follows:

Authorization: Bearer <token>

Onboardings

Most of our APIs require an onboarding to be done before communicating with them. An onboarding is essentially a KYC (Know Your Customer) workflow which authorizes a person to conduct a mutual fund transaction. The workflow is the following:

graph TD; create_onboarding(Create onboarding with pan number and date of birth)-- Existing investor -->submit_bank_details(Submit bank details) create_onboarding-- Not an existing investor -->full_kyc(Full KYC); submit_bank_details-->update_onboarding(Submit user details and other FATCA details); update_onboarding-->create_nominees(Optionally: Create nominees); create_nominees-->create_transaction(Move ahead to create a transaction); full_kyc-->submit_pan(Submit picture of PAN card); submit_pan-->submit_address(Submit picture of an address proof); submit_address-->submit_signature(Submit picture of signature); submit_signature-->submit_cancelled_cheque(Submit picture of cancelled cheque of investor); submit_cancelled_cheque-->submit_selfie(Submit selfie image); submit_selfie-->verify_details(Verify details so far); verify_details-->submit_video(Submit video with OTP); submit_video-->aadhaar_sign(Aadhaar OTP verification); aadhaar_sign-->submit_full_kyc(Submit for verification);

Onboarding object

Parameter Description
uuid String Unique identifier of the onboarding object
pan_number String Customer PAN number. Note that the pan number is overwritten when parsed from the pan card.
existing_investor Boolean If this customer is an existing investor in the KRA databases. Use this field to determine if you to do a full KYC for the customer or not.
name String Customer's full name.
date_of_birth String Format DD/MM/YYYY. Note that the dob is overwritten when parsed from the pan card.
email String Customer's email address.
phone_number String Customer's phone number with +91 prefix.
kyc_status One of: ["success", "failure", "pending"] Result of full KYC verification post submission
pan_card_image_url URL String The pan card image submitted
fathers_name String Father's name from the pan card
address_proof_image_url URL String The address proof image submittted
address_proof_type One of: ["aadhaar", "voter_id", "passport", "license"]
address String Customer's street address.
city String Customer's city.
pincode String Customer's pincode.
signature_image_url URL String The signature image submitted
selfie_image_url URL String The selfie image submitted
cancelled_cheque_url URL String The cancelled cheque image submitted
video_url URL String The selfie video submitted
annual_income String Annual income code (refer to enum list)
gender String Gender code (refer to enum list)
occupation String Occupation code (refer to enum list)
marital_status String Marital status code (refer to enum list)
if_fatca_required Boolean This comes after the pan number is inserted into the onboarding either during create or update. If true, you MUST submit FATCA parameters (See "Update Onboarding" for fatca params)

Create onboarding

// body
{ "onboarding": 
  {
    "pan_number": "ABCDE1234C",
    "amc_code": "MOF",
    "phone_number": "9801234567",
    "email": "aa@bb.com"
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the onboarding JSON object with the name filled in if the customer is an existing investor.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings

Parameters

Parameter Required Description
pan_number true String Customer PAN number
amc_code true String AMC code for which this onboarding is being done

Show onboarding

curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns the onboarding JSON object.

HTTP Request

GET https://surface.thesavvyapp.in/secure/onboardings

Create onboarding bank account

// body
{ "onboarding": 
  {
    "account_number": "0012345678901",
    "ifsc_code": "HDFC0000873"
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/bank_account" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the onboarding JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/bank_account

JSON Parameters

Parameter Required Description
account_number true String A Valid bank account number
ifsc_code true String A valid IFSC code

Update onboarding

// body
{ "onboarding": 
  {
    "address": "67 Baker Street",
    "city": "Mumbai",
    "pincode": "900900",
    "date_of_birth": "27/06/1981",
    "occupation": "05",
    "email": "aa@bb.com",
    "fatca": {
      "fatca_birth_country_code": "IN",
      "fatca_citizenship_country_code": "IN",
      "fatca_tax_country_code": "IN",
      "fatca_place_of_birth": "Mumbai",
      "fatca_address_type": "01",
      "fatca_occupation": "05",
      "fatca_gross_income": "31",
      "fatca_source_wealth": "01"
    }
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>" \
  -X PUT \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the onboarding JSON object

HTTP Request

PUT https://surface.thesavvyapp.in/secure/onboardings/<UUID>

JSON Parameters

Parameter Required Description
email false String Required only if onboarding wasn't created with an email
address true String Street address
city true String Residential city of the investor
pincode true String Residential pincode of the investor
date_of_birth true Date Date of birth of the investor
occupation_code true Enum String Occupation of the investor
fatca_birth_country_code false String, required if is_fatca_required = true See FATCA country code enum below
fatca_citizenship_country_code false String, required if is_fatca_required = true See FATCA country code enum below
fatca_tax_country_code false String, required if is_fatca_required = true See FATCA country code enum below
fatca_place_of_birth false String, required if is_fatca_required = true Place of birth
fatca_address_type false String, required if is_fatca_required = true See FATCA Address Type enum below
fatca_occupation false String, required if is_fatca_required = true See occupation enum below
fatca_gross_income false String, required if is_fatca_required = true See income enum below
fatca_source_wealth false String, required if is_fatca_required = true See FATCA source of wealth enum below

Create nominees

// body
{ "nominees":
  [{
    "name": "Something",
    "email": "Something@gmail.com",
    "phone_number": "9898098980",
    "pan": "ABCDE1234C",
    "address": "Something",
    "city": "Something",
    "relationship": "Mother",
    "dob": "21/12/2012",
    "guardian_name": "Something",
    "percentage": 100,
    "guardian_address": "Something",
    "guardian_pan": "ABVDE1234R"
  }]
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/nominees" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the nominee JSON object

HTTP Request

PUT https://surface.thesavvyapp.in/secure/onboardings/<UUID>/nominees

Important note

JSON Parameters

Parameter Required Description
name true String Nominee's name
email true String Nominee's email
phone_number true String Nominee's phone number
pan true String Nominee's pan
address true String Nominee's address
city true String Nominee's address city
relationship true String Nominee's relationship (Mother, Father etc)
percentage false Decimal Percentage allocated to this nominee
dob true String Nominee's date of birth
guardian_name false String Gaurdian's name
guardian_address false String Gaurdian's address
guardian_pan false String Gaurdian's pan

Start Full KYC

// body
{ "onboarding":
  {
    "email": "batman@gmail.com",
    "name": "Bruce Wayne",
    "phone_number": "+919009012345",
    "full_kyc_redirect_url": "https://example.com/redirect"
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/full_kyc" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the onboarding JSON object

This endpoint prepares the onboarding object for a full KYC

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/full_kyc

JSON Parameters

Parameter Required Description
name true String Customer's name
email true String Customer's email
phone_number true String Customer's phone number
full_kyc_redirect_url true URL Where to redirect the user once the KYC is submitted to the AMC.

Upload file

// body
{
  "upload": "<file to upload>"
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/upload_file" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

Notice that to upload files, you must make a multi-part request. This will not work without appropriate multi-part headers.

This endpoint uploads files to our server for further processing and analysis.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/upload_file

JSON Parameters

Parameter Required Description
upload true File The file you want to upload

JSON response

Parameter Required Description
file true String URL of the uploaded file

Read pan card

// body
{
  "onboarding": {
    "image_urls": ["https://s3.images.com/123"]
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_pan_card" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns extra params along with the onboarding object. Please make sure you're reading the response correctly.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_pan_card

JSON Parameters

Parameter Required Description
image_urls true Array List of images to process. In the case of PAN card, we only need the front of the card.

JSON response

Parameter Required Description
onboarding true Object The normal onboarding object
name true String Name on the pan card
fathers_name true String Fathers name on the pan card
date_of_birth true String Date of birth on the pan card
pan_number true String Pan number on the pan card

Note that the scanned details are not guaranteed to match the PAN card exactly. They're on a best effort basis.

Read pan card from Digilocker

// body for digilocker auth
{
  "onboarding": {
    "is_digilocker": true,
    "digilocker_stage": "createUrl"
  }
}

// body for fetching info
{
  "onboarding": {
    "is_digilocker": true,
    "digilocker_stage": "getDetails"
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_pan_card" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns extra params along with the onboarding object. Please make sure you're reading the response correctly.

Instead of scanning an image, you may choose to give the option the user for extracting the PAN from digilocker. For this option, first generate an authorization URL by calling the API with the "createUrl" param, and then fetch the PAN using the "getDetails" param. Note that the digilocker authorization is only valid for 60 minutes. Post that, the user would have to re-auth.

For fetching further details like address proof etc, you do not need to call "createUrl" again. You can extract other docs using the same authorization.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_pan_card

JSON Parameters

Parameter Required Description
is_digilocker true Boolean Whether to initiate a digilocker request.
digilocker_stage true Enum: createUrl, getDetails Which function to run.

JSON response

Parameter Required Description
onboarding true Object The normal onboarding object
url false String Only returned in case of digilocker of stage "createUrl". This is the URL to direct the user to for authorizing digilocker.
images false Array of strings Only returned in case of digilocker of stage "getDetails". Images of the PAN extracted from Digilocker.
name false String Name on the pan card
fathers_name false String Fathers name on the pan card
date_of_birth false String Date of birth on the pan card
pan_number false String Pan number on the pan card

Submit pan card

// body
{
  "onboarding": {
    "name": "John Smith",
    "fathers_name": "Mark Smith",
    "date_of_birth": "01/01/1991",
    "pan_number": "ABCD1234C",
    "is_digilocker": true
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/pan_card" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/pan_card

JSON Parameters

Parameter Required Description
name true String Name on the pan card
fathers_name true String Fathers name on the pan card
date_of_birth true String Date of birth on the pan card
pan_number true String Pan number on the pan card
is_digilocker false Boolean If submitted details are from digilocker

The details submitted and the actual details on the PAN card must match. If they don't, the KYC will be rejected.

Read address proof

// body
{
  "onboarding": {
    "address_proof_type": "aadhaar",
    "image_urls": ["https://s3.images.com/123", "https://s3.images.com/456"]
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_address_proof" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns extra params along with the onboarding object, depending on the type of address proof. Please make sure you're reading the response correctly.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_address_proof

JSON Parameters

Parameter Required Description
address_proof_type true Enum One of [voter_id, passport, license]
image_urls true Array List of images to process. In the case of address proof, we need both back and front of the document.

JSON response

Parameter Required Description
onboarding true Object The normal onboarding object.
aadhaar_uid false String Masked aadhaar UID.
license_number false String License number.
passport_number false String Passport number.
voter_id_number false String Voter ID number.
name true true
date_of_birth true Date Date of birth on the proof.
pincode true String Pincode on the proof.
address true String Street address on the proof.
district true String District on the proof.
city true String City on the proof.
state true String State on the proof.
issue_date false Date Only present in license and passport.
expiry_date false Date Only present in license and passport.
fathers_name false String Only present in license, passport and voter id.

Note that the scanned details are not guaranteed to be correct. They're on a best effort basis.

Read address proof from Digilocker

// body for digilocker auth
{
  "onboarding": {
    "address_proof_type": "aadhaar",
    "is_digilocker": true,
    "digilocker_stage": "createUrl"
  }
}

// body for fetching info
{
  "onboarding": {
    "address_proof_type": "aadhaar",
    "is_digilocker": true,
    "digilocker_stage": "getDetails"
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_address_proof" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns extra params along with the onboarding object. Please make sure you're reading the response correctly.

Please note that Digilocker is only available for Aadhaar and Drivers' license

Instead of scanning an image, you may choose to give the option the user for extracting the address proof from digilocker. For this option, first generate an authorization URL by calling the API with the "createUrl" param, and then fetch the address proof using the "getDetails" param. Note that the digilocker authorization is only valid for 60 minutes. Post that, the user would have to re-auth.

If the user has already given authorization for PAN, you do not need to re-auth.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_address_proof

JSON Parameters

Parameter Required Description
address_proof_type true Enum One of [aadhaar, license]
is_digilocker true Boolean Whether to initiate a digilocker request.
digilocker_stage true Enum: createUrl, getDetails Which function to run.

JSON response

Parameter Required Description
onboarding true Object The normal onboarding object
url false String Only returned in case of digilocker of stage "createUrl". This is the URL to direct the user to for authorizing digilocker.
images false Array of strings Only returned in case of digilocker of stage "getDetails". Images of the PAN extracted from Digilocker.
onboarding true Object The normal onboarding object.
aadhaar_uid false String Masked aadhaar UID.
license_number false String License number.
passport_number false String Passport number.
voter_id_number false String Voter ID number.
name true true
date_of_birth true Date Date of birth on the proof.
pincode true String Pincode on the proof.
address true String Street address on the proof.
district true String District on the proof.
city true String City on the proof.
state true String State on the proof.
issue_date false Date Only present in license and passport.
expiry_date false Date Only present in license and passport.
fathers_name false String Only present in license, passport and voter id.

Submit address proof

// body
{
  "onboarding": {
    "address_proof_type": "aadhaar",
    "is_digilocker": true,
    "name": "John Smith",
    "expiry_date": "01/01/2029",
    "date_of_birth": "01/01/1991",
    "issue_date": "01/01/2000",
    "address":"23 Baker Street",
    "city": "Mumbai",
    "state": "Maharashtra",
    "district": "Malad",
    "pincode": "400051",
    "license_number": "12345678",
    "uid": "", // The aadhaar masked UID
    "passport_number": "",
    "voter_id_number": ""
   }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/address_proof" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/address_proof

JSON Parameters

Parameter Required Description
address_proof_type true String type of address proof being processed.
is_digilocker false Boolean If submitted details are from digilocker
name true String Name on proof.
expiry_date maybe (refer above) String Expiry date of proof.
date_of_birth maybe (refer above) String Date of birth on proof.
issue_date maybe (refer above) String Issue date of proof.
address true String Street address on proof.
city true String City on proof.
state true String State on proof.
district true String District on proof.
pincode true String Pincode on proof.
license_number maybe (refer above) String License number in case of license.
aadhaar_uid maybe (refer above) String Aadhaar UID in case of aadhaar
passport_number maybe (refer above) String Passport number in case of passort
voter_id_number maybe (refer above) String Voter ID number in case of voter ID

The details submitted and the actual details on the address proof must match. If they don't, the KYC will be rejected.

Read cancelled cheque

// body
{
  "onboarding": {
    "image_urls": ["https://s3.images.com/123", "https://s3.images.com/456"]
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_cancelled_cheque" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns extra params along with the onboarding object. Please make sure you're reading the response correctly.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/read_cancelled_cheque

JSON Parameters

Parameter Required Description
image_urls true Array List of images to process.

JSON response

Parameter Required Description
onboarding true Object The normal onboarding object.
ifsc_code true String IFSC code of the bank.
bank_account_number true String Bank account number.
bank_address true String Address of the bank.
accout_holder_name true String Name on cheque.

Note that the scanned details are not guaranteed to be correct. They're on a best effort basis.

Submit cancelled cheque

// body
{
  "onboarding": {
    "bank_account_number": "089897978797",
    "ifsc_code": "HDFC0000001",
    "bank_address": "Address",
    "account_holder_name": "John Smith"
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/cancelled_cheque" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/cancelled_cheque

JSON Parameters

Parameter Required Description
ifsc_code true String IFSC code of the bank.
bank_account_number true String Bank account number.
bank_address true String Address of the bank.
accout_holder_name true String Name on cheque.

The details submitted and the actual details on the address proof must match. If they don't, the KYC will be rejected.

Submit Investor Details

// body
{
  "onboarding": {
    "gender": "M",
    "marital_status": "UNMARRIED",
    "occupation_description": "Professional",
    "occupation_code": "04",
    "citizenship_code": "101",
    "citizenship_country": "India",
    "application_status_code": "01",
    "application_status_description": "New",
    "annual_income": "31"
   }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/form" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/form

JSON Parameters

Parameter Required Description
gender true Enum Refer to Enum tables at the bottom
marital_status true Enum Refer to Enum tables at the bottom
occupation_description true Enum Refer to Enum tables at the bottom
occupation_code true Enum Refer to Enum tables at the bottom
citizenship_code true Enum Refer to Enum tables at the bottom
citizenship_country true Enum Refer to Enum tables at the bottom
application_status_code true Enum Refer to Enum tables at the bottom
application_status_description true Enum Refer to Enum tables at the bottom
annual_income true Enum Refer to Enum tables at the bottom

Penny check

// body
{
  "onboarding": {
    "account_number": "1234567890",
    "ifsc_code": "HDFC0000001"
   }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/one_time_penny_drop" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object, along with penny check result.

This API analyzes the bank account and returns whether it belongs to the user in the onboarding. Note that the name of the user must already be filled in the onboarding object for this API to work.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/one_time_penny_drop

JSON Parameters

Parameter Required Description
account_number true String Bank account number
ifsc_code true String Bank account IFSC code

Response Parameters

Parameter Required Description
fuzzy_match_score true Decimal The matching score between the bank account owners' name and the onboarding name
onboarding true Object Onboarding object (see above)

Upload signature

// body
{
  "onboarding": {
    "image_urls": ["https://s3.images.com/123"]
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/signature" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/signature

JSON Parameters

Parameter Required Description
image_urls true Array List of images to process. In the case of signature, we need just one image.

Note that the signature must be against a white background. This can be either a physical signature on a white background, or a digital signature on a white background. The form factor is up to you

Upload selfie

// body
{
  "onboarding": {
    "image_urls": ["https://s3.images.com/123"]
  }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/selfie" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/selfie

JSON Parameters

Parameter Required Description
image_urls true Array List of images to process. In the case of selfie, we need just one image.

Start Video Verification

// body
{}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/start_video_verification" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns extra params along with the onboarding object. Please make sure you're reading the response correctly.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/start_video_verification

Important Info about this API

The API will return a random 6 digit number. The user must say this number on video. This allows to do a "liveness check" (make sure it's not a pre-recorded video).

JSON Response

Parameter Required Description
onboarding true Regular onboarding object
transaction_id true ID uniquely identifying this video verification
random_number true Random number to say on video

Submit Video Verification

// body
{
  "onboarding": {
    "video_url": "https://s3.videos/123",
    "transaction_id": "12345"
   }
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/video_verification" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/video_verification

JSON Parameters

Parameter Required Description
video_url true URL URL of the uploaded video via the upload file API.
transaction_id true String ID returned by the start video verification API.

Generate KYC Contract

// body
{
  "redirect_url": "https://example.com"
}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/generate_contract" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns extra params along with the onboarding object. Please make sure you're reading the response correctly.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/generate_contract

Important Info about this API

The API will return a url which you must redirect the user to. The webpage will show all the information submitted so far, and the user must sign the contract displayed with their aadhaar e-signature. The page has been known to not play well with app-embedded browsers. So it's recommended that you redirect the user to the actual browser on the phone.

Wait for the webhook to be informed of success/failure of contract signing and the reasons for failure, if any. The webhook will usually be triggered before the redirect URL. Refer to the webhook section for more info regarding the esign_success and esign_error params in the webhook.

JSON Request

Parameter Required Description
redirect_url false A URL to redirect user to post signing the contract. This is optional, if not supplied, the user will be redirected to a generic savvy page.

JSON Response

Parameter Required Description
onboarding true Regular onboarding object.
url true Aadhaar e-sign contract URL.

Execute Verification

// body
{}
curl "https://surface.thesavvyapp.in/secure/onboardings/<UUID>/execute_verification" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

This API returns the onboarding object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/onboardings/<UUID>/execute_verification

Important Info about this API

On success response of this API, the investors' details are pushed to the KRA/AMC for verification. Wait for the webhook to be informed of success/failure and the reasons for failure, if any. In case there is a failure, you can use the API to update the same onboarding. You will, however, have to generate a new contract, get a new aadhaar e-sign and execute verification again.

JSON Response

Parameter Required Description
onboarding true Regular onboarding object.

AMCs

This API gives you a list of supported AMCs by the Savvy API. This list remains relatively static, but we are constantly adding AMCs, so we recommend having some mechanism of fetching this list every so often. A monthly update might be ideal, but this is up to you.

AMC object

Parameter Description
name String Name of the AMC.
code String Operational code of the AMC. This code must be submitted in API requests, not the name.

Get all AMCs

curl "https://surface.thesavvyapp.in/secure/amcs" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns an array of AMC JSON objects.

HTTP Request

GET https://surface.thesavvyapp.in/secure/amcs

Funds

This API gives you lists of supported mutual funds, by AMC. There is also support for NFOs, along with their timelines. Please note that NFOs are updated 1-2 days before the launch date.

Fund object

Parameter Description
name String Name of the fund.
active Boolean Whether the fund is currently accepting purchases from customers.
code String Global unique identifier of this fund. This code must be submitted in API requests, not the name.
fund_info Object Current information of the fund; full object below.
minimum_first_time_investment Decimal Min investment if investing first time in the account. This is per account; if a new account is opened then this will apply.
minimum_ongoing_investment Decimal Min investment if investing again in the account. This is per account; if a new account is opened then this will not apply.
minimum_redemption_amount Decimal Min amount for withdrawals. If submitting a transaction that will make the balance fall below this min, it will not be accepted
settlement_days Integer Amount of days taken for units to get allocated.
minimum_sip_amount Decimal Min amount for an SIP.
minimum_swp_amount Decimal Min amount for an SWP.
minimum_stp_amount Decimal Min amount for an STP.
factsheet_link String Link to the factsheet on the AMC website.
category String Category of the fund
sub_category String Sub-category of the fund
risk_rating Integer 1-6 rating on the riskometer
crisil_rating String Rating from CRISIL
expense_ratio Decimal Expense ratio (fees collected by the scheme) for this fund
objective String Investment objective of this fund
aum Decimal Assets under management for this fund
comparisons Array Comparisons of this fund with other similar funds
expense_ratio Decimal Expense ratio as a percentage
fund_managers Array[String] List of fund managers
volatility Decimal Volatility rating of this fund
is_regular_scheme Boolean Whether fund is regular or direct
sip_returns Object SIP returns of the fund; full object below.

Fund info

Parameter Description
nav Decimal Current net asset value of the fund. This is updated at cutoff time.
return_year_1 Decimal CAGR since last 1 year
return_year_3 Decimal CAGR since last 3 year
return_year_5 Decimal CAGR since last 5 year

SIP returns

Parameter Description
week_1 Decimal SIP returns since last week
year_1 Decimal SIP returns since 1 year ago
year_3 Decimal SIP returns since 3 years ago
year_5 Decimal SIP returns since 5 years ago
inception Decimal SIP returns since inception of the fund
date Decimal Date of last calculation of returns

Get all funds

curl "https://surface.thesavvyapp.in/secure/funds?amc_code=code" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns an array of Fund JSON objects.

HTTP Request

GET https://surface.thesavvyapp.in/secure/funds

URL Parameters

Parameter Required Description
amc_code true String Code of the AMC from the AMC list API.

Fund performance

curl "https://surface.thesavvyapp.in/secure/funds/<fund_code>/performance?amc_code=code" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns a map of date mapped to average NAV value.

HTTP Request

GET https://surface.thesavvyapp.in/secure/funds/<fund_code>/performance

URL Parameters

Parameter Required Description
amc_code true String Code of the AMC from the AMC list API.

JSON Response

Parameter Required Description
Map true A map of (month, year) -> Average NAV value in that month

Fund holdings

curl "https://surface.thesavvyapp.in/secure/funds/<fund_code>/holdings?amc_code=code" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns a map of date mapped to average NAV value.

HTTP Request

GET https://surface.thesavvyapp.in/secure/funds/<fund_code>/holdings

URL Parameters

Parameter Required Description
amc_code true String Code of the AMC from the AMC list API.

JSON Response

Parameter Required Description
holding true Company/Asset name
exposure true Number in percentage terms of the exposure of the fund to the asset.

Accounts

For most usecases, the accounts API is a pull-only API. Accounts are created asynchronously; when a purchase transaction is successful, a new account number (Folio number in the MF world) is allocated. You should be listening to webhooks to listen for account creations.

Account object

Parameter Description
uuid String Unique identifier of the account.
amc_code String Code of the AMC which this account is of.
amc_name String Name of the AMC which this account is of.
account_value Map Fund code => Current investment amount mapping.
units_by_fund Map Fund code => Units mapping.
folio_number String AMC generated number.
portfolio Array Full portfolio information of the account.
holding_mode Enum: ["SI"] Only Single mode is supported as of now.

Index accounts

curl "https://surface.thesavvyapp.in/secure/accounts?onboarding_uuid=<ONBOARDING_UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns a list of account JSON objects.

HTTP Request

GET https://surface.thesavvyapp.in/secure/accounts

Show account

curl "https://surface.thesavvyapp.in/secure/accounts/<UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns a account JSON object.

HTTP Request

GET https://surface.thesavvyapp.in/secure/accounts/<UUID>

Bank configurations

Before making lumpsum, SIP or mandate transactions, you may want to check whether which banks are available for which payment modes.

Bank configuration object

Parameter Description
ifsc_first_4 String First 4 digits of the IFSC code
debit_card_mandate_allowed Boolean
debit_card_mandate_maximum Integer
net_banking_mandate_allowed Boolean
net_banking_mandate_maximum Integer
upi_mandate_allowed Boolean
upi_mandate_maximum Integer
upi_lumpsum_allowed Boolean
upi_lumpsum_maximum Integer
net_banking_lumpsum_allowed Boolean
net_banking_lumpsum_maximum Integer

Show bank configuration

curl "https://surface.thesavvyapp.in/secure/bank_configurations/<IFSC CODE>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns a single bank configuration object.

HTTP Request

GET https://surface.thesavvyapp.in/secure/bank_configurations/<IFSC CODE>

URL Parameters

The IFSC code must be appended on to the end of the URL.

Deposits

The deposits API describes how to create a mutual fund purchase transaction. This API can only be accessed post the onboarding flow. The workflow for creating and completing a purchase is:

graph TD; create_deposit(Create deposit with amount and fund details)-->redirect_user(Redirect user to payments page) redirect_user-- Failure -->user_failure(Your failure page); redirect_user-- Success-->user_success(Your success page); user_success-->listen(Listen for transaction updates via webhook);

Deposit object

Parameter Description
uuid String Unique identifier of the deposit.
fund_code String Code of the fund invested in.
fund_name String Name of the fund invested in.
amount Integer Original amount of the investment.
current_amount Decimal Current value of the investment.
units Decimal Units allocated for the investment.
status Enum: created, payment_made, submitted_to_rta, completed, error Status of the investment.
status_description String Reason in case of failure / rejections.
reinvest_mode Enum: payout: 'N', reinvestment: 'Y', growth: 'Z', bonus: 'B' What should happen with any dividend that is paid out.
partner_transaction_id String Your ID associated with the transaction.
user_completed_payment_at Datetime Time at which payment was completed by the user.
transferred_to_amc_at Datetime Time at which the payment was transferred to the AMC.
created_at Datetime Time at which the deposit was created.
sip_uuid String Identifier of the SIP that the deposit is part of.
stp_uuid String Identifier of the STP that the deposit is part of

Get deposits

curl "https://surface.thesavvyapp.in/secure/deposits?account_uuid=<UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns an array of deposit JSON objects.

HTTP Request

GET https://surface.thesavvyapp.in/secure/deposits?account_uuid=<UUID>

URL Parameters

Parameter Required Description
page true Integer Maximum of 25 records are returned per request. Specify the page you want to access.
account_uuid false String All deposits associated with a account.

Show deposit

curl "https://surface.thesavvyapp.in/secure/deposits/<UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns a deposit JSON object.

HTTP Request

GET https://surface.thesavvyapp.in/secure/deposits/<UUID>

Create deposit

// body
{ "deposit": 
  {
    "amount": "1000",
    "fund_code": "1234",
    "account_uuid": "aaaaa-bbbb-cccc-dddd",
    "onboarding_uuid": "aaaaa-bbbb-cccc-dddd",
    "payment_mode": "upi",
    "payment_redirect_url": "https://example.com/payment_redirect",
    "partner_transaction_id": "id",
  }
}
curl "https://surface.thesavvyapp.in/secure/deposits" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the deposit JSON object along with the payment URL

HTTP Request

POST https://surface.thesavvyapp.in/secure/deposits

Parameters

Parameter Required Description
amount true Integer Amount to be invested
fund_code true Date Code of the fund to be invested in
payment_redirect_url true String Where to direct the customer after payment. A field called status (as a query param) in the redirect URL will be available to indicate success or failure.
account_uuid false String If the deposit has to be created in an existing account.
onboarding_uuid false String Mandatory if account uuid is not specified.
payment_mode false Enum: upi, internet_banking By default, it is upi
partner_transaction_id false String Your custom ID to identify this transaction.

JSON response

Parameter Required Description
deposit true Object Deposit object
url true String URL to redirect the customer to for payment

Create basket of deposits

// body
{ "deposit": {
  "onboarding_uuid": "aaaaa-bbbb-cccc-dddd",
  "payment_redirect_url": "https://example.com/payment_redirect",
  "payment_mode": "upi",
  "deposit_parts": [
    {
      "amount": "1000",
      "fund_code": "1234",
      "amc_code": "IPRU",
      "account_uuid": "aaaaa-bbbb-cccc-dddd",
      "partner_transaction_id": "id",
    },
    {
      "amount": "100",
      "fund_code": "xyz",
      "amc_code": "IPRU",
      "account_uuid": "aaaaa-bbbb-cccc-dddd",
      "partner_transaction_id": "id",
    }
  ]}
}
curl "https://surface.thesavvyapp.in/secure/deposits/create_basket" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the deposit JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/deposits/create_basket

Parameters

Parameter Required Description
payment_redirect_url true String Where to direct the customer after payment. A field called status (as a query param) in the redirect URL will be available to indicate success or failure.
payment_mode false Enum: upi, internet_banking By default, it is upi
onboarding_uuid false String Mandatory if account uuid is not specified.
deposit_parts true Array [amount, fund_code, amc_code, account_uuid] to specify how much to invest in which funds

JSON response

Parameter Required Description
deposits true Objects Deposit object list
url true String URL to redirect the customer to for payment

Withdrawals

The withdrawals API describes how to create a mutual fund redemption transaction. This API can only be accessed post the onboarding flow. The workflow for creating and completing a redemption is:

graph TD; create_withdrawal(Create withdrawal with amount and fund details)-->verify_otp(Verify OTP on registered phone number and/or email) verify_otp-- Failure -->verify_otp; verify_otp-- Success-->listen(Listen for transaction updates via webhook);

Withdrawal object

Parameter Description
uuid String Unique identifier of the withdrawal.
account_uuid String Account which the withdrawal is part of.
fund_code String Code of the fund invested in.
fund_name String Name of the fund invested in.
amount Integer Amount to be withdrawn.
units Decimal Units withdrawn for the transaction.
status Enum: created, otp_complete, submitted_to_rta, completed, error Status of the withdrawal.
basket_transaction_id String Used in case of collections of withdrawals.
status_description String Reason in case of failure / rejections.
partner_transaction_id String Your ID associated with the transaction.
created_at Datetime Time at which the withdrawal was created.
swp_uuid String Identifier of the SIP that the withdrawal is part of.
stp_uuid String Identifier of the STP that the withdrawal is part of

Get withdrawals

curl "https://surface.thesavvyapp.in/secure/withdrawals?account_uuid=<UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns an array of withdrawal JSON objects.

HTTP Request

GET https://surface.thesavvyapp.in/secure/withdrawals?account_uuid=<UUID>

URL Parameters

Parameter Required Description
account_uuid true String All withdrawals associated with a account

Show withdrawal

curl "https://surface.thesavvyapp.in/secure/withdrawals/<UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns a withdrawal JSON object.

HTTP Request

GET https://surface.thesavvyapp.in/secure/withdrawals/<UUID>

Create withdrawal

// body
{ "withdrawal": 
  {
    "amount": "1000",
    "fund_code": "1234",
    "account_uuid": "aaaaa-bbbb-cccc-dddd",
    "partner_transaction_id": "xyv-abc"
  }
}
curl "https://surface.thesavvyapp.in/secure/withdrawals" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the withdrawal JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/withdrawals

On success, an OTP is sent on both the users' registered email and phone number. This OTP has to be verified by the user and sent to us on API.

Parameters

Parameter Required Description
amount true Decimal Amount to be invested
fund_code true Date Code of the fund to be invested in
account_uuid true String If the deposit has to be created in an existing account.
partner_transaction_id false String Your custom ID to identify this transaction.

Resend withdrawal OTP

// body
{}
curl "https://surface.thesavvyapp.in/secure/withdrawals/<UUID>/resend_otp" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the withdrawal JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/withdrawals/<UUID>/resend_otp

The OTP can be resent in case of delivery failures after 30 seconds of first attempt.

Verify withdrawal OTP

// body
{ "withdrawal": 
  {
    "otp": "123456",
    // For alternate mode:
    "pincode": "160019",
    "bank_account_number": "50028774999273"
  }
}
curl "https://surface.thesavvyapp.in/secure/withdrawals/<UUID>/verify_otp" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the withdrawal JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/withdrawals/<UUID>/verify_otp

On success, the status of the withdrawal will change to otp_complete. The OTP verification will expire in 5 minutes, and the OTP can be resent in case of delivery failures after 30 seconds of first attempt.

In case of OTP delivery failure (network / lost access to phone etc), there is a fallback mechanism where investors can verify by entering their pincode and bank account number. This should only be used a last resort. Do not verify OTPs continuously with this method, you will get banned.

Parameters

Parameter Required Description
otp false String The user inputted OTP
pincode false String For alternate verification process. Investors' address pincode
bank_account_number false String For alternate verification process. Investors' bank account number

Create basket withdrawal

// body
{ "withdrawal": {
    "onboarding_uuid": "aaaaa-bbbb-cccc-dddd",
    "withdrawal_parts": [
    {
      "amount": "1000",
      "fund_code": "1234",
      "amc_code": "IPRU",
      "account_uuid": "aaaaa-bbbb-cccc-dddd",
      "partner_transaction_id": "xyv-abc"
    }]
  },
  "allow_invalid_parts": true
}
curl "https://surface.thesavvyapp.in/secure/withdrawals/create_basket" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the withdrawal JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/withdrawals/create_basket

On success, an OTP is sent on both the users' registered email and phone number. This OTP has to be verified by the user and sent to us on API.

Parameters

Parameter Required Description
withdrawal true Object Withdrawal object
allow_invalid_parts false Boolean (default: false) If true, then invalid withdrawals will be ignored and only valid ones will get considered. If false, all withdrawal parts will get rejected if even one part is invalid.

Withdrawal:

Parameter Required Description
onboarding_uuid true String UUID of the onboarding
withdrawal_parts true Array Parts of the withdrawal

Withdrawal parts:

Parameter Required Description
amount true Decimal Amount to be invested.
amc_code true String Code of the amc.
fund_code true Date Code of the fund to be invested in.
account_uuid true String If the deposit has to be created in an existing account.

Verify basket withdrawal OTP

// body
{ "withdrawal": 
  {
    "otp": "123456"
  }
}
curl "https://surface.thesavvyapp.in/secure/withdrawals/<BASKET_TRANSACTION_ID>/verify_basket_otp" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the withdrawal JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/withdrawals/<BASKET_TRANSACTION_ID>/verify_basket_otp

On success, the status of the withdrawal will change to otp_complete. The OTP verification will expire in 5 minutes, and the OTP can be resent in case of delivery failures after 30 seconds of first attempt.

Parameters

Parameter Required Description
otp true String The user inputted OTP

One-click Checkout (OCC)

This API describes how to create instant investment links. This API can handle any scenario (existing folio, existing investor but no folio, and non-existing investor). This comes as a hosted solution under your logo.

OCC object

Parameter Description
account_uuid String Account associated with the investment.
masked_folio_number String Masked folio number, last 3 digits only.
fund_name String Name of the fund invested in.
amc_name String Name of AMC for the fund invested in.
checkout_type Enum: one_time, ongoing Whether the checkout type is a lumpsum or a SIP.
start_date Date Start date of the SIP.
end_date Date End date of the SIP.
frequency Enum: monthly, weekly, daily, ad-hoc Frequency of debits
amount Integer Amount of lumpsum or monthly instalment of SIP
deposit_request_id String Payment request ID of the investment.
deposit_status Enum: created, payment_made, submitted_to_rta, completed, error Status of the investment.
partner Object Partner details. See next table.
sip_request_id String Payment returnsuest ID of the SIP.
sip_mandate_status Enum: pending, accepted_by_user, completed, error, cancelled Status of the SIP auto-debit.
short_link URL string This URL can be shared with the user to go to for transaction completion.

Create OCC (Lumpsum)

// body
{ "one_click_checkout": 
  {
    "onboarding": {
      "name": "James Bond",
      "phone_number": "9800011111",
      "email": "email@example.com",
      "pan_number": "ABCDE1234C",
      "amc_code": "IPRU"
    },
    "account": {
      "folio_number": "12345678",
      "amc_code": "IPRU",
      "type": "SI"
    },
    "bank_account": {
      "account_number": "000111199999",
      "ifsc_code": "HDFC0000001",
      "bank_name": "HDFC BANK LTD"
    },
    "deposits": [{
      "amount": 1000,
      "fund_code": "10",
      "amc_code": "IPRU",
    },
    {
      "amount": 2000,
      "fund_code": "20",
      "amc_code": "IPRU"
    }]
  }
}
curl "https://surface.thesavvyapp.in/secure/one_click_checkouts" \
  -X POST \
  -d body
  -H "Authorization: Bearer <token>"

The above command returns a OCC JSON object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/one_click_checkouts

Parameters

Parameter Required Description
onboarding false Object Investor details
account false Object Account details
bank_account false Object Bank account details
deposits true Array[Object] Transaction details

Onboarding

Parameter Required Description
name true String Name of investor
phone_number true String Phone number of investor
email true String Email of investor
pan_number true String PAN of investor

Account

Parameter Required Description
folio_number true String Folio number of investor
amc_code true String AMC code of the folio
type true String Holding pattern of folio

Bank Account

Parameter Required Description
account_number true String Bank account number
ifsc_code true String IFSC code
bank_name true String Name of bank

Deposits (Array)

Parameter Required Description
amount true Integer Amount of the investment
fund_code true String Fund ID
amc_code true String AMC code

Create OCC (SIP)

// body
{ "one_click_checkout": 
  {
    "onboarding": {
      "name": "James Bond",
      "phone_number": "9800011111",
      "email": "email@example.com",
      "pan_number": "ABCDE1234C",
      "amc_code": "IPRU"
    },
    "account": {
      "folio_number": "12345678",
      "amc_code": "MOS",
      "type": "SI"
    },
    "bank_account": {
      "account_number": "000111199999",
      "ifsc_code": "HDFC0000001",
      "bank_name": "HDFC BANK LTD"
    },
    "sips": [{
      "amount": 1000,
      "fund_code": 10,
      "amc_code": "IPRU"
    },
    {
      "amount": 1000,
      "fund_code": 10,
      "amc_code": "IPRU"
    }],
    "sip_day": 1,
    "frequency": "monthly",
    "start_date": "25/12/2024"
  }
}
curl "https://surface.thesavvyapp.in/secure/one_click_checkouts/create_sip" \
  -X POST \
  -d body \
  -H "Authorization: Bearer <token>"

The above command returns a OCC JSON object.

HTTP Request

POST https://surface.thesavvyapp.in/secure/one_click_checkouts/create_sip

Parameters

Parameter Required Description
onboarding false Object Investor details
account false Object Account details
bank_account false Object Bank account details
sips true Array[Object] Transaction details
sip_day true Integer Day of the month that the SIP should be triggered
frequency true Enum Either "monthly" or "weekly"
start_date true Date Start date of the SIP. Minimum 2 business days from current date. Format: "DD/MM/YYYY".

Onboarding

Parameter Required Description
name true String Name of investor
phone_number true String Phone number of investor
email true String Email of investor
pan_number true String PAN of investor

Account

Parameter Required Description
folio_number true String Folio number of investor
amc_code true String AMC code of the folio
type true String Holding pattern of folio

Bank Account

Parameter Required Description
account_number true String Bank account number
ifsc_code true String IFSC code
bank_name true String Name of bank

SIPs (Array)

Parameter Required Description
amount true Integer
fund_code true String Fund ID
amc_code true String AMC code

Importing the SDK

Get the SDK from our CDN: https://cdn.savvyapp.in/lib/savvy.min.js

<script
  defer="defer"
  src="https://cdn.savvyapp.in/lib/savvy.min.js" />

Using the SDK

The SDK accepts a number of parameters, depending on what information is available to the merchant:

Staging library: https://cdn.savvyapp.in/lib/savvyJsStagingSDK.min.js

Production library: https://cdn.savvyapp.in/lib/savvyJsSDK.min.js

<script src="https://cdn.savvyapp.in/lib/savvyJsStagingSDK.min.js"></script>
<script>
  function doPayment() {
    var config = {
      isProduction: false, // If hitting UAT or production
      uuid: "uuid", // UUID from generated link on dashboard OR from API
      partnerAccessKey: "key", // Partner access key provided to you
      type: "one_click_checkout",
      amcCode: "",
      partnerTransactionId: "", // Unique ID generated by partner
      phoneNumber: "",
      panNumber: "",
      paymentSamePageRedirection: false,
      redirectUrl: "",
      onUserExit: (data) => {
        console.log("ON_USER_EXITED");
      },
      onError: () => {
        console.log("ON_ERROR_OCCURED");
      },
      onComplete: (data) => {
        console.log("ON_COMPLETE_OCCURED");
      },
      onPaymentUrlReceived: (data) => {
        console.log("ON_PAYMENT_URL_RECEIVED_OCCURED")
      }
    };
    var savvySDK = new SavvySDK(config);
    savvySDK.start();
  }
</script>
<div>
  <button onclick="doPayment()">Do Payment</button>
</div>

Generic Checkout

While the previously mentioned one-click-checkout is for a specific user and is a one-time use only, generic checkout is a way to make the same checkout experience, but for many users. This feature is currently available only on the dashboard, and not over API. SDK usage for embedding is described below:

Using the SDK

Create a new generic link on the dashboard. Then, pass in the generated UUID to the SDK to start the journey.

Staging library: https://cdn.savvyapp.in/lib/savvyJsStagingSDK.min.js

Production library: https://cdn.savvyapp.in/lib/savvyJsSDK.min.js

<script src="https://cdn.savvyapp.in/lib/savvyJsStagingSDK.min.js"></script>
<script>
  function doPayment() {
    var config = {
      isProduction: false, // If hitting UAT or production
      uuid: "uuid", // UUID from generated link on dashboard
      partnerAccessKey: "key", // Partner access key provided to you
      type: "generic_checkout",
      amcCode: "",
      partnerTransactionId: "", // Unique ID generated by partner
      phoneNumber: "",
      panNumber: "",
      paymentSamePageRedirection: "",
      redirectUrl: "",
      defaultMandateMax: 10000, // Default mandate maximum
      defaultTransactionType: 'sip', // If you want to show SIP or lumpsum first
      onUserExit: (data) => {
        console.log("ON_USER_EXITED");
      },
      onError: () => {
        console.log("ON_ERROR_OCCURED");
      },
      onComplete: (data) => {
        console.log("ON_COMPLETE_OCCURED");
      },
      onPaymentUrlReceived: (data) => {
        console.log("ON_PAYMENT_URL_RECEIVED_OCCURED")
      }
    };
    var savvySDK = new SavvySDK(config);
    savvySDK.start();
  }
</script>
<div>
  <button onclick="doPayment()">Do Payment</button>
</div>

Generic Checkout SDK object

Parameter Required Description
partnerAccessKey true String Access key provided to the partner.
type true String Type of checkout, in this case generic_checkout
isProduction true Boolean Production request or not
uuid true String UUID of the generic checkout.
partnerTransactionId false Unique ID of the partner. Gets put into the newly created onboarding.
onComplete(data) true Function() Callback hook on completion of SIP setup.
onUserExit true Function() Callback hook if user exited before completion.
onError true Function() Callback hook in case of error with the transaction.
phoneNumber false String Pass in the phone number if available
panNumber false String Pass in the PAN number if available. IMPORTANT: Must be uppercase.
paymentSamePageRedirection false Boolean In case you want to handle the payment flow. More on this below.
redirectUrl false String If using paymentSamePageRedirection, then specify which URL the user should land on post success / failure of the payment.
onPaymentUrlReceived false Function(data) Callback hook in case you would like to conduct the payment flow yourself. More on this below.
defaultMandateMax false Integer Default maximum for the mandate. If not specified, the default is zero.
defaultTransactionType false Enum: ['lumpsum', 'sip'] The transaction type you'd like to show first. If not specified, the default is lumpsum.

Payment flow

You can choose to let the SDK handle the payment flow. However, in certain cases this becomes a problem. For example, a lot of iOS users may have pop-ups turned off. Since the SDK utilizes a pop-up new window to do the payment flow, this can cause issues. Therefore, you can choose to conduct the payment flow yourself. The process is as follow:

  1. Pass paymentSamePageRedirection as true, and specify a URL in redirectUrl.
  2. Listen for onPaymentUrlReceived. The data object will contain a param called url where you will have to redirect.
  3. Redirect the user to the url received in the above callback.
  4. The user will land on the redirect URL you specify. A few params will be included in the URL: status and reason. The status can either be success or failure. If it's a failure, then the reason will also be specified.
  5. You can handle showing the status of the payment to use user as you see fit.

Mandates

This API describes how to create mandates for use with SIPs. This API can only be accessed post the onboarding flow.

Mandate object

Parameter Description
uuid String Unique identifier of the mandate.
start_date Date Start date of the mandate.
end_date Date End date of the mandate.
amount Integer Max amount that can be debited.
status Enum: null, pending, completed, error, cancelled Current status of the mandate

Create Mandate

// body
{ "mandate": 
  {
    "amount": "1000",
    "start_date": "30/01/2022",
    "end_date": "30/12/2022",
    "redirect_url": "https://example.com/redirect",
    "name": "John Smith",
    "email": "john@smith.com",
    "phone_number": "9888810000",
    "authentication_method": "debit_card",
    "mandate_gateway": "cashfree",
    "bank_account": {
      "account_number": "123456789",
      "ifsc_code": "HDFC0000873",
      "bank_name": "HDFC BANK LTD"
    }
  }
}
curl "https://surface.thesavvyapp.in/secure/mandates" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the mandate JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/mandates

On success, a payment url is sent. The user must be redirected to this url to sign the e-nach mandate.

NOTE: The link that will be generated must be embedded in the browser as a POST request. This means you cannot simply copy-paste the link into the browser URL input. You will have to make a dummy form. Example is as shown on the right

<!-- The <button> can be auto-triggered via javascript -->
<!DOCTYPE html>
<html id="savvy-html">
  <body>
    <form action="<URL HERE>" method="post">

      <button type="submit" value="Submit">
    </form>
  </body>
</html>

Parameters

Parameter Required Description
amount true Decimal Max amount of mandate
start_date true Date Start date of the mandate.
end_date true Date End date of the mandate.
redirect_url true URL String Where to direct the customer after payment. A field called status (as a query param) in the redirect URL will be available to indicate success or failure. Do not put query params in the redirect url.
mandate_gateway false Enum: billdesk (default), cashfree Specify the gateway to use.
authentication_method false Enum: net_banking (default), debit_card, upi_intent, upi_collect, upi_qr The auth method to use. Net banking will require a login to the internet banking page of the bank. Debit card will be authenticated directly with NPCI. UPI intent will give a list of URLs for various UPI apps. UPI QR will give a QR code for a user to scan with their app. UPI collect will send a push notification via the UPI app.
upi_vpa false String Required only in case authentication_method is upi_collect.
name true String Name of investor.
email true String Email of investor.
phone_number true String Phone number of investor.
bank_account true Object Must contain account_number, ifsc_code and bank_name

JSON response

Parameter Required Description
mandate true Objects Mandate object
url false String URL to redirect the customer to for signing the mandate in case of debit_card or net_banking. However, if mandate uuid is specified and valid, then a URL will not be returned.
message false String Sample message to show the user in case of upi_collect
urls false Object Only in case of upi_intent. This contains 2 fields: ios and android, each of which contain URLs for different UPI apps. Choose the appropriate one.
qr false String QR to display to the user in case of upi_qr

Systematic Investment Plans

This API describes how to create a SIP transaction. This API can only be accessed post the onboarding flow. The workflow for creating and registering an SIP is:

graph TD; create_sip(Create SIP with amount and fund details)-->create_mandate(Create E-Nach / UPI Mandate) create_mandate -->redirect_user(Redirect user to bank page); redirect_user-- Failure-->user_failure(Your failure page); user_failure -->create_mandate; redirect_user-- Success -->user_success(Your success page); user_success -->listen(Listen for mandate updates via webhook);

SIP object

Parameter Description
uuid String Unique identifier of the SIP.
account_uuid String Account which the SIP is part of.
fund_code String Code of the fund invested in.
fund_name String Name of the fund invested in.
start_date Date Start date of the SIP.
end_date Date End date of the SIP.
sip_day Integer Day of the month / week when the SIP will be triggered.
frequency Enum: monthly, weekly, daily, ad-hoc Frequency of debits
amount Integer Amount to be deposited at each installment.
payment_link String Only applicable for create API URL to which to take the user for mandate checkout.
mandate_redirect_url String Where to direct the customer after payment. A field called status (as a query param) in the redirect URL will be available to indicate success or failure.
active Boolean Whether the SIP is actively debiting.
partner_transaction_id String Your ID associated with the transaction.
created_at Datetime Time at which the SIP was created.

Get sips

curl "https://surface.thesavvyapp.in/secure/sips?account_uuid=<UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns an array of sip JSON objects.

HTTP Request

GET https://surface.thesavvyapp.in/secure/sips?account_uuid=<UUID>

URL Parameters

Parameter Required Description
account_uuid true String All sips associated with a account

Show sip

curl "https://surface.thesavvyapp.in/secure/sips/<UUID>" \
  -X GET \
  -H "Authorization: Bearer <token>"

The above command returns a sip JSON object.

HTTP Request

GET https://surface.thesavvyapp.in/secure/sips/<UUID>

Create sip

// body
{ "sip": 
  {
    "amount": "1000",
    "fund_code": "1234",
    "account_uuid": "aaaaa-bbbb-cccc-dddd",
    "onboarding_uuid": "aaaaa-bbbb-cccc-dddd",
    "partner_transaction_id": "xyv-abc",
    "start_date": "30/01/2022",
    "end_date": "30/12/2022",
    "sip_day" : 5,
    "mandate_gateway": "cashfree",
    "authentication_method": "debit_card",
    "frequency": "monthly",
    "mandate_uuid": "aaaaa-bbbb-cccc-dddd",
    "mandate_redirect_url": "https://example.com/redirect"
  }
}
curl "https://surface.thesavvyapp.in/secure/sips" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the sip JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/sips

If mandate_uuid is specified, then the mandate will be used for the SIP. If no mandate_uuid is specified, then on success, a payment url is sent. The user must be redirected to this url to sign the e-nach mandate required for periodic auto-debits.

NOTE: The link that will be generated must be embedded in the browser as a POST request. This means you cannot simply copy-paste the link into the browser URL input. You will have to make a dummy form. Example is as shown on the right

<!-- The <button> can be auto-triggered via javascript -->
<!DOCTYPE html>
<html id="savvy-html">
  <body>
    <form action="<URL HERE>" method="post">

      <button type="submit" value="Submit">
    </form>
  </body>
</html>

Parameters

Parameter Required Description
amount true Decimal Amount to be invested
fund_code true Date Code of the fund to be invested in
account_uuid false String If the SIP has to be created in an existing account.
onboarding_uuid false String If the SIP has to be created in a new account.
partner_transaction_id false String Your custom ID to identify this transaction.
start_date true Date Start date of the SIP.
end_date true Date End date of the SIP.
sip_day false Integer Day of the month / week when the SIP will be triggered.
frequency true Enum: monthly, weekly, daily, ad-hoc Frequency of debits
mandate_uuid false String UUID of an existing mandate.
mandate_gateway false Enum: billdesk (default), cashfree Specify the gateway to use.
authentication_method false Enum: net_banking (default), debit_card, upi_intent, upi_collect, upi_qr The auth method to use. Net banking will require a login to the internet banking page of the bank. Debit card will be authenticated directly with NPCI. UPI intent will give a list of URLs for various UPI apps. UPI QR will give a QR code for a user to scan with their app. UPI collect will send a push notification via the UPI app.
upi_vpa false String Required only in case authentication_method is upi_collect.
mandate_redirect_url true URL String Where to direct the customer after payment. A field called status (as a query param) in the redirect URL will be available to indicate success or failure.

Create basket of SIPs

// body
{ "sip": {
  "onboarding_uuid": "aaaaa-bbbb-cccc-dddd",
  "mandate_uuid": "aaaaa-bbbb-cccc-dddd",
  "mandate_redirect_url": "https://example.com/redirect",
  "start_date": "30/01/2022",
  "end_date": "30/12/2022",
  "sip_day": 5,
  "frequency": "monthly",
  "mandate_gateway": "cashfree",
  "authentication_method": "debit_card",
  "mandate_max_amount": "10000",
  "sip_parts": [
    {
      "amount": "1000",
      "fund_code": "1234",
      "amc_code": "IPRU",
      "account_uuid": "aaaaa-bbbb-cccc-dddd",
      "partner_transaction_id": "id",
    },
    {
      "amount": "100",
      "fund_code": "xyz",
      "amc_code": "IPRU",
      "account_uuid": "aaaaa-bbbb-cccc-dddd",
      "partner_transaction_id": "id",
    }
  ]}
}
curl "https://surface.thesavvyapp.in/secure/sips/create_basket" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the deposit JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/sips/create_basket

Parameters

Parameter Required Description
onboarding_uuid false String If the SIP has to be created in a new account.
start_date true Date Start date of the SIP.
end_date true Date End date of the SIP.
frequency true Enum: monthly, weekly, daily, ad-hoc Frequency of debits
mandate_uuid false String UUID of an existing mandate.
mandate_redirect_url true URL String Where to direct the customer after payment. A field called status (as a query param) in the redirect URL will be available to indicate success or failure.
mandate_gateway false Enum: billdesk (default), cashfree Specify the gateway to use.
authentication_method false Enum: net_banking (default), debit_card, upi_intent, upi_collect, upi_qr The auth method to use. Net banking will require a login to the internet banking page of the bank. Debit card will be authenticated directly with NPCI. UPI intent will give a list of URLs for various UPI apps. UPI QR will give a QR code for a user to scan with their app. UPI collect will send a push notification via the UPI app.
upi_vpa false String Required only in case authentication_method is upi_collect.
mandate_max_amount false Integer By default this will be the amount of the basket.
sip_parts true Array [amount, fund_code, amc_code, account_uuid] to specify how much to invest in which funds

JSON response

Parameter Required Description
sips true Objects Deposit object list
url false String URL to redirect the customer to for signing the mandate in case of debit_card or net_banking. However, if mandate uuid is specified and valid, then a URL will not be returned.
message false String Sample message to show the user in case of upi_collect
urls false Object Only in case of upi_intent. This contains 2 fields: ios and android, each of which contain URLs for different UPI apps. Choose the appropriate one.
qr false String QR to display to the user in case of upi_qr

Cancel sip

// body
{}
curl "https://surface.thesavvyapp.in/secure/sips/<UUID>/cancel" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the sip JSON object

HTTP Request

POST https://surface.thesavvyapp.in/secure/sips/<UUID>/cancel

This API cancels an existing SIP. Note that cancellation is not instant. The AMC will communicate the cancellation within 24 hours of the request being registered. However, the API will stop accepting new requests on the cancelled SIP instantly.

Systematic Withdrawal Plans

This API describes how to create a SWP transaction. This API can only be accessed post the onboarding flow. The workflow for creating and registering an SWP is:

graph TD; create_swp(Create SWP with amount and fund details)-->verify_otp(Verify OTP on registered phone number and/or email) verify_otp-- Failure -->verify_otp; verify_otp-- Success-->listen(Listen for transaction updates via webhook);

SWP Object

Coming Soon!

Systematic Transfer Plans

This API describes how to create a STP transaction, for periodic transfers from one fund to another in the same or different accounts. This API can only be accessed post the onboarding flow. The workflow for creating and registering an STP is:

graph TD; create_stp(Create STP with amount and fund details)-->verify_otp(Verify OTP on registered phone number and/or email) verify_otp-- Failure -->verify_otp; verify_otp-- Success-->listen(Listen for transaction updates via webhook);

STP Object

Coming soon!

Save Now, Buy Later (SNBL)

SNBL is a unique proposition, where customers can save up (via SIP) to purchase products from merchants. This service is provided as an SDK to merchants so they can embed SNBL inside their purchase journeys. The solution is available on both API and SDK. For the API, please refer to the following workflow:

graph TD; create_onboarding(Create onboarding)-->complete_otp(Complete OTP process of the onboarding); complete_otp-->do_kyc(Do KYC of the onboarding); do_kyc-->create_sip(Make SIP and complete mandate setup); create_sip -->create_saving_goal(Create saving goal);

Authentication

Please refer to the start of the documentation for details on how to authenticate to the API. The first 4 steps must be completed using the Onboarding & SIP/mandate APIs.

Saving Goal object

Parameter Description
uuid String Unique identifier of the goal.
saving_events JSON: {}
description String Title / description of the goal.
end_date Date End date of the goal.
amount Integer Amount of the goal.
sip Object The SIP attached to the goal. Refer to the SIP object earlier.

Create Saving goal

// body
{ "saving_goal":
  {
    "amount": 1000,
    "description": "MMT - Leh Vacation",
    "end_date": "30/12/2022",
    "saving_events": [{ "date": "01/01/2023", "amount": 100 }, { "date": "01/02/2023", "amount": 100 }],
    "sip_id": "1"
  }
}
curl "https://surface.thesavvyapp.in/snbl/saving_goals" \
  -X POST \
  -H "Authorization: Bearer <token>" \
  -d body

The above command returns the goal JSON object

HTTP Request

POST https://surface.thesavvyapp.in/snbl/saving_goals

Please note that the SIP must be created before the saving goal is created.

Parameters

Parameter Required Description
amount true Decimal Amount to be invested
end_date true Date End date of the SIP.

SDK

Importing the SDK

Get the SDK from our CDN: https://cdn.savvyapp.in/lib/savvypayCoreSDK.min.js

<script
  defer="defer"
  src="https://cdn.savvyapp.in/lib/savvypayCoreSDK.min.js" />

Using the SDK

The SDK accepts a number of parameters, depending on what information is available to the merchant:

<script>
  function doPayment() {
      var config = {
        key: "XXXXX-XXXXX",
        offerUuid: "XXXXX-XXXXX",
        isProduction: false,
        isDisplayDetail: false,
        minAmount: 10000,
        maxAmount: 20000,
        endDate: "DD/MM/YYYY",
        productName: "Mauritius Vacation",
        multiplier: 1,
        amcCode: 'IPRU',
        merchantLogo: 'https://www.logo.com',
        merchantName: 'Name',
        onComplete: (data) => {
          console.log("ON_COMPLETE_OCCURED", data);
          alert("Savvy completed successfully!");
        },
        onUserExit: () => {
          console.log("ON_USER_EXITED");
        }}

      var savvySDK = new SavvySDK(config);
        savvySDK.start();
    }
  }
</script>
...

<button onclick="doPayment()">Do Payment</button>

Track investment SDK usage

After SNBL setup, a customer may want to track their investment. In this case, pass one extra option, isDisplayDetail as true to the same SDK:

<script>
  function showTracker() {
      var config = {
        key: "XXXXX-XXXXX",
        isProduction: false,
        isDisplayDetail: true,
        amcCode: 'IPRU',
        merchantLogo: 'https://www.logo.com',
        merchantName: 'Name',
        onUserExit: () => {
          console.log("ON_USER_EXITED");
        }}

      var savvySDK = new SavvySDK(config);
        savvySDK.start();
    }
  }
</script>
...

<button onclick="showTracker()">Show Tracker</button>

SNBL SDK object

Parameter Required Description
key true String API key provided to the merchant.
offerUuid true String Product offer uuid. This can be static, or dynamic. It is either created by the merchant at purchase time, or created by Savvy and provided to the merchant.
isProduction true Boolean Production request or not
isDisplayDetail false Boolean Whether to open in track investment mode or not.
minAmount false Decimal Min amount, if the amount is a range.
maxAmount false Decimal Max amount, if the amount is a range, or the exact amount in case there is no range.
endDate false Date Targeted purchase date of the product.
productName false String Name of the product being purchased.
multiplier false Integer The amount of products being bought.
amcCode true String Code of the AMC being used.
merchantLogo: true String Image for the merchant logo.
merchantName: true String Name of the merchant.
onComplete(data) true Function Callback hook on completion of SIP setup.
onUserExit true Function Callback hook if user exited before completion.

AMC name & fund

This API is used for displaying the name of the fund, AMC name and link.

curl "https://surface.thesavvyapp.in/amcs/<AMC_CODE>/name_and_liquid_fund" \
  -X GET \
  -H "X-PARTNER-ACCESS-KEY: <YOUR KEY>"

The above command returns a JSON object.

HTTP Request

GET https://surface.thesavvyapp.in/amcs/<AMC_CODE>/name_and_liquid_fund

Response parameters

Parameter Description
amc_name AMC name
amc_logo Link to amc logo
liquid_fund Name of the fund
liquid_fund_link Link to the fund

Risk Profiling

To improve the user experience in terms of fund selection, we offer a risk profiling API that takes customer profile information + a couple of risk related questions as inputs to output a maximum of 4 funds. While designed by our in-house MF experts, this API is provided "as-is", without any guarantees of correctness.

Calculators

We offer a stand-alone API for advanced calculations. The various types of calculations are listed below:

Authentication

The auth mechanism for the calculators is a bit simpler than the rest of the API. To authorize, you must pass your API access key as a header as shown on the right. The relevant header is X-PARTNER-ACCESS-KEY

curl -XGET "https://surface.thesavvyapp.in/calculators/..." \
  -H "X-PARTNER-ACCESS-KEY: <key>"

SIP returns for historical custom time ranges

This API will help you calculate XIRR returns for custom time ranges for all schemes available on the Savvy API. Note this API has a rate limit of 10 per minute for each partner. Please message for a rate limit increase.

HTTP Request

GET https://surface.thesavvyapp.in/calculators/sip_returns

URL parameters

Parameter Required Description
amc_code true String Code of the AMC
fund_code true String Code of the scheme
start_date true Date (DD/MM/YYYY) Start date of the SIP (note this must be post the scheme start date)
end_date true Date (DD/MM/YYYY) End date of the SIP (note this cannot be after today's date)
monthly_amount true Decimal Amount of money to put in every month

SIP returns for future time ranges

This API will help you calculate future expected IRR returns for custom time ranges. This is applicable for all schemes available on the Savvy API. Note this API has a rate limit of 10 per minute for each partner. Please message for a rate limit increase.

Potential gotcha: There is no start date available. We assume in this API that the start date is always Today's date.

HTTP Request

GET https://surface.thesavvyapp.in/calculators/future_sip_returns

URL parameters

Parameter Required Description
amc_code false String Code of the AMC
fund_code false String Code of the scheme
end_date true Date (DD/MM/YYYY) End date of the SIP (note this cannot be after today's date)
monthly_amount true Decimal Amount of money to put in every month
irr false Decimal If a scheme is not specified, a custom irr can also be specified.

Reports

We offer aggregated reports accross multiple categories for easy reconciliation and customer viewing.

Frontend SDKs

For non-distributors, we offer the ability to use readymade SDKs for offering mutual fund onboarding and transactions. This exposes no private data of the customer. Marketing and non-fintech usecases should use this.

We also offer SDKs for simplified purchase transactions. Instead of redirecting the user to another page for payments, the SDK will allow you to complete the transaction on your assets itself.

Webhooks

The webhooks API is an essential part of the Savvy API. There are several long running tasks and asynchronos activites that occur in the processing of onboardings and mutual fund transactions. For you to provide a good user experience, we offer webhooks that give you async updates about various activities you do via the Savvy API.

Webhook structure

Parameter Description
event String Unique identifier of the withdrawal.
sent_at Datetime Time at which the SIP was created.
payload JSON Data sent as part of webhook.
signature String SHA265 signature of the JSON payload.

Events

Event Description
onboardings.create Sent when an onboarding is created
deposits.create Sent when a deposit is created
deposits.status.update Sent when a deposit status is updated. Use this for tracking success / failure of deposit transactions.
accounts.create Sent when a folio number is allocated (folio number is equivalent to new account creation).
withdrawals.create Sent when a withdrawal is created
withdrawals.status.update Sent when a withdrawal status is updated. Use this for tracking success / failure of withdrawal transactions.
funds.create Sent when a new NFO is created.

Webhook authentication

To make sure that the webhook is coming from Savvy, we append a signature to all webhooks in the signature parameter. The signature is a HMAC-SHA256 hash of the payload JSON string using your secret key:

HMAC('sha256', secret_key, payload)

Make sure to verify this signature before using the payload.

Webhook structure

Onboardings

// body
{
  "onboarding": {
    "partner_transaction_id": "aaa-vvv",
    "uuid": "aa-bb-cc-dd",
    "amc_code": "DSP",
    "existing_investor": false,
    "full_kyc_status": "pending",
    "esign_success": false,
    "esign_error": "User cancelled E-sign",
  }
}

Deposits

// body
{
  "deposit": {
    "onboarding_uuid": "aaa-bbb-ddd",
    "uuid": "aa-bb-cc-ff",
    "amount": 100,
    "fund": "<Fund object: plz see above>",
    "status": "completed"
  }
}

Accounts

// body
{
  "account": {
    "onboarding_uuid": "aaa-vvv-www",
    "uuid": "aa-dd-ff"
  }
}

Funds

// body
{
  "fund": {"COMPLETE FUND OBJECT. PLEASE REFER ABOVE"},
  "nfo_details": {
    "is_nfo": "true",
    "nfo_start_date": "31/01/2023",
    "nfo_end_date": "31/03/2023",
    "nfo_restart_date": "10/04/2023"
  }
}

Enums

Annual Income Codes

Code Description
31 Below 1 Lac
32 1-5 Lacs
33 5-10 Lacs
34 10-25 Lacs
35 25 Lacs-1 crore
36 1 crore

Gender Codes

Code Description
M Male
F Female
T Transgender

Occupation Codes

Code Description
01 Private Sector
02 Public Sector
03 Business
04 Professional
06 Retired
07 Housewife
08 Student
10 Government Sector
99 Others
11 Self Employed
12 Not Categorized

Address Types

Code Description
01 Residential or Business
02 Residential
03 Business
04 Registered Office

Marital Status Codes

Code Description
MARRIED Married
UNMARRIED Unmarried
OTHERS Others

FATCA Sources of Wealth

Code Description
01 Salary
02 Business
03 Gift
04 Ancestral Property
05 Rental Income
06 Prize Money
07 Royalty
08 Others

Application status codes and description

Code Description
R Resident Indian
N Non-Resident Indian
P Foreign National
I Person of Indian Origin

FATCA country codes

Code Description
AF Afghanistan
AX Aland Islands
AL Albania
DZ Algeria
AS American Samoa
AD Andorra
AO Angola
AI Anguilla
AQ Antarctica
AG Antigua And Barbuda
AR Argentina
AM Armenia
AW Aruba
AU Australia
AT Austria
AZ Azerbaijan
BS Bahamas
BH Bahrain
BD Bangladesh
BB Barbados
BY Belarus
BE Belgium
BZ Belize
BJ Benin
BM Bermuda
BT Bhutan
BO Bolivia
BQ Bonaire, Sint Eustatius And Saba
BA Bosnia And Herzegovina
BW Botswana
BV Bouvet Island
BR Brazil
IO British Indian Ocean Territory
BN Brunei Darussalam
BG Bulgaria
BF Burkina Faso
BI Burundi
KH Cambodia
CM Cameroon
CA Canada
CV Cape Verde
KY Cayman Islands
CF Central African Republic
TD Chad
CL Chile
CN China
CX Christmas Island
CC Cocos (Keeling) Islands
CO Colombia
KM Comoros
CG Congo
CD Congo, The Democratic Republic Of The
CK Cook Islands
CR Costa Rica
CI Cote D'Ivoire
HR Croatia
CU Cuba
CW Curacao
CY Cyprus
CZ Czech Republic
DK Denmark
DJ Djibouti
DM Dominica
DO Dominican Republic
EC Ecuador
EG Egypt
SV El Salvador
GQ Equatorial Guinea
ER Eritrea
EE Estonia
ET Ethiopia
FK Falkland Islands (Malvinas)
FO Faroe Islands
FJ Fiji
FI Finland
FR France
GF French Guiana
PF French Polynesia
TF French Southern Territories
GA Gabon
GM Gambia
GE Georgia
DE Germany
GH Ghana
GI Gibraltar
GR Greece
GL Greenland
GD Grenada
GP Guadeloupe
GU Guam
GT Guatemala
GG Guernsey
GN Guinea
GW Guinea-Bissau
GY Guyana
HT Haiti
HM Heard Island And Mcdonald Islands
HN Honduras
HK Hong Kong
HU Hungary
IS Iceland
IN India
ID Indonesia
IR Iran, Islamic Republic Of
IQ Iraq
IE Ireland
IM Isle Of Man
IL Israel
IT Italy
JM Jamaica
JP Japan
JE Jersey
JO Jordan
KZ Kazakhstan
KE Kenya
KI Kiribati
KP Korea, Democratic People's Republic Of
KR Korea, Republic Of
KW Kuwait
KG Kyrgyzstan
LA Lao People's Democratic Republic
LV Latvia
LB Lebanon
LS Lesotho
LR Liberia
LY Libyan Arab Jamahiriya
LI Liechtenstein
LT Lithuania
LU Luxembourg
MO Macao
MK Macedonia, The Former Yugoslav Republic Of
MG Madagascar
MW Malawi
MY Malaysia
MV Maldives
ML Mali
MT Malta
MH Marshall Islands
MQ Martinique
MR Mauritania
MU Mauritius
YT Mayotte
MX Mexico
FM Micronesia, Federated States Of
MD Moldova, Republic Of
MC Monaco
MN Mongolia
ME Montenegro
MS Montserrat
MA Morocco
MZ Mozambique
MM Myanmar
NA Namibia
NR Nauru
NP Nepal
NL Netherlands
AN Netherlands Antilles
NC New Caledonia
NZ New Zealand
NI Nicaragua
NE Niger
NG Nigeria
NU Niue
NF Norfolk Island
MP Northern Mariana Islands
NO Norway
XX Not categorised
OM Oman
ZZ Others
PK Pakistan
PW Palau
PS Palestinian Territory, Occupied
PA Panama
PG Papua New Guinea
PY Paraguay
PE Peru
PH Philippines
PN Pitcairn
PL Poland
PT Portugal
PR Puerto Rico
QA Qatar
RE Reunion Island
RO Romania
RU Russian Federation
RW Rwanda
BL Saint Barthelemy
SH Saint Helena, Ascension And Tristan da Cunha
KN Saint Kitts And Nevis
LC Saint Lucia
MF Saint Martin
PM Saint Pierre And Miquelon
VC Saint Vincent And The Grenadines
WS Samoa
SM San Marino
ST Sao Tome And Principe
SA Saudi Arabia
SN Senegal
RS Serbia
SC Seychelles
SL Sierra Leone
SG Singapore
SX Sint Maarten (Dutch Part)
SK Slovakia
SI Slovenia
SB Solomon Islands
SO Somalia
ZA South Africa
GS South Georgia And The South Sandwich Islands
SS South Sudan
ES Spain
LK Sri Lanka
SD Sudan
SR Suriname
SJ Svalbard And Jan Mayen Islands
SZ Swaziland
SE Sweden
CH Switzerland
SY Syrian Arab Republic
TW Taiwan, Province Of China
TJ Tajikistan
TZ Tanzania, United Republic Of
TH Thailand
TL Timor-Leste
TG Togo
TK Tokelau
TO Tonga
TT Trinidad And Tobago
TN Tunisia
TR Turkey
TM Turkmenistan
TC Turks And Caicos Islands
TV Tuvalu
UG Uganda
UA Ukraine
AE United Arab Emirates
GB United Kingdom
US United States
UM United States Minor Outlying Islands
UY Uruguay
UZ Uzbekistan
VU Vanuatu
VA Vatican City State
VE Venezuela, Bolivarian Republic Of
VN Viet Nam
VG Virgin Islands, British
VI Virgin Islands, U.S.
WF Wallis And Futuna
EH Western Sahara
YE Yemen
ZM Zambia
ZW Zimbabwe

Country Codes

Code Description
India 101
Albania 003
Aland Islands 002
Afghanistan 001
Algeria 004
American Samoa 005
Andorra 006
Angola 007
Anguilla 008
Antarctica 009
Antigua And Barbuda 010
Argentina 011
Armenia 012
Aruba 013
Australia 014
Austria 015
Azerbaijan 016
Bahamas 017
Bahrain 018
Bangladesh 019
Barbados 020
Belarus 021
Belgium 022
Belize 023
Benin 024
Bermuda 025
Bhutan 026
Bolivia 027
Bosnia And Herzegovina 028
Botswana 029
Bouvet Island 030
Brazil 031
British Indian Ocean Territory 032
Brunei Darussalam 033
Bulgaria 034
Burkina Faso 035
Burundi 036
Cambodia 037
Cameroon 038
Canada 039
Cape Verde 040
Cayman Islands 041
Central African Republic 042
Chad 043
Chile 044
China 045
Christmas Island 046
Cocos (Keeling) Islands 047
Colombia 048
Comoros 049
Congo 050
Congo, The Democratic Republic Of The 051
Cook Islands 052
Costa Rica 053
Cote D'Ivoire 054
Croatia 055
Cuba 056
Cyprus 057
Czech Republic 058
Denmark 059
Djibouti 060
Dominica 061
Dominican Republic 062
Ecuador 063
Egypt 064
El Salvador 065
Equatorial Guinea 066
Eritrea 067
Estonia 068
Ethiopia 069
Falkland Islands (Malvinas) 070
Faroe Islands 071
Fiji 072
Finland 073
France 074
French Guiana 075
French Polynesia 076
French Southern Territories 077
Gabon 078
Gambia 079
Georgia 080
Germany 081
Ghana 082
Gibraltar 083
Greece 084
Greenland 085
Grenada 086
Guadeloupe 087
Guam 088
Guatemala 089
Guernsey 090
Guinea 091
Guinea-Bissau 092
Guyana 093
Haiti 094
Heard Island And Mcdonald Islands 095
Holy See (Vatican City State) 096
Honduras 097
Hong Kong 098
Hungary 099
Iceland 100
Indonesia 102
Iran, Islamic Republic Of 103
Iraq 104
Ireland 105
Isle Of Man 106
Israel 107
Italy 108
Jamaica 109
Japan 110
Jersey 111
Jordan 112
Kazakhstan 113
Kenya 114
Kiribati 115
Korea, Democratic People’s Republic Of 116
Korea, Republic Of 117
Kuwait 118
Kyrgyzstan 119
Lao People’s Democratic Republic 120
Latvia 121
Lebanon 122
Lesotho 123
Liberia 124
Libyan Arab Jamahiriya 125
Liechtenstein 126
Lithuania 127
Luxembourg 128
Macao 129
Macedonia, The Former Yugoslav Republic Of 130
Madagascar 131
Malawi 132
Malaysia 133
Maldives 134
Mali 135
Malta 136
Marshall Islands 137
Martinique 138
Mauritania 139
Mauritius 140
Mayotte 141
Mexico 142
Micronesia, Federated States Of 143
Moldova, Republic Of 144
Monaco 145
Mongolia 146
Montserrat 147
Morocco 148
Mozambique 149
Myanmar 150
Namibia 151
Nauru 152
Nepal 153
Netherlands 154
Netherlands Antilles 155
New Caledonia 156
New Zealand 157
Nicaragua 158
Niger 159
Nigeria 160
Niue 161
Norfolk Island 162
Northern Mariana Islands 163
Norway 164
Oman 165
Pakistan 166
Palau 167
Palestinian Territory, Occupied 168
Panama 169
Papua New Guinea 170
Paraguay 171
Peru 172
Philippines 173
Pitcairn 174
Poland 175
Portugal 176
Puerto Rico 177
Qatar 178
Reunion 179
Romania 180
Russian Federation 181
Rwanda 182
Saint Helena 183
Saint Kitts And Nevis 184
Saint Lucia 185
Saint Pierre And Miquelon 186
Saint Vincent And The Grenadines 187
Samoa 188
San Marino 189
Sao Tome And Principe 190
Saudi Arabia 191
Senegal 192
Serbia And Montenegro 193
Seychelles 194
Sierra Leone 195
Singapore 196
Slovakia 197
Slovenia 198
Solomon Islands 199
Somalia 200
South Africa 201
South Georgia And The South Sandwich Islands 202
Spain 203
Sri Lanka 204
Sudan 205
Suriname 206
Svalbard And Jan Mayen 207
Swaziland 208
Sweden 209
Switzerland 210
Syrian Arab Republic 211
Taiwan, Province Of China 212
Tajikistan 213
Tanzania, United Republic Of 214
Thailand 215
Timor-Leste 216
Togo 217
Tokelau 218
Tonga 219
Trinidad And Tobago 220
Tunisia 221
Turkey 222
Turkmenistan 223
Turks And Caicos Islands 224
Tuvalu 225
Uganda 226
Ukraine 227
United Arab Emirates 228
United Kingdom 229
United States 230
United States Minor Outlying Islands 231
Uruguay 232
Uzbekistan 233
Vanuatu 234
Venezuela 235
Viet Nam 236
Virgin Islands, British 237
Virgin Islands, U.S. 238
Wallis And Futuna 239
Western Sahara 240
Yemen 241
Zambia 242
Zimbabwe 243
Côte D'ivoire CI
Korea,Democratic People'sRepublicOf KP
Lao People’s Democratic Republic 12

Errors

The Savvy API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API key is wrong.
403 Forbidden -- The API requested is hidden for administrators only.
404 Not Found -- The specified API / object could not be found.
405 Method Not Allowed -- You tried to access an API with an invalid method.
406 Not Acceptable -- You requested a format that isn't json.
410 Gone -- The API requested has been removed from our servers.
418 I'm a teapot.
429 Too Many Requests -- You're making too many requests! Slow down!
500 Internal Server Error -- We had a problem with our server. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.