The project is in a healthy, maintained state
DocFox exposes the nCino KYC DocFox API endpoints through Active Call service objects.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme

Active Call - nCino KYC DocFox

Gem Version

DocFox exposes the nCino KYC DocFox API endpoints through Active Call service objects.

  • Installation
  • Configuration
  • Usage
    • Using call
    • Using call!
    • When to use call or call!
    • Using lists
  • Service Objects
  • Development
  • Contributing
  • License

Installation

Install the gem and add to the application's Gemfile by executing:

bundle add active_call-doc_fox

If bundler is not being used to manage dependencies, install the gem by executing:

gem install active_call-doc_fox

Configuration

Configure your API credentials.

In a Rails application, the standard practice is to place this code in a file named doc_fox.rb within the config/initializers directory.

require 'active_call-doc_fox'

DocFox::BaseService.configure do |config|
  config.api_key = ''
  config.secret = ''

  # Optional configuration.
  config.cache = Rails.cache # Default: ActiveSupport::Cache::MemoryStore.new
  config.logger = Rails.logger # Default: Logger.new($stdout)
  config.logger_level = :debug # Default: :info
  config.log_headers = true # Default: false
  config.log_bodies = true # Default: false
end

Usage

Using call

Each service object returned will undergo validation before the call method is invoked to access API endpoints.

After successful validation.

service.success? # => true
service.errors # => #<ActiveModel::Errors []>

After failed validation.

service.success? # => false
service.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=id, type=blank, options={}>]>
service.errors.full_messages # => ["Id can't be blank"]

After a successful call invocation, the response attribute will contain a Faraday::Response object.

service.success? # => true
service.response # => #<Faraday::Response ...>
service.response.success? # => true
service.response.status # => 200
service.response.body # => {"data"=>{"id"=>"aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "type"=>"kyc_application", "attributes"=>{}}, ...}

At this point you will also have a facade object which will hold all the attributes for the specific resource.

service.facade # => #<DocFox::KycApplication::Facade @kyc_entity_type_name="South African Citizen" ...>
service.facade.kyc_entity_type_name # => 'South African Citizen'

For convenience, facade attributes can be accessed directly on the service object.

service.kyc_entity_type_name # => 'South African Citizen'

After a failed call invocation, the response attribute will still contain a Faraday::Response object.

service.success? # => false
service.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=base, type=not_found, options={}>]>
service.errors.full_messages # => ["Not Found"]
service.response # => #<Faraday::Response ...>
service.response.success? # => false
service.response.status # => 404
service.response.body # => {"errors"=>[{"title"=>"not_found", "status"=>"404", "detail"=>"The resource you requested could not be found"}]}

Using call!

Each service object returned will undergo validation before the call! method is invoked to access API endpoints.

After successful validation.

service.success? # => true

After failed validation, a DocFox::ValidationError exception will be raised with an errors attribute which will contain an ActiveModel::Errors object.

rescue DocFox::ValidationError => exception
  exception.message # => ''
  exception.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=id, type=blank, options={}>]>
  exception.errors.full_messages # => ["Id can't be blank"]

After a successful call! invocation, the response attribute will contain a Faraday::Response object.

service.success? # => true
service.response # => #<Faraday::Response ...>
service.response.success? # => true
service.response.status # => 200
service.response.body # => {"data"=>{"id"=>"aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "type"=>"kyc_application", "attributes"=>{}}, ...}

At this point you will also have a facade object which will hold all the attributes for the specific resource.

service.facade # => #<DocFox::KycApplication::Facade @kyc_entity_type_name="South African Citizen" ...>
service.facade.kyc_entity_type_name # => 'South African Citizen'

For convenience, facade attributes can be accessed directly on the service object.

service.kyc_entity_type_name # => 'South African Citizen'

After a failed call! invocation, a DocFox::RequestError will be raised with a response attribute which will contain a Faraday::Response object.

rescue DocFox::RequestError => exception
  exception.message # => 'Not Found'
  exception.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=base, type=not_found, options={}>]>
  exception.errors.full_messages # => ["Not Found"]
  exception.response # => #<Faraday::Response ...>
  exception.response.status # => 404
  exception.response.body # => {"errors"=>[{"title"=>"not_found", "status"=>"404", "detail"=>"The resource you requested could not be found"}]}

When to use call or call!

An example of where to use call would be in a controller doing an inline synchronous request.

