Integrating ServiceNow with HipChat

My tutorial on integrating [ServiceNow] with [Slack] turned out to be one of my most popular articles ever. Justin Meader recently asked me on Twitter how easy it would be to integrate Service­Now with [HipChat] instead.

@joeyday Hey Joey, I found your article on integrating Slack with Service­Now, and it’s very helpful.

— Justin Meader (@justinmeader) May 13, 2015

@joeyday We’re a HipChat shop, and I was wondering how difficult it would be to adapt the include script for HipChat? I’m not a coder sadly.

— Justin Meader (@justinmeader) May 13, 2015

So, I gave it a whirl. In this article I’ll show you how you can post Service­Now notifications right into HipChat using their API. Just like in the previous tutorial, I’ll give you a ready-made Service­Now Script Include and instructions and examples for how you can call that Script Include from any scripted Business Rule.

Getting access to the HipChat API

To get started, you’ll need an endpoint URL for the HipChat API to which Service­Now can send web service calls. To get this URL, go to HipChat’s Integrations page:

HipChat Integrations Page

Scroll to the bottom and click “Set Up An Integration”:

HipChat Set Up An Integration

If you’re not already logged you may be asked to do so, then click the “Create” button under “Build Your Own!”:

HipChat Build Your Own Integration

On the next screen, choose the room you want to use and the name of the bot as you’d like it to appear whenever it posts, then click “Create”:

HipChat Choose the Room and Name Your Integration Bot

On the next screen, you should see a URL like the below:

https://api.hipchat.com/v2/room/xxxxxxx/notification?auth_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Save this URL someplace safe. I’ll show you where to use it in a bit. HipChat doesn’t require any kind of authentication to use this API, so the token in this URL essentially is your password. Keep it a secret.

Creating the REST Message in ServiceNow

The first step in Service­Now is to set up a REST Message. If you’re running Fuji you can actually skip this step and go straight to the Script Include, as the new RESTMessageV2 API in Fuji doesn’t require a REST Message database record. If you’re still on Eureka or want to keep the integration backwards-compatible with earlier releases for any reason, read on.

  1. Navigate to System Web ServicesOutboundREST Messages in your Service­Now instance.
  2. Click “New” to create a new REST Message.
    • Type “HipChat” for the name.
    • Click the lock icon to unlock the Endpoint field and type “${endpoint}” there.
    • Type something useful in the Description field if you go for that sort of thing.
  3. Right-click in the header and choose “Save” to submit the new record and stay where you are.
  4. At the bottom of the newly-saved record, there will be a related list containing REST Message Functions, of which there should be four: “get”, “post”, “put”, and “delete”. Check the box to the left of all these but “post” and use the drop-down at the bottom to delete them. The only one we need to keep here is the “post” function.
  5. Click into the “post” function.
    • Verify the Endpoint here is also set to “${endpoint}” (it should’ve inherited this setting from the parent REST Message).
    • Insert an HTTP Header row Name “Content-Type” and Value “application/json”.
    • In the Content field, type “${payload}”.
  6. Click “Update”.

That’s it, the REST Message and REST Message Function should be ready to go.

The Script Include

To create the Script Include, follow these steps:

  1. Navigate to System DefinitionScript Includes in your Service­Now instance.
  2. Click “New”.
    • Name the Script Include “HipChatNotification”.
    • Give it a description if you want.
    • Copy and paste the script below.
  3. Click “Submit”.

Here’s the script itself:
[code language=”javascript”]var HipChatNotification = Class.create();

HipChatNotification.prototype = {
‘initialize’: function() {},

‘send’: function (message, endpoint) {
// Set the text and channel (or fall back to defaults)
this.payload.message = message || this.payload.message;
this.endpoint = endpoint || this.endpoint;

// Encode the payload as JSON
var SNJSON = JSON; // Workaround for JSLint warning about using JSON as a constructor
var myjson = new SNJSON();
var encoded_payload = myjson.encode(this.payload);

// Create and send the REST Message
var msg = new RESTMessage(‘HipChat’, this.method);
msg.setStringParameter(‘endpoint’, this.endpoint);
msg.setXMLParameter(‘payload’, encoded_payload);
var res = msg.execute();
return res;
},

‘endpoint’ : gs.getProperty(‘hipchat_notification.default_endpoint’),
‘method’ : ‘post’,
‘payload’ : {
‘color’ : gs.getProperty(‘hipchat_notification.default_color’),
‘message’ : ”,
‘message_format’ : ‘html’,
‘notify’ : false
},

‘type’: ‘HipChatNotification’
};[/code]

