In this tutorial we will take our first steps with the Bloom API, learning the main concepts and fetching our first credit report.

We will go through the necessary steps to get onboarded, authenticate, and call the Bloom API. It is recommended to have familiarity with scripting and/or programming as well as general concepts of HTTP before starting.

# Authenticating with the API

## Getting Credentials

To start the authentication process with the Bloom API, make sure you have both a `client_id` and `client_secret` ready to be used. Using these credentials, you will be able to generate the `access token` used to authenticate your API calls.

> 📘
>
> ### If you don't have credentials yet, [contact us](https://www.bloomcredit.io/contact-us) to get onboarded onto our platform.

## Environments

In this tutorial, we will be working with the `Sandbox` environment and its endpoints, where we will use training data. To learn more about environments and get information on moving to productions read [Environments Overview](https://developers.bloomcredit.io/docs/environments-1).

## Getting an access token

Access tokens are keys used to authenticate all Bloom API calls. You can generate tokens using the `https://authn.bloomcredit.dev/oauth/token` endpoint in the following way:

> Here you need to replace `$CLIENT_ID` and `$CLIENT_SECRET` with the credentials fetched earlier.
>
> Replace `$SCOPE` as following:
>
> - Set as "data-access:all" for accessing Data Access endpoints.
> - Set as "furnishment:all" for accessing Furnishment endpoints.
> - Set "data-access:all furnishment:all" for accessing both Data Access and Furnishment endpoints.
> - You also need to use an `$AUDIENCE`, for the Sandbox environment, the audience is set to `dev-api`.

```shell
curl --location --request POST 'https://authn.bloomcredit.dev/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=$CLIENT_ID' \
--data-urlencode 'client_secret=$CLIENT_SECRET' \
--data-urlencode 'audience=$AUDIENCE' \
--data-urlencode 'scope=$SCOPE' \
--data-urlencode 'grant_type=client_credentials'
```

```javascript
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");

var urlencoded = new URLSearchParams();
urlencoded.append("client_id", "$CLIENT_ID");
urlencoded.append("client_secret", "$CLIENT_SECRET");
urlencoded.append("audience", "$AUDIENCE");
urlencoded.append("scope", "$SCOPE");
urlencoded.append("grant_type", "client_credentials");

var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  body: urlencoded,
  redirect: 'follow'
};

fetch("https://authn.bloomcredit.dev/oauth2/token", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
```

```python
import requests

url = "https://authn.bloomcredit.dev/oauth2/token"

client_id = "$CLIENT_ID"
client_secret = "$CLIENT_SECRET"
audience = "$AUDIENCE"
scope = "$SCOPE"
payload= f'client_id={client_id}&client_secret={client_secret}&audience={audience}&scope={scope}&grant_type=client_credentials'

headers = {
  'Content-Type': 'application/x-www-form-urlencoded'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)
```

```go
package main

import (
  "fmt"
  "strings"
  "net/http"
  "io/ioutil"
)

func main() {

url := "https://authn.bloomcredit.dev/oauth2/token"
  method := "POST"

payload := strings.NewReader("client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&audience=$AUDIENCE&scope=$SCOPE&grant_type=client_credentials")

client := &http.Client {}
  req, err := http.NewRequest(method, url, payload)

if err != nil {
    fmt.Println(err)
    return
  }
  req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

res, err := client.Do(req)
  if err != nil {
    fmt.Println(err)
    return
  }
  defer res.Body.Close()

body, err := ioutil.ReadAll(res.Body)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(string(body))
}
```

A successful call will yield the following response, containing the `access_token` used for the subsequent calls:

```json
{
    "access_token": "<ACCESS_TOKEN_WILL_BE_HERE>",
    "scope": "data-access:all furnishment:all",
    "expires_in": 86400,
    "token_type": "Bearer"
}
```

## Using the access token

To use the access token fetched in the previous step, include it in your HTTP Headers as follows:

Authorization Header

```curl
Authorization: Bearer <ACCESS_TOKEN>
```

## Refreshing the access token

An access token expires after a defined time (this can be seen in the response of the `/oauth2/token` call).

Once your access token is expired, retrieve a new one using the `/oauth2/token` API once again.

# Fetching your organization's portfolios

[Organizations](https://developers.bloomcredit.io/docs/organizations) are representations of companies. They contain multiple [Portfolios](https://developers.bloomcredit.io/docs/portfolios) which represent Credit Products managed by a company.

Before creating an entity for the customer you want a credit report for, you first need to know which Portfolio the consumer belongs to within your Organization.

To do so, run the following API call to the `https://sandbox.bloom.dev/v2/core/organization` endpoint. This endpoint will return all portfolios available under your organization:

> replace the `$ACCESS_TOKEN` with the previously created access token
>
> For more details, see the [API Reference](https://developers.bloomcredit.io/reference/coreget-organization) .

```shell
curl --request GET \
     --url https://sandbox.bloom.dev/v2/core/organization \
     --header 'accept: application/json' \
     --header 'authorization: Bearer $ACCESS_TOKEN'
```

```javascript
const sdk = require('api')('@bloomcredit/v2.0#1z6kflqx2qpgd');

sdk.auth('$ACCESS_TOKEN');
sdk.coreGetOrganization()
  .then(({ data }) => console.log(data))
  .catch(err => console.error(err));
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://sandbox.bloom.dev/v2/core/organization")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["accept"] = 'application/json'
request["authorization"] = 'Bearer $ACCESS_TOKEN'

response = http.request(request)
puts response.read_body
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://sandbox.bloom.dev/v2/core/organization', [
  'headers' => [
    'accept' => 'application/json',
    'authorization' => 'Bearer $ACCESS_TOKEN',
  ],
]);

echo $response->getBody();
```

```python
import requests

url = "https://sandbox.bloom.dev/v2/core/organization"

headers = {
    "accept": "application/json",
    "authorization": "Bearer $ACCESS_TOKEN"
}

response = requests.get(url, headers=headers)

print(response.text)
```

Here is an example response for a successful call:

```json
{
  "data": {
    "id": "<organization_id>",
    "type": "organizations",
    "attributes": {
      "name": "Your organization name",
      "is_active": false,
      "hubspot_company_id": "<hubspot_company_id>",
      "consumer_address_normalization_rule": "OVERRIDE",
      "portfolios": [
        {
          "id": "<portfolio_id>",
          "name": "<portfolio_name>",
          "type": "CREDIT_CARD",
          "data_access_retention": 129600,
          "furnishment_retention": 2630880
        }
      ]
    }
  }
}
```

Store the `<portfolio_id>` of the chosen portfolio to be used in the next step.

# Creating a consumer

[Consumers](https://developers.bloomcredit.io/docs/consumers-1) are representations of persons within the Bloom API. To order a credit report for a consumer, you first need to submit their information to Bloom.

To do so, create the consumer using the `https://sandbox.bloom.dev/v2/core/consumers` API:

> Here we are using test data to create a consumer
>
> Make sure to replace `$ACCESS_TOKEN` with a previously generated access token.

```shell
curl --location --request POST 'https://sandbox.bloom.dev/v2/core/consumers' \
--header 'Authorization: Bearer $ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": {
        "type": "consumers",
        "attributes": {
            "ssn": "666018517",
            "date_of_birth": "1986-4-17",
            "emails": [
                {
                    "email_address": "consumeremail@up.com",
                    "primary": true
                }
            ],
            "name": {
                "first_name": "Miranda",
                "middle_name": "E",
                "last_name": "Smith"
            },
            "addresses": [
                {
                    "line1": "4189 E Garford St",
                    "line2": "EXT",
                    "city": "BLACK CREEK",
                    "state_code": "NC",
                    "zipcode": "27813",
                    "primary": true
                }
            ]
        }
    }
}'
```

```javascript
// npm install api --save
const sdk = require('api')('@bloomcredit/v2.0#5a1mg2ulle8xc1g');

sdk.auth('$ACCESS_TOKEN');
sdk.createConsumerV2({
  data: {
    attributes: {
      name: {first_name: 'Miranda', last_name: 'Smith', middle_name: 'E'},
      addresses: [
        {
          city: 'BLACK CREEK',
          line1: '4189 E Garford St',
          line2: 'EXT',
          state_code: 'NC',
          primary: true,
          zipcode: '27813'
        }
      ],
      date_of_birth: '1986-4-17',
      ssn: '666018517'
    },
    type: 'consumers'
  }
})
  .then(({ data }) => console.log(data))
  .catch(err => console.error(err));
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://sandbox.bloom.dev/v2/core/consumers")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["accept"] = 'application/json'
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer $ACCESS_TOKEN'
request.body = "{\"data\":{\"attributes\":{\"name\":{\"first_name\":\"Miranda\",\"last_name\":\"Smith\",\"middle_name\":\"E\"},\"addresses\":[{\"city\":\"BLACK CREEK\",\"line1\":\"4189 E Garford St\",\"line2\":\"EXT\",\"state_code\":\"NC\",\"primary\":true,\"zipcode\":\"27813\"}],\"date_of_birth\":\"1986-4-17\",\"ssn\":\"666018517\"},\"type\":\"consumers\"}}"

response = http.request(request)
puts response.read_body
```

```php
// composer require guzzlehttp/guzzle
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://sandbox.bloom.dev/v2/core/consumers', [
  'body' => '{"data":{"attributes":{"name":{"first_name":"Miranda","last_name":"Smith","middle_name":"E"},"addresses":[{"city":"BLACK CREEK","line1":"4189 E Garford St","line2":"EXT","state_code":"NC","primary":true,"zipcode":"27813"}],"date_of_birth":"1986-4-17","ssn":"666018517"},"type":"consumers"}}',
  'headers' => [
    'accept' => 'application/json',
    'authorization' => 'Bearer $ACCESS_TOKEN',
    'content-type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```python
import requests

url = "https://sandbox.bloom.dev/v2/core/consumers"

payload = { "data": {
        "attributes": {
            "name": {
                "first_name": "Miranda",
                "last_name": "Smith",
                "middle_name": "E"
            },
            "addresses": [
                {
                    "city": "BLACK CREEK",
                    "line1": "4189 E Garford St",
                    "line2": "EXT",
                    "state_code": "NC",
                    "primary": True,
                    "zipcode": "27813"
                }
            ],
            "date_of_birth": "1986-4-17",
            "ssn": "666018517"
        },
        "type": "consumers"
    } }
headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "authorization": "Bearer $ACCESS_TOKEN"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
```

Upon a successful consumer creation, you will receive a response containing the `id` of the consumer.

Here is an example of the response.

```json
{
    "data": {
        "id": "<consumer_id>",
        "type": "consumers",
        "attributes": {
            "ssn": "666018517",
            "date_of_birth": "1986-04-17",
            "name": {
                "first_name": "Miranda",
                "middle_name": "E",
                "last_name": "Smith"
            },
            "emails": [
                {
                    "email_address": "consumeremail@up.com",
                    "primary": true
                }
            ],
            "addresses": [
                {
                    "id": "<address_id>",
                    "line1": "4189 E Garford St",
                    "line2": "EXT",
                    "city": "BLACK CREEK",
                    "state_code": "NC",
                    "zipcode": "27813",
                    "primary": true
                }
            ]
        }
    }
}
```

Store the `<consumer_id>` for the next step, as it will be needed to order a credit report for that consumer.

# Ordering a credit report

Once your consumer is created, you can order a credit report via the Bloom API. This order will be made for Bloom to fetch the credit report for your order.

Here is a sample for ordering a credit report, using the `https://sandbox.bloom.dev/v2/data-access/orders` endpoint:

> We use the previously fetched `consumer_id` and `portfolio_id` for this call, also we authenticate this call using the previously generated `$ACCESS_TOKEN`.
>
> For more details, see the [API Reference](https://developers.bloomcredit.io/reference/data-accessnew-order).

```shell
curl --location --request POST 'https://sandbox.bloom.dev/v2/data-access/orders' \
--header 'Authorization: Bearer $ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": {
        "type": "order",
        "attributes": {
            "consumer_id": "<consumer_id>",
            "portfolio_id": "<portfolio_id>",
            "sku": "equifax-bronze-soft-vantage-internet"
        }
    }
}'
```

```javascript
// npm install api --save
const sdk = require('api')('@bloomcredit/v2.0#1760q2tlqgyl8um');

sdk.auth('$ACCESS_TOKEN');
sdk.dataAccessNewOrder({
  data: {
    attributes: {
      consumer_id: '<consumer_id>',
      portfolio_id: '<portfolio_id>',
      sku: 'equifax-bronze-soft-vantage-internet'
    },
    type: 'order'
  }
})
  .then(({ data }) => console.log(data))
  .catch(err => console.error(err));
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://sandbox.bloom.dev/v2/data-access/orders")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["accept"] = 'application/json'
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer $ACCESS_TOKEN'
request.body = "{\"data\":{\"attributes\":{\"consumer_id\":\"<consumer_id>\",\"portfolio_id\":\"<portfolio_id>\",\"sku\":\"equifax-bronze-soft-vantage-internet\"},\"type\":\"order\"}}"

response = http.request(request)
puts response.read_body
```

```php
// composer require guzzlehttp/guzzle
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://sandbox.bloom.dev/v2/data-access/orders', [
  'body' => '{"data":{"attributes":{"consumer_id":"<consumer_id>","portfolio_id":"<portfolio_id>","sku":"equifax-bronze-soft-vantage-internet"},"type":"order"}}',
  'headers' => [
    'accept' => 'application/json',
    'authorization' => 'Bearer $ACCESS_TOKEN',
    'content-type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```python
import requests

url = "https://sandbox.bloom.dev/v2/data-access/orders"

payload = { "data": {
        "attributes": {
            "consumer_id": "<consumer_id>",
            "portfolio_id": "<portfolio_id>",
            "sku": "equifax-bronze-soft"
        },
        "type": "orders"
    } }
headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "authorization": "Bearer $ACCESS_TOKEN"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
```

Here is a sample success response for the previous call:

```json
{
    "data": {
        "type": "orders",
        "id": "<order_id>",
        "attributes": {
            "consumer_id": "<consumer_id>",
            "sku": "equifax-silver-soft-vantage-internet",
            "order_placed": "2024-04-13T14:19:16.37393Z",
            "order_filled": "2024-04-13T14:19:17.655478427Z",
            "order_updated": "2024-04-13T14:19:17.659033043Z",
            "status": "SUCCESS",
            "status_code": "30",
            "status_message": "Hit",
            "status_details": "https://developers.bloomcredit.io/docs/status-codes#30"
        }
    }
}
```

Store the `<order_id>` for the next step, as it will be needed to fetch the report.

# Fetching a full report

Once credit data has been ordered and successfully fulfilled, you can use the Bloom API to fetch a full credit data report. To do so, use the `https://sandbox.bloom.dev/v2/data-access/orders/<order_id>/full-report` endpoint. A full-report contains all information collected regarding a credit data order for a single consumer:

> Replace `<order_id>` with the previously fetched id and authenticate this call using the previously generated `$ACCESS_TOKEN`

```shell
curl --request GET \
     --url https://sandbox.bloom.dev/v2/data-access/orders/<order_id>/full-report \
     --header 'accept: application/json' \
     --header 'authorization: Bearer $ACCESS_TOKEN'
```

```javascript
// npm install api --save
const sdk = require('api')('@bloomcredit/v2.0#es0dinlt7kfibt');

sdk.auth('$ACCESS_TOKEN');
sdk.getOrdersOrderidFullReport({orderId: '<order_id>'})
  .then(({ data }) => console.log(data))
  .catch(err => console.error(err));
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://sandbox.bloom.dev/v2/data-access/orders/<order_id>/full-report")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["accept"] = 'application/json'
request["authorization"] = 'Bearer $ACCESS_TOKEN'

response = http.request(request)
puts response.read_body
```

```php
// composer require guzzlehttp/guzzle
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://sandbox.bloom.dev/v2/data-access/orders/<order_id>/full-report', [
  'headers' => [
    'accept' => 'application/json',
    'authorization' => 'Bearer $ACCESS_TOKEN',
  ],
]);

echo $response->getBody();
```

```python
import requests

url = "https://sandbox.bloom.dev/v2/data-access/orders/%3Corder_id%3E/full-report"

headers = {
    "accept": "application/json",
    "authorization": "Bearer $ACCESS_TOKEN"
}

response = requests.get(url, headers=headers)

print(response.text)
```

This call will return a response containing the full data for the previously ordered credit report. Here is a sample snippet for a response:

```json
{
    "credit_data_order": null,
    "tradeline_attributes": [
        {
            "total_tradelines": null,
            "open_tradelines": null,
            "tradeline_open_last_3_months": null,
            "tradeline_open_last_6_months": null,
            "tradeline_open_last_9_months": null,
            "tradeline_open_last_12_months": null,
...cont.
```

# What's next

Through this tutorial, we had an overview of the interactions with the Bloom API, from authentication through creating consumers and ordering credit reports for them. This is only the first step and there are many more features available through the API to access credit data information of your consumers.

For further reading, see:

- [Batch Ordering](https://developers.bloomcredit.io/docs/batch-ordering), for ways to order credit data for multiple consumers at predefined cadence.
- [Credit Data Concepts](https://developers.bloomcredit.io/docs/credit-reports), to learn about all data available within the credit reports.
- [Querying Reports](https://developers.bloomcredit.io/docs/querying-reports), for ways to search and query precisely into reports.