class SomeController < ApplicationController
  def update
    @service = DocFox::KycApplication::UpdateService.call(**params)

    if @service.success?
      redirect_to [@service], notice: 'Success', status: :see_other
    else
      flash.now[:alert] = @service.errors.full_messages.to_sentence
      render :edit, status: :unprocessable_entity
    end
  end
end

An example of where to use call! would be in a job doing an asynchronous request.

You can use the exceptions to determine which retry strategy to use and which to discard.

class SomeJob < ApplicationJob
  discard_on DocFox::NotFoundError

  retry_on DocFox::RequestTimeoutError, wait: 5.minutes, attempts: :unlimited
  retry_on DocFox::TooManyRequestsError, wait: :polynomially_longer, attempts: 10

  def perform
    DocFox::KycApplication::UpdateService.call!(**params)
  end
end

Using lists

If you don't provide the per_page argument, multiple API requests will be made untill all records have been returned. You could be rate limited, so use wisely.

Service Objects

KYC Applications

KYC Applications

List KYC applications

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications/get

DocFox::KycApplication::ListService.call(page: 1, per_page: 10).each do |facade|
  facade.id
end

Filter by names, numbers contact information or external refs.

DocFox::KycApplication::ListService.call(search_term: 'eric.cartman@example.com').map { _1 }

Get a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D/get

service = DocFox::KycApplication::GetService.call(id: '')
service.id
service.approved_at
service.archived
service.created_at
service.status
service.relationships.dig('profile', 'data', 'id')
service.relationships.dig('data_requirements', 'links', 'related')
...

Include related resources.

managed_by, profile.additional_details, profile.addresses, profile.contacts, profile.names, profile.numbers, parent_related_entities, onboarding_token_summary, onboarding_token_summary.status_summaries, onboarding_token_summary.data_requirement_summaries, onboarding_token_summary.kyc_entity_template_designation_schema, onboarding_token_summary.parent_related_entity_designation_summary, onboarding_token_summary.parent_onboarding_token_summary, onboarding_token_summary.relationship_builder_config

service = DocFox::KycApplication::GetService.call(id: '', params: { include: 'managed_by,profile.names' })
service.included

Create a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications/post

DocFox::KycApplication::CreateService.call(
  data: {
    type: 'kyc_application',
    attributes: {
      kyc_entity_template_id: 'aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb',
      names: {
        first_names: 'Eric Theodore',
        last_names: 'Cartman'
      },
      # ...more fields following the schema definitions.
    }
  }
)

Approve a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D~1approve/patch

DocFox::KycApplication::ApproveService.call(id: '')

Unapprove a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D~1unapprove/patch

DocFox::KycApplication::UnapproveService.call(id: '', reason: '')

Transfer a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D~1transfer/patch

DocFox::KycApplication::TransferService.call(id: '', transfer_to_user_id: '')

Archive a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D~1archive/post

DocFox::KycApplication::ArchiveService.call(id: '', reason: '')

Unarchive a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D~1unarchive/post

DocFox::KycApplication::UnarchiveService.call(id: '', reason: '')

Delete a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Applications/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D/delete

DocFox::KycApplication::DeleteService.call(id: '')
Status Summaries

Status Summaries

Get a status summary of a KYC application

# https://www.docfoxapp.com/api/v2/documentation#tag/Status-Summaries/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D~1status_summaries/get

service = DocFox::StatusSummary::GetService.call(id: '')
service.id
service.overall_kyc_application_status
service.module_statuses
...
Profiles

Profiles

List profiles

# https://www.docfoxapp.com/api/v2/documentation#tag/Profiles/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D~1profiles/get

DocFox::Profile::ListService.call(kyc_application_id: '', page: 1, per_page: 10).each do |facade|
  facade.id
end

Get a profile

# https://www.docfoxapp.com/api/v2/documentation#tag/Profiles/paths/~1api~1v2~1profiles~1%7Bprofile_id%7D/get

service = DocFox::Profile::GetService.call(id: '')
service.id
service.created_at
...

Include related resources.

additional_details, addresses, contacts, contacts.invitation_tokens, names, numbers

service = DocFox::Profile::GetService.call(id: '', params: { include: 'names,numbers,additional_details' })
service.included
Data Requirements

Data Requirements

List data requirements

# https://www.docfoxapp.com/api/v2/documentation#tag/Data-Requirements/paths/~1api~1v2~1kyc_applications~1%7Bkyc_application_id%7D~1data_requirements/get

DocFox::DataRequirement::ListService.call(kyc_application_id: '', page: 1, per_page: 10).each do |facade|
  facade.id
end

List only data requirements for forms.