Now, I said earlier if you’re running Fuji you could skip the step for adding the REST Message. If you did that, you’ll want to find the following block of code in the above script . . .
[code language=”javascript”]// Create and send the REST Message
var msg = new RESTMessage(‘HipChat’, this.method);
msg.setStringParameter(‘endpoint’, this.endpoint);
msg.setXMLParameter(‘payload’, encoded_payload);
var res = msg.execute();
return res;[/code]

. . . And replace it with this:
[code language=”javascript”]// Create and send the REST Message
var msg = new sn_ws.RESTMessageV2();
msg.setEndpoint(this.endpoint);
msg.setHttpMethod(this.method);
msg.setRequestHeader(‘Content-Type’, ‘application/json’);
msg.setRequestBody(encoded_payload);
var res = msg.execute();
return res;[/code]

This alternative code instantiates a new RESTMessageV2 object (instead of the older RESTMessage object) and does so without specifying any parameters. One of the neat things about the new version of the Outbound REST API is you don’t have to specify an existing REST Message, but can use the setter methods you see here to set the Endpoint and the HTTP Method, as well as directly set the Content Body of the message, all at runtime. Obviously if there’s a lot of setup (special headers and authentication and such) you may still want to go the former route of declaring the REST Message up front and calling it here, but since using the HipChat API doesn’t require a lot of complicated setup, being able to do it this way keeps things simple.

System Properties

You may have noticed the Script Include pulls in a couple of System Properties. I like using System Properties because they allow you to change settings on the fly later without re-deploying code. You can get a list view of all System Properties by typing “sys_properties.list” in the search box at the top of the left sidebar in Service­Now. To create a new System Property from there, simply click the “New” button.

You’ll need to declare the following System Properties in your instance for the Script Include above to function properly:

Name Value
hipchat_notification.default_endpoint Here’s where you should paste that URL you put in a safe place way back in the first section above.
hipchat_notification.default_color Specify the color you’d like all HipChat notifications to be by default. You can choose from yellow, green, red, purple, gray, or random.

I called these both defaults since, as I’ll show below, you can override either or both of them in your individual Business Rules. As a best practice I recommend you rename these to include a company prefix, e.g. acme.hipchat_notification.default_endpoint. If you do, just don’t forget to modify each of the gs.getProperty() calls in the Script Include to match the new names.

Examples

Here’s how easy it is to send a notification to the default endpoint using this Script Include. In an advanced Business Rule (with conditions specified however you like), just call the send() method on a new HipChatNotification object:

[code language=”javascript”]var hipchat = new HipChatNotification();
hipchat.send(‘Hello World!’);[/code]

To send the notification someplace other than the default room, simply create another integration for that room and specify the alternate endpoint URL as a second parameter of the send() method:

[code language=”javascript”]var hipchat = new HipChatNotification();
hipchat.send(‘Hello World!’, ‘https://api.hipchat.com/v2/room/xxxxxxx/notification?auth_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx’);[/code]

Note that the message itself can include HTML. Here’s a more realistic example how you might notify a room when an Incident has been assigned to a particular assignment group:

[code language=”javascript”]// Initialize a new HipChatNotification
var hipchat = new HipChatNotification();

// Set up the payload
hipchat.payload.message = ‘An Incident has been assigned to ‘ + current.assignment_group.name + ‘: <a href=”https://’ + gs.getProperty(‘instance_name’) + ‘.service-now.com/nav_to.do?uri=incident.do?sys_id=’ + current.sys_id + ‘”>’ + current.number + ‘</a> ‘ + current.short_description;
hipchat.payload.color = ‘red’;

// Fire off the message
var response = hipchat.send();[/code]

The above will result in a Slack notification looking like this:

HipChat Notification

Don’t miss how you can call the send() method without any parameters as long as you’ve specified useful values for the payload beforehand, and be aware you may need to use toString() when you set values if you’re not using string concatenation or something else that would implicitly cast the contents of a record field into a string.

Lastly, note that the send() method returns the server response. If you store that response you can debug by grabbing values out of it as shown below:
[code language=”javascript”]// Send the notification
var hipchat = new HipChatNotification();
var response = hipchat.send(‘Hello World!’);

// Show error message if it failed
if(response.getStatusCode() != 200) {
gs.addInfoMessage(“response.getBody: “ + response.getBody());
gs.addInfoMessage(“response.getStatusCode: “ + response.getStatusCode());
gs.addInfoMessage(“response.getErrorMessage: “ + response.getErrorMessage());
}[/code]

Conclusion

So, what can you use this for? The sky’s the limit really. You can set up a Business Rule to fire on any condition you want and send any HTML message into any HipChat room. Use it as above to notify any given team when they have a new assignment. Use it to notify management when there’s a P1 incident. If you find a creative use for this Script Include, I’d love if you’d leave a comment below or drop me a line on social media. Cheers! 

Integrating ServiceNow with Slack

Slack + ServiceNow One of our teams at work recently started using Slack for all their team communication and approached me about possibly having ServiceNow shoot Incident assignment notifications into one of their Slack channels. As it turns out, integrating ServiceNow and Slack is really easy. In this article I’ll show you how to enable the necessary Slack “Incoming Webhooks” integration service as well as give you a ready-to-go ServiceNow Script Include you can use to post messages to Slack from any scripted ServiceNow Business Rule. Finally, I include some examples and ideas for how to use and re-use the Script Include in your own Business Rules.

Getting access to the Slack API

To get started, you’ll need an endpoint URL for the Slack API to which ServiceNow can send web service calls. To get this URL, from within any Slack channel (either in the Slack app or the Slack website), simply drop down the arrow next to the channel name and select “Add a service integration”. It doesn’t matter which channel you do this in—I’ll show below how you can use this same integration endpoint to post to any channel within the same team.

Slack “Add a service integration…”

On the next screen, scroll almost all the way to the bottom and click “+Add” next to “Incoming Webhooks”.

Slack Choose Incoming Webhooks

Lastly, click “Add Incoming Webhooks Integration”.

Slack Incoming Webhooks setup

On the next screen you should see a long web address labeled “Webhook URL”, similar to this:

https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx

Save this URL someplace safe. I’ll show you where to use it in a bit. Slack doesn’t require any kind of authentication to use this API, so the tokens in this URL essentially are your password. Keep it a secret.

Creating the REST Message in ServiceNow

The first step in ServiceNow is to set up a REST Message. If you’re running Fuji you can actually skip this step and go straight to the Script Include, as the new RESTMessageV2 API in Fuji doesn’t require a REST Message database record. If you’re still on Eureka or want to keep the integration backwards-compatible with earlier releases for any reason, read on.

  1. Navigate to System Web ServicesOutboundREST Messages in your ServiceNow instance.
  2. Click “New” to create a new REST Message.
    • Type “Slack” for the name.
    • Click the lock icon to unlock the Endpoint field and type “${endpoint}” there.
    • Type something useful in the Description field if you go for that sort of thing.
  3. Right-click in the header and choose “Save” to submit the new record and stay where you are.
  4. At the bottom of the newly-saved record, there will be a related list containing REST Message Functions, of which there should be four: “get”, “post”, “put”, and “delete”. Check the box to the left of all these but “post” and use the drop-down at the bottom to delete them. The only one we need to keep here is the “post” function.
  5. Click into the “post” function.
    • Verify the Endpoint here is also set to “${endpoint}” (it should’ve inherited this setting from the parent REST Message).
    • In the Content field, type “${payload}”.
  6. Click “Update”.

That’s it, the REST Message and REST Message Function should be ready to go.

The Script Include

To create the Script Include, follow these steps:

  1. Navigate to System DefinitionScript Includes in your ServiceNow instance.
  2. Click “New”.
    • Name the Script Include “SlackMessage”.
    • Give it a description if you want.
    • Copy and paste the script below.
  3. Click “Submit”.

Here’s the script itself:
[code language=”javascript”]var SlackMessage = Class.create();

SlackMessage.prototype = {
‘initialize’: function() {
if (gs.getProperty(‘slack_message.default_icon_url’) != ”) {
this.payload.icon_url = gs.getProperty(‘slack_message.default_icon_url’);
}
else if (gs.getProperty(‘slack_message.default_icon_emoji’) != ”) {
this.payload.icon_emoji = gs.getProperty(‘slack_message.default_icon_emoji’);
}
},

‘send’: function (text, channel) {
// Set the text and channel (or fall back to defaults)
this.payload.text = text || this.payload.text;
this.payload.channel = channel || this.payload.channel;

// Encode the payload as JSON
var SNJSON = JSON; // Workaround for JSLint warning about using JSON as a constructor
var myjson = new SNJSON();
var encoded_payload = myjson.encode(this.payload);

// Create and send the REST Message
var msg = new RESTMessage(‘Slack’, this.method);
msg.setStringParameter(‘endpoint’, this.endpoint);
msg.setXMLParameter(‘payload’, encoded_payload);
var res = msg.execute();
return res;
},

‘endpoint’: gs.getProperty(‘slack_message.default_endpoint’),
‘method’: ‘post’,
‘payload’: {
‘channel’: gs.getProperty(‘slack_message.default_channel’),
‘username’: gs.getProperty(‘slack_message.default_username’),
‘text’: ”,
‘attachments’: []
},

‘type’: ‘SlackMessage’
};[/code]

Now, I said earlier if you’re running Fuji you could skip the step for adding the REST Message. If you did that, you’ll want to find the following block of code in the above script . . .
[code language=”javascript” firstline=”23″]// Create and send the REST Message
var msg = new RESTMessage(‘Slack’, this.method);
msg.setStringParameter(‘endpoint’, this.endpoint);
msg.setXMLParameter(‘payload’, encoded_payload);
var res = msg.execute();
return res;[/code]

. . . And replace it with this:
[code language=”javascript” firstline=”23″]// Create and send the REST Message
var msg = new sn_ws.RESTMessageV2();
msg.setEndpoint(this.endpoint);
msg.setHttpMethod(this.method);
msg.setRequestBody(encoded_payload);
var res = msg.execute();
return res;[/code]

This alternative code instantiates a new RESTMessageV2 object (instead of the older RESTMessage object) and does so without specifying any parameters. One of the neat things about the new version of the Outbound REST API is you don’t have to specify an existing REST Message, but can use the setter methods you see here to set the Endpoint and the HTTP Method, as well as directly set the Content Body of the message, all at runtime. Obviously if there’s a lot of setup (special headers and authentication and such) you may still want to go the former route of declaring the REST Message up front and calling it here, but since the Slack API doesn’t require any of that, being able to do it this way keeps things simple.

System Properties

You may have noticed the Script Include pulls in a handful of System Properties. I like using System Properties because they allow you to change settings on the fly later without re-deploying code. You can get a list view of all System Properties by typing “sys_properties.list” in the search box at the top of the left sidebar in ServiceNow. To create a new System Property from there, simply click the “New” button.

You’ll need to declare the following System Properties in your instance for the Script Include above to function properly:

Name Value
slack_message.default_endpoint Here’s where you should paste that Slack Webhook URL you put in a safe place way back in the first section above.
slack_message.default_channel Specify the channel to which you’ll post the majority of your Slack messages, with a leading hash symbol, such as “#general” or “#servicenow”. The Slack API also allows specifying a person’s username preceded by an at symbol to send direct messages instead, such as “@joeyday”.
slack_message.default_username This is the display name of the bot that will post the messages. I set mine to “ServiceNow”, but this could be anything you like.
slack_message.default_icon_url Specify a URL of an image to be used as the avatar for your bot, or leave this blank if you want to use an Emoji instead (see the next property). This image can be anywhere on the web or hosted on Slack as long as you’ve shared it to the whole team and not left it private.
slack_message.default_icon_emoji Specify an Emoji code including surrounding colons, such as “:warning:”. Slack uses the same Emoji codes as Campfire and Github, for which there is a very handy Emoji cheat sheet. This setting will be ignored if you’ve specified an image URL instead (see the previous property).

I called these all defaults since, as I’ll show below, you can override any or all of them in your individual Business Rules. As a best practice I recommend you rename these to include a company prefix, e.g. acme.slack_message.default_endpoint. If you do, just don’t forget to modify all the gs.getProperty() calls in the Script Include to match the new names.

Examples

Here’s how easy it is to send a message into the default channel using this Script Include. In an advanced Business Rule (with conditions specified however you like), just call the send() method on a new SlackMessage object:

[code language=”javascript”]var slack = new SlackMessage();
slack.send(‘Hello World!’);[/code]

To send the message to a different channel or as a direct message to an individual, simply specify the channel or user in a second parameter of the send() method:

[code language=”javascript”]var slack = new SlackMessage();
slack.send(‘Hello World!’, ‘#random’);[/code]

[code language=”javascript”]var slack = new SlackMessage();
slack.send(‘Hello World!’, ‘@joeyday’);[/code]

You can get even more fancy using the payload member variable to override defaults and/or specify additional API options (this is very similar to the Business Rule script I actually wrote for the team I mentioned in the opening paragraph):

[code language=”javascript”]// Initialize a new SlackMessage
var slack = new SlackMessage();

// Set up the payload
slack.payload.text = ‘An Incident has been assigned to ‘ + current.assignment_group.name + ‘:’;
slack.payload.icon_emoji = ‘:exclamation:’;
slack.payload.attachments.push({
‘title’: current.number.toString(),
‘title_link’: ‘https://’ + gs.getProperty(‘instance_name’) + ‘.service-now.com/nav_to.do?uri=incident.do?sys_id=’ + current.sys_id,
‘text’: current.short_description.toString()
});

// Fire off the message
slack.send();[/code]

The above will result in a Slack message looking like this:

Slack Message

Don’t miss how you can call the send() method without any parameters as long as you’ve specified useful values in the payload beforehand, and that you may need to use toString() when you set values if you’re not using string concatenation or something else that would implicitly cast the contents of a record field into a string.

There are more options I haven’t gone over here and I encourage you to read up on the Slack Incoming Webhooks API for more details. The important thing to notice is that “payload” is a JavaScript object that gets encoded as JSON and sent in as the Request Body of the REST message, so you can declare any option you want from the Incoming Webhooks API as a key/value pair in that payload object and it should work.

I should mention that you can even override the default endpoint if you need to send a message to an entirely different team:

[code language=”javascript” autolinks=”false”]var slack = new SlackMessage();
slack.endpoint = ‘https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx’;
slack.send(‘Hello World!’, ‘#general’);[/code]

Lastly, the send() method returns the server response. If you store that response you can debug by grabbing values out of it as shown below:
[code language=”javascript”]// Send the message
var slack = new SlackMessage();
var response = slack.send(‘Hello World!’);

// Show error message if it failed
if(response.getStatusCode() != 200) {
gs.addInfoMessage(“response.getBody: “ + response.getBody());
gs.addInfoMessage(“response.getStatusCode: “ + response.getStatusCode());
gs.addInfoMessage(“response.getErrorMessage: “ + response.getErrorMessage());
}[/code]

Ideas

What sorts of things can you do with this? The sky’s the limit really. What I was tasked with doing was simply send a message into a specific channel whenever an Incident was assigned to a specific User Group. By specifying different conditions in your Business Rule, you could send messages only if an Incident is high priority or attached to certain Configuration Items.

One idea I thought of is adding a Slack username field to the sys_user table and then using that to push a private message whenever a user has a ticket assigned to them, something like:

[code language=”javascript”]if (current.assigned_to.u_slack_username != ”) {
slack.send(‘Ticket ‘ + current.number + ‘ has been assigned to you!’, ‘@’ + current.assigned_to.u_slack_username);
}[/code]

If you use this Script Include for something interesting, I’d love if you’d leave a comment below or drop me a line on social media. Cheers! 

Two Covenants

Are the two major divisions of the Bible really “testaments” or “covenants”?

In what way are the major divisions of the Bible “testaments” or “covenants”? Are “Old Testament” and “New Testament” just arbitrary titles, or are we really to understand them as somehow actually being covenants?

The other day I wrote about the biblical warrant for calling our two major divisions of Scripture the Old and New Testaments. I explained that 2 Corinthians 3:6, 14 is a solid basis for calling them what we do, either formally or at least informally. Today I want to peel back the onion one more layer. I want to get deeper into why we can and should call them covenants, beyond simply that the Bible itself calls them that.

[![Michael Kruger’s “Canon Revisited”](http://joeyday.com/wp-content/uploads/2014/10/9781433505003.jpg)](http://amzn.com/1433505002/?tag=joeyday-20)
Michael Kruger’s “Canon Revisited”

For this I have to lean on a book I recently read, Michael Kruger’s Canon Revisited: Establishing the Origins and Authority of the New Testament Books. In a chapter on the apostolic origins of the New Testament canon, Kruger tackles exactly this question, concluding that canon is itself derived from redemption and covenant.

If you think about it, what are the most important sections of our two testaments? For the Old Testament, the important section is the Torah, the Pentateuch, the five Books of Moses, which tell of God establishing the old covenant with his people Israel through Moses as mediator. The important section of the New Testament is the four Gospels, which tell of a new covenant God has established with his people through Christ as mediator.

What about the rest of Scripture? Everything else in the Old Testament took place and was written in the context of the old covenant, and everything else in the New Testament was written in the context of the new covenant. Kruger explains, taking a cue from other scholars such as Meredith Kline, that the prophetic books of the Old Testament and the epistles of the New Testament function as “covenant lawsuits”, bringing charges against God’s covenant people for various offenses against the covenant. So these secondary documents even function as an important part of the written form of each covenant.

So our two collections of Scripture are certainly about covenants, but in what sense can we call them covenants or testaments in and of themselves? Here, Kruger helpfully explains that every covenant in the ancient near east included certain elements. One important element was the depositing of a written copy of the covenant to be kept by both parties in a safe place. A notable example of this custom is the ten commandments, written by God himself on stone tablets, being deposited in the Ark of the Covenant and kept in the tabernacle and later the temple in Jerusalem. Kruger argues, and I agree, what we have in our Old and New Testaments is nothing less than the written deposit of God’s covenants with man.

Given this function of these written texts, it is right not only to say they are about covenants, but to call them covenants in and of themselves. And isn’t this what we saw in my previous article? Paul considered the written text of the Old Testament synonymous with the old covenant when he said in 2 Corinthians 3:14: “when they read the old covenant”. 

Two Testaments

Where do we find biblical warrant for the terms “New Testament” and “Old Testament”?
![Bible by Adam Dimmick](http://joeyday.com/wp-content/uploads/2014/11/2680204486_188ed5040f_b.jpg)
Photo credit: [Bible](https://www.flickr.com/photos/fatmanad/2680204486/) by [Adam Dimmick](https://www.flickr.com/people/fatmanad/)

Where do the terms “Old Testament” and “New Testament” come from? What do they mean? Is it right for us to name the two divisions of our Bible this way?

Melito of Sardis is widely regarded as the person who coined the terms “Old Testament” and “New Testament”. His is the earliest known canon (list of books) of the Old Testament (circa 180 CE). But I discovered recently that the New Testament itself spoke of the Old and New Testaments a century before Melito.

In 2 Corinthians 3:14, Paul refers to the “old covenant” as a written document (“when they read the old covenant”). It’s important to explain here that the word for “covenant” in this passage is the Greek διαθήκη (diathēkē), which variously means “testament” or “covenant”. Look at this same passage in the King James and you’ll find the word “testament” there in place of “covenant”. When Melito of Sardis coined the terms, he was writing in Greek and used exactly this word διαθήκη.

What’s remarkable is that just 8 verses back, in 2 Corinthians 3:6, Paul states that God has made him and the other apostles “ministers of a new covenant” (same word διαθήκη, and if you look at the KJV you’ll find “new testament” here). It’s hard to escape the implication that Paul knew he was contributing to a new collection of Scripture which he would at least informally have referred to as the “new covenant” just as he referred to the Jewish Scriptures as the “old covenant”.

It’s impossible to know for certain if this is where Melito got his terms for the Old and New Testaments, but I think it’s a remarkable coincidence if not. I think perhaps it would be better for us to call them the Old and New Covenants, but Testament is a valid translation of διαθήκη and it’s rather late to change our conventional English wording now. Whether we call them Covenants or Testaments, though, I see 2 Corinthians 3:6, 14 as a solid biblical basis for naming our two collections of Scripture as we do. 

Treasure

Since I began studying covenant theology in the past couple years, I’ve become partial to verses of hymns that speak of God being our highest treasure, portion, or inheritance.

My new favorite verse of Be Thou My Vision is:

Riches I heed not nor man’s empty praise,
Thou mine inheritance now and always;
Thou and thou only first in my heart;
High king of heaven, my treasure thou art. ((Be Thou My Vision, Eleanor Hull, 1912.))

My new favorite verse of Amazing Grace is:

The Lord has promised good to me,
His word my hope secures;
He will my shield and portion be,
As long as life endures. ((Amazing Grace, John Newton, 1779.))

These hymn verses echo for me the promise of God reiterated in every progressive revelation of the covenant of grace that he will be God to us and we will be his people (Genesis 17:7; Leviticus 26:11–12; Jeremiah 31:33; Revelation 21:3). They remind me that God is indeed “the strength of my heart and my portion forever” (Psalm 73:26).