DocFox::DataRequirement::ListService.call(kyc_application_id: '', forms: true).map { _1 }

List data requirements associated with an account application

# https://www.docfoxapp.com/api/v2/documentation#tag/Data-Requirements/paths/~1api~1v2~1account_applications~1%7Baccount_application_id%7D~1data_requirements/get

DocFox::DataRequirement::ListService.call(account_application_id: '', page: 1, per_page: 10).each do |facade|
  facade.id
end

List only data requirements for forms.

DocFox::DataRequirement::ListService.call(account_application_id: '', forms: true).map { _1 }

Get a data requirement

# https://www.docfoxapp.com/api/v2/documentation#tag/Data-Requirements/paths/~1api~1v2~1data_requirements~1%7Bdata_requirement_id%7D/get

service = DocFox::DataRequirement::GetService.call(id: '')
service.id
service.created_at
service.form
service.name
service.required
service.slug
service.valid_evidence_types
...

Include related resources.

evidence_submissions, active_evidence_submission, active_evidence_submission.form, active_evidence_submission.form.active_form_datum

service = DocFox::DataRequirement::GetService.call(id: '', params: { include: 'evidence_submissions,active_evidence_submission' })
service.included
KYC Entity Templates

KYC Entity Templates

List KYC entity templates

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Entity-Templates/paths/~1api~1v2~1kyc_entity_templates/get

DocFox::KycEntityTemplate::ListService.call(page: 1, per_page: 10).each do |facade|
  facade.id
end

Get a KYC entity template

# https://www.docfoxapp.com/api/v2/documentation#tag/KYC-Entity-Templates/paths/~1api~1v2~1kyc_entity_templates~1%7Bkyc_entity_template_id%7D/get

service = DocFox::KycEntityTemplate::GetService.call(id: '')
service.id
service.kyc_entity_type_name
service.kyc_entity_type_category
service.created_at
service.profile_schema
...
Evidence Submissions

Evidence Submissions

List evidence submissions

# https://www.docfoxapp.com/api/v2/documentation#tag/Evidence-Submissions/paths/~1api~1v2~1data_requirements~1%7Bdata_requirement_id%7D~1evidence_submissions/get

DocFox::EvidenceSubmission::ListService.call(data_requirement_id: '', page: 1, per_page: 10).each do |facade|
  facade.id
end

Get an evidence submission

# https://www.docfoxapp.com/api/v2/documentation#tag/Evidence-Submissions/paths/~1api~1v2~1evidence_submissions~1%7Bevidence_submission_id%7D/get

service = DocFox::EvidenceSubmission::GetService.call(id: '')
service.id
service.evidence_type
service.form
service.status
service.created_at
service.attributes
...

Include related resources.

document: the related document, for document evidence submission
qualitative_checks: the related qualitative checks, for document evidence submission
rejection_reasons: the related rejection reasons
form: the related form, for form evidence submission
form.active_form_datum: the related form and its latest data submission, for form evidence submission

service = DocFox::EvidenceSubmission::GetService.call(id: '', params: { include: 'document,qualitative_checks' })
service.included

Update an evidence submission

At the moment this is used only to add third party data to an external evidence submission for a specific third party provider.

# https://www.docfoxapp.com/api/v2/documentation#tag/Evidence-Submissions/paths/~1api~1v2~1evidence_submissions~1%7Bevidence_submission_id%7D/patch

DocFox::EvidenceSubmission::UpdateService.call(
  id: '',
  data: {
    type: 'evidence_submission',
    id: '',
    attributes: {
      results: {
        dob: '1984-01-01',
        gender: 'M',
        surname: 'Cartman',
        forename1: 'Eric',
        forename2: nil,
        id_number: '8401017223183',
        addresses: {
          address: [
            {
              addr_type: 'R',
              addr_line1: '28201 E. Bonanza St.',
              addr_line2: '',
              addr_line3: '',
              addr_line4: 'South Park',
              addr_postal_code: '8000',
              addr_update_date: '2017-11-21'
            }
          ]
        },
        telephones: {
          telephone: [
            {
              tel_num: '27715555555',
              tel_type: 'Cell',
              tel_update_date: '2017-09-05'
            }
          ]
        },
        deceased_date: nil,
        deceased_flag: 'N',
        verified_date: '2015-06-23',
        verified_flag: 'Y',
        deceased_reason: nil
      }
    }
  }
)

Reject an active evidence submission

# https://www.docfoxapp.com/api/v2/documentation#tag/Evidence-Submissions/paths/~1api~1v2~1evidence_submissions~1%7Bevidence_submission_id%7D~1reject/patch

DocFox::EvidenceSubmission::RejectService.call(id: '', reason: '')

Approve an active evidence submission

# https://www.docfoxapp.com/api/v2/documentation#tag/Evidence-Submissions/paths/~1api~1v2~1evidence_submissions~1%7Bevidence_submission_id%7D~1approve/patch

DocFox::EvidenceSubmission::ApproveService.call(id: '')

Replace an active evidence submission

# https://www.docfoxapp.com/api/v2/documentation#tag/Evidence-Submissions/paths/~1api~1v2~1evidence_submissions~1%7Bevidence_submission_id%7D~1replace/patch

DocFox::EvidenceSubmission::ReplaceService.call(id: '')
Documents

Documents

List documents

# https://www.docfoxapp.com/api/v2/documentation#tag/Documents/paths/~1api~1v2~1evidence_submissions~1%7Bevidence_submission_id%7D~1documents/get

DocFox::Document::ListService.call(evidence_submission_id: '', page: 1, per_page: 10).each do |facade|
  facade.id
end

Get a document

# https://www.docfoxapp.com/api/v2/documentation#tag/Documents/paths/~1api~1v2~1documents~1%7Bdocument_id%7D/get

service = DocFox::Document::GetService.call(id: '')
service.id
service.created_at
service.content_type
service.filename
service.token
service.token_expiry
service.uploaded_by
...

Include related resources.

evidence_submissions

service = DocFox::Document::GetService.call(id: '', params: { include: 'evidence_submissions' })
service.included
Document Tokens

Document Tokens

List document tokens

# https://www.docfoxapp.com/api/v2/documentation#tag/Document-Tokens/paths/~1api~1v2~1documents~1%7Bdocument_id%7D~1document_tokens/get

DocFox::DocumentToken::ListService.call(document_id: '', page: 1, per_page: 10).each do |facade|
  facade.id
end

Get a document token

# https://www.docfoxapp.com/api/v2/documentation#tag/Document-Tokens/paths/~1api~1v2~1document_tokens~1%7Bdocument_token_id%7D/get

service = DocFox::DocumentToken::GetService.call(id: '')
service.id
service.created_at
service.expiry
service.content_type
...

Create a document token

# https://www.docfoxapp.com/api/v2/documentation#tag/Document-Tokens/paths/~1api~1v2~1documents~1%7Bdocument_id%7D~1document_tokens/post

DocFox::DocumentToken::CreateService.call(
  document_id: '',
  data: {
    type: 'document_token'
  }
)
Download Documents

Download Documents

Download a document file

# https://www.docfoxapp.com/api/v2/documentation#tag/Download-Documents/paths/~1api~1v2~1document_file_downloads~1%7Bdocument_token_id%7D/get

service = DocFox::Document::DownloadService.call(document_token_id: '', content_type: 'image/jpeg')
service.response.body # => "\xFF\xD8\xFF\xDB\x00\x84\x00\x04\x05\x..."

Possible values for content_type.

  • image/jpeg
  • image/png
  • application/pdf

You can also provide just the document_id and the service will automatically request the document_token_id and content_type for you.

service = DocFox::Document::DownloadService.call(document_id: '')
service.response.body # => "\xFF\xD8\xFF\xDB\x00\x84\x00\x04\x05\x..."
Document Uploads

Document Uploads

Upload a document file

# https://www.docfoxapp.com/api/v2/documentation#tag/Document-Uploads/paths/~1api~1v2~1evidence_submissions~1%7Bevidence_submission_id%7D~1documents/post

DocFox::Document::UploadService.call(
  evidence_submission_id: '',
  data: {
    type: 'document',
    attributes: {
      evidence_type: 'taxes_paid_in_prior_quarter',
      filename: 'taxes_paid.png',
      document_data: "data:image/png;base64,#{Base64.encode64(File.read('/path/to/taxes_paid.png'))}"
    }
  }
)
Users

Users

List users

# https://www.docfoxapp.com/api/v2/documentation#tag/Users/paths/~1api~1v2~1users/get

DocFox::User::ListService.call(page: 1, per_page: 10).each do |facade|
  facade.id
end

Get a user

# https://www.docfoxapp.com/api/v2/documentation#tag/Users/paths/~1api~1v2~1users~1%7Buser_id%7D/get

service = DocFox::User::GetService.call(id: '')
service.id
service.email
service.first_names
service.last_names
service.deactivated
...

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/kobusjoubert/doc_fox.

License

The gem is available as open source under the terms of the MIT License.