Sharing and embedding (API)

thecrag.com Application Programming Interface (API) enables sharing of rock climbing information in a programmatic way. For example you will be able to use this API to build your own applications, or present rock climbing information on your website.

The API is in Beta release, which means that it is subject to change. We will be using a couple of trial applications to help us stablise the specification, including the website itself and an Android mobile app. If you want to be one of the brave developers to work with Beta API release then contact us.

An application may use the API to:

  • access read-only crag information;
  • update crag information;
  • access to read-only public account information;
  • access read-only private account information; or
  • update account information.

We are also developing a javascript wrapper framework for the API so you can easily integrate server data into your javascript code. See https://github.com/theCrag/thecrag-javascript for the pre-release version (probably too early to start using it, but worth while knowing it is there if you are planning to write an app).

This document covers the following topics:

  1. Projects
  2. Access
  3. Application key
  4. Protected resources
  5. Read access points
  6. Optimising down the wire
  7. Update access points

1. Projects

The current API projects are underway:

  • mobile app for Android and iPhone;
  • New routes for club website;
  • Climbing geo links for outdoor sites;
  • Wordpress template for single crag; and
  • thecrag.com website.

2. Access

Access to the API is broadly in-line with our copyright (Creative Commons - Attribution Non-Commercial Share Alike), but must be negotiated with us. Generally speaking granting access to our API needs to be a win win scenario where both thecrag and the third party gets something. For example this may be more users, content, or revenue share. Here are some examples of the kind of things that we would be interested in:

Deal A: You give us content for an area, we'll give yiou API access for that area - eg a local club or a local guidebook getting 'merged into the borg'.

Deal B: You give us tick data data, we host logbook and leverage stats, probably free, but maybe commecial if high traffic.

Deal C: You give us money, revenue share, we give you content. You add value essentially in a better UX for a platform (iPhone, Andriod, XBox, etc).

Deal D: You give us money we give you exposure to user base (eg sponsored links, sponsored articles).

Deal E: You give us new users, we give you new users (for example cross linking with MTB site or skiing site).

Deal F: You make a donation, we give you limited API access to test an idea (eg one crag).

When considering any proposals to us please note that we are interested in a long term mutually beneficial relationship. We are not interested in providing free content so you can kick start a competitive business.

Conditions of use of API:

  1. You must have an api key.
  2. You must use the dev api for for application testing and development purposes and get your application approved by us before being released in production.
  3. You must use the api calls as advised for your application. For example if an application is inefficiently using the API calls and we identify a better way of doing so then you must change the to the recommended calls. In many instances we may actually develop an API call tailored for your application. This protects thecrag from applications making hundreds of calls to get information that could be made in one call.
  4. All instances of your application must have a reasonable combined peak load usage. Reasonable is defined as not adversely effecting the overall performance of the server. As a guideline with a single server (our current configuration), reasonable peak load is less than 10 calls in a 10 second period but may vary depending on what API calls are made. As we scale the system we intend to be more flexible with the definition of reasonable load.
  5. You must disclose whether your app is commecial or not. Commercial includes user pays, advertising and promotional applications. For example if there is advertising associated with the application then we would consider this commercial. Also if you are building the application as a promotional app (eg for Black Diamond or for a gym) then this would also be seen as commercial. Please ask us about whether or not we would view your application as commercial. If you want a commercial app then we are not greedy it's just a matter of negotiating fair compensation. It's only fair that thecrag.com does not bear other peoples commercial costs without being compensated (yes it does cost money for us to have an API available).
  6. You must not use the api to build your own content from that supplied by the api. Please discuss with us any caching or storing of content on your client side, because in some instances caching or storing of content is acceptable. Unless otherwise negotiated you should assume that storing or caching of content is not acceptable. This ensures that the final end user gets up-to-date information and also protects thecrag from bad will usage (eg using thecrag api to build lists of climbs for your own server).
  7. You must adhear to all copyright restrictions of the data you are accessing though the api. For avoidance of doubt, access to information through the API does not give you any additional rights to copyright material. Information from third parties may be passed through the api, in which case they will have their own copyright tag. If data is not tagged with a copyright then you can assume it falls under thecrag.com copyright.
  8. There is no quality of service or continuity of service guarantee.
  9. The api is in early beta stage so you should only use it if you are able to deal with the frustrations of a beta product.
  10. In many instances we will allow in-kind commercial use of the api.

For commecial initiatives we may implement Quality of Service guarentees and provide priority access depending on how things pan out.

2.1 How do I get API access?

In order to get access to the API you must:

  • Contact us
  • Get us to allocate an API key
  • Trial application on the development server (dev.thecrag.com)

2.2 Copyright constraints

Please note that API implementations are bound by the copyright restrictions of thecrag.com or the contributing publisher. Thecrag.com's copyright requires attribution under the Creative Commons - Attribution Non-Commercial Share Alike licence. As a guide, for areas where contributions have come from lots of users we allow you to attribute the highest Karma contributors and reference how to get the original information from thecrag.com. Specific information like photos, or grade contributions should reference the particular user. Please note that we reserve the right to ask you to make additional attributions in your application (it's only fair that climbers spending their time and effort for the benefit of the whole climbing community get properly attributed).

Where the API is providing information under a third party publisher then you are bound by their copyright not thecrag.com's copyright. This information will be tagged with a copyright ID. You may retieve details of the publishers copyright through a separate copyright api call.

You must check for publisher tagged copyright for the following entities:

  • Area descriptions
  • Route descriptions
  • Photos
  • Topos

3. Application key

All access to the API must use an API key. The API key may be supplied as a URL parameter ‘key=abc’ or though a custom HTTP header item ‘X-CData-Key: key=abc;’.

Developer style note: you should provide a global variable for setting the application key, and standardise the way you access the API. This will minimise the headaches if you have to change API keys for some reason.

3.1 As URL parameter

If the api key is supplied as a URL parameter the API call would look something like:

  www.thecrag.com/api/area/id/1234?key=abc

3.2 As HTTP header

If the api key is supplied as a HTTP header then the http GET call would look something like:

  GET www.thecrag.com/api/area/id/1234 HTTP/1.1
  X-CData-Key: key=abc;

4. Protected resources

An application may get access to protected resources (ie private account data) using OAuth protocol. OAuth is an Internet standard protocol and is fairly well supported in popular development software. You will need to use OAuth for:

  • Access to private account data; and
  • Updating account data including logging ticks.

thecrag.com’s OAuth implementation uses the following end points in the production system:

  • Temporary Credentials: http://www.thecrag.com/oauth/request_token
  • User Authorization: http://www.thecrag.com/oauth/authorize
  • Access Token: http://www.thecrag.com/oauth/access_token

In the development system use the following similar end points:

  • Temporary Credentials: http://dev.thecrag.com/oauth/request_token
  • User Authorization: http://dev.thecrag.com/oauth/authorize
  • Access Token: http://dev.thecrag.com/oauth/access_token

Developer style note: As you will have to test the application in the development system you should create a global variable for the server and set it to either 'http://www.thecrag.com' or 'http://dev.thecrag.com'. This will eliminate the painful problems of only half cutting over from the development to production server. Please note also that we do intend to cut over to https in the near term.

For all OAuth end points use HMAC-SHA1 as the oauth_signature_method. The OAuth spec has a nice explicit example of the information flow for Auth. The following discussion should be read in conjuction with the spec example to show how OAuth works on thecrag.com.

4.1 Temporary Credentials

When you apply for an API access key you will be given the Application key and secret. Use these as the consumer_key and consumer_secret for getting temporary token.

  http://www.thecrag.com/oauth/request_token
  (note that Authorization fields must be included in the HTTP header request)

Temporary credentials request requires the following OAuth fields in the Authorization header:

  • oauth_consumer_key
  • oauth_signature_method
  • oauth_timestamp
  • oauth_nonce
  • oauth_callback
  • oauth_signature

A temporary oauth_token and oauth_secret will be returned if the signature is verified.

  HTTP/1.1 200 OK
  Content-Type: application/x-www-form-urlencoded

  oauth_token=ijk&oauth_token_secret=qrs&oauth_callback_confirmed=true

4.2 User Authorization

After you are given temporary credentials the client application must redirect to thecrag.com’s authorization URL using the oauth_token (returned by the Temporary Credentials step above) as a URL parameter. You may also supply the user login if this is already known. For example:

  http://www.thecrag.com/oauth/authorize?oauth_token=abc&login=XYZ

Don’t worry if the login is not known then the user will be prompted for their login. Also note that if the user is already logged into thecrag via cookie sessions then this will be used to identify the default user for authorizing access.

The user will be prompted for an account login name and a password. If the login and password are successfully verified by thecrag.com server then the client will be redirected to the oauth_callback (supplied in the Temporary Credentials step) using with URL parameters oauth_token, oauth_verifier and accountID.

  oauth_callback_url?oauth_token=abc&oauth_verifier=efg&accountID=1234

Please note the use of oauth_verifier, as this is a more recent change to the OAuth protocol. Please be aware that some of OAuth implementations may not include this.

4.3 Access Token

After the user has authorized access then the client API can get an access token for ongoing access to the account data.

  http://www.thecrag.com/oauth/access_token
  (note that Authorization fields must be included in the HTTP header request)

Access Token request request requires the following OAuth fields in the Authorization header:

  • oauth_consumer_key
  • oauth_token
  • oauth_signature_method
  • oauth_timestamp
  • oauth_nonce
  • oauth_verifier
  • oauth_signature

A full oauth_token and oauth_secret will be returned if the signature is verified.

  HTTP/1.1 200 OK
  Content-Type: application/x-www-form-urlencoded

  oauth_token=tuv&oauth_token_secret=wxy&oauth_callback_confirmed=true&account_id=1234

4.4 Protected Resource Access

Once a client app has the full access token the client will be able to access the protected resource (ie private account data associated with the account) by using the token in the Authorization header. For example

  http://www.thecrag.com/api/account/id/1234
  (with the Authorization item included in the header)

OAuth fields for access to a protected resource:

  • oauth_consumer_key
  • oauth_token
  • oauth_signature_method
  • oauth_timestamp
  • oauth_nonce
  • oauth_signature

Note that generating the signature uses the uri of the protected resource. This must be the 'http://www.thecrag.com/api/some/endpoint' (or https) without any url parameters.

5. Read access points

The API top level access point is:

  http://www.thecrag.com/api

There are some secondary access points you may be able to use if you need web page style access. These secondary access points are not documented but replicate the data used by the website templates (note that these are not to be generally used by client apps without special permissions, and hence remain undocumented).

Full definitions of the API access points may be found here:

thecrag API endpoint reference

Unless otherwise stated all API read access points return utf8 encoded text.

The API returns JSON data (mime type of application/json). If you are using Firefox then you may find a plugin which displays this nicely.

If you wish to return JSONP for a javascript function you use the URL paramater jsonp=myFunction. If JSONP is used then the API will return MIME type text/javascript. For example:

  http://www.thecrag.com/api/area/id/1234?jsonp=processArea

Some of the read api functions return JSON data which contains thecrag flavored markdown. Normally for the website this markdown text is automatically marked up to HTML for website display, however with the API you may sometimes want it marked up as text or as html. For thecrag flavored markdown to be marked up as text use the URL parameter markupType=text, otherwise use markupType=html. Please note that the default is 'none' (ie the API does not do any conversion of markdown text and leaves that up to the client.

For example if you wanted to convert area beta markdown into HTML you would use:

  http://www.thecrag.com/api/area/id/1234/beta?markupType=html

The following sections outline some examples of api read calls.

If general error was encountered with the API call then JSON data is returned indicating what the error was, for example:

  {
    error: "bad uri",
  }

5.1 System Configuration

Grade context configuration is essentially used to resolve conflicts when parsing grades into potentially conflicting grades from grading systems around the world.

Grade type configuration aggregates the grading systems to like types.

Grade system configuration defines the grading systems used by thecrag. It includes variables for parsing, displaying and converting to an internal score (0-500).

5.2 Country

Note that you must also use an application if you were to implement any of the examples in this section or following sections. These examples use a application key associated with the API demo. You are not permitted to use this API key in your application. The demo API key will be changed from time to time, so your application will just stop working if you are using the demo API key.

5.3 Climber

If an account is public then you may access their data, however if an account is private then you need to use OAuth to access the data.

You may substiture the alias 'user' or 'account' for the word 'climber' in the climber end points.

Please note that the 'days-since-expired' field for subscriptions is optional. If it is specified then the recently expired subscriptions are included as well as valid subscriptions in the return data.

5.4 Node (Area/Route)

Note that you may use ‘node’ instead of ‘area’ or ‘route’. This may be useful if you don’t know if the node is an area or a route.

Developer style note: You should always get only what you need in as few API calls as you need (ie use show URL parameter).

5.5 Ascent

Developer style note: You should always consider server load when retrieving information via the API. The API has been developed for flexibility so that you can make more efficient calls. For example if you need information about alot of ascents then you should use the multiple ids method of getting ascent information.

5.6 Trip

5.7 Photo

5.8 Copyright

5.9 Maps

The first three elements in the above map summary lists are:

  • NodeID
  • Long, without decimal place (x1000000)
  • Lat, without decimal place (x1000000)

In the crag summary lists the next two fields are optional:

  • Number routes not located (if not present then this is a leaf node of the heirachy, area with no children or route)
  • Relative depth of node from query node (the order of the list means you can use this to determine the heirachy structure).
The bbox returns the node(s) that fully contain the bounded box.

5.10 Interface

The following are experimental features to support logging in using Facebook or other third party social networking sites.

5.11 Discussions

Crag Chat discussions may be private between members or public associated with an area or route or just a general discussion. A discussion may also be linked to an ascent or a trip.

To access a discussion you need to know the id of the root message. Accessing a discussion is done:

A discussion can have one or more messages associated with it. If there are more then 50 messages then the discussion is paginated (use the 'page' parameter as above). To find out if another message has been added to the discussion then use the 'last' api end point. If you use the 'last' end point please use some sort of algorithm which progressively polls at larger and larger intervals, otherwise the system will be become clogged up with polling that is essentially returning the same thing.

Note that the 'page' parameter does not work in the example above, it is there for syntatic purposes. At some point the example will be swapped over to something that works.

Private discussions

In order to access private discussions you must authenticate using OAuth and be one of the accounts associated with the discussion.

Further API work required to get the list of private discussions.

You may provide the following URL arguments:

  • unreadOnly: if set to 1 will return only unread messages.
  • page: set the page number for traversing multiple pages of discussions (default 1).
  • perPage: set the number of discussions per page (default 10).

In addition the subscribed discussions has the following URL arguments:

  • recentDays: sets the number of days from now to base the start date of the query (default 14).

The subscribed discussions cover all general and area forums you are subscribed to. People are automatically subscribed to area forums when they log an ascent to the crag, mark a favorite crag or become an editor to a crag. They can control their configuration through their 'chat' tab in their thecrag web account. People can also manually subscribe to general forums and area forums.

TODO: manage subscriptions through API.

Please note that if somebody starts a discussion at a route level it will filter down to the crag area discussion.

Area/route discussions

Area/route discussions are special type of forum where the discussions are rolled up into their ancestor nodes. This means a discussion on a route will also appear in the cliff, crag and country discussions.

The unreadOnly parameter requires OAuth to have identify the account.

Generic discussions

API work to be completed

Trip discussions

API work to be completed

Ascent discussions

API work to be completed

5.12 Markup

You may POST a thecrag flavoured markdown string to an endpoint to have it marked up including internal links. The POST end point is:

 POST http://www.thecrag.com/api/markup HTTP/1.1
  === header stuff === 

 {
   "data": {
     "type": "html",    # html/text
     "markdown": "Test *bold* and internal link to 'Grotto Wall' in 'Arapiles'.",
     "node": 11740915,
     "token": ["tlc"],  # list of zero or more of 'tlc', 'acronym', or 'parentAcronym'.
   }
 }

The node and token data variables tell the system the context for looking for internal links.

5.13 Index Structure

The world query returns the index structure from world node to top level crags. The id structure returns the index structure from tlc and lower. The returned structure excludes the queried node.

The returned JSON is an ordered array of nodes optimised for minimising down the wire data bandwidth. The information returned for each node is:

  • node ID
  • node name
  • node type: a - area, r - route, m - merged, w - world, n - annotation (you should only see 'a', 'r' and 'n').
  • area type: optional, Fi - Field, U - unknown, Fe - Feature, B - Boulder, S - Sector, Cl - Cliff, Cr - Crag, R - Region, A - Area.
  • parent ID: optional, if it is not there then it is the same as the previous node in the list.

5.14 Facet Search

Facet search provides an interface into searching thecrag data using a url query language. You are able to search the following entities using facet search:

  • routes
  • areas
  • nodes
  • ascents
  • favorites
  • photos
  • topos
  • activity
  • messages
  • climbers

The API facet search has the following generic endpoint structure:

  /api/facet/{entity}/url/query/language  # where entity is as listed above.

The url query language is a series of uri argument pairs for directive and value, for example at/1234 specifies entities at node id 1234. You may also specify multiple values using the '+' character, for example at/1234+5678.

Results are paginated with page size settable in the url parameters, defaulting to 100 with a maximum of 5000.

The following specific URL parameters may be set:

  • page
  • perPage
  • sortby

The sortby parameter is a comma separated list of pairs (field,asc/desc), for example 'at,desc'.

Before you start using these please be aware that some faceted searches may be very resource intensive. Please discuss with site management the queries you intend to use, otherwise we may have to disable your key.

Routes

The url query string may contain the following search directives:

  • created-by
  • by
  • created-by-friends-of
  • by-friends-of
  • at-followed-by
  • at
  • after
  • before
  • between
  • created-after
  • created-before
  • created-between
  • with-stars
  • with-grade
  • with-gear-style
  • is
  • missing
  • has-been
  • length-shorter
  • length-longer
  • length-between
  • search
  • prefix-search

The following sort by:

  • when
  • when-fa
  • when-history # this may result in dups
  • at
  • stars
  • length
  • grade
  • gear-style

For example:

Areas

The url query string may contain the following search directives:

  • at
  • of-area-type
  • created-after
  • created-before
  • created-between
  • search
  • prefix-search

The following sort by:

  • when
  • at

For example:

Nodes

The url query string may contain the following search directives:

  • at
  • of-node-type
  • created-after
  • created-before
  • created-between
  • search
  • prefix-search
  • fuzzy-search

The following sort by:

  • when
  • at

For example:

Ascents

The url query string may contain the following search directives:

  • by
  • on
  • at
  • by-friends-of
  • at-followed-by
  • after
  • before
  • between
  • logged-after
  • logged-before
  • logged-between
  • with-tick-group
  • with-quality
  • with-route-grade
  • with-route-gear-style
  • with-route-stars
  • route-is
  • route-length-shorter
  • route-length-longer
  • route-length-between
  • search
  • search-comment

The following sort by:

  • when
  • when-climbed
  • by
  • at
  • tick-type
  • route-stars
  • route-length
  • route-grade
  • route-gear-style
  • route-bolts

For example:

Favorites

The url query string may contain the following search directives:

  • by
  • at
  • by-friends-of
  • after
  • before
  • between
  • search

The following sort by:

  • when
  • by
  • at

For example:

Photos

The url query string may contain the following search directives:

  • uploaded-by
  • taken-by
  • of
  • uploaded-by-friends-of
  • taken-by-friends-of
  • of-friends-of
  • at-followed-by
  • on
  • at
  • after
  • before
  • between
  • uploaded-after
  • uploaded-before
  • uploaded-between
  • with-route-grade
  • with-route-gear-style
  • with-route-stars
  • route-is
  • route-length-shorter
  • route-length-longer
  • route-length-between
  • search

The following sort by:

  • when
  • when-taken
  • uploaded-by
  • taken-by
  • uploaded-of
  • at
  • route-stars
  • route-length
  • route-grade
  • route-gear-style

For example:

Topos

The url query string may contain the following search directives:

  • at
  • after
  • before
  • between
  • at

The following sort by:

  • when

For example:

Activity

The url query string may contain the following search directives:

  • by
  • at
  • by-friends-of
  • after
  • before
  • between
  • with-time
  • with-route-grade
  • is
  • for
  • with-route-gear-style
  • with-route-stars
  • route-is
  • route-length-shorter
  • route-length-longer
  • route-length-between
  • search

The following sort by:

  • by
  • at
  • item
  • for
  • route-stars
  • route-length
  • route-grade
  • route-gear-style

For example:

Messages

The url query string may contain the following search directives:

  • at
  • at-followed-by
  • from
  • involving
  • after
  • before
  • between
  • since-message
  • search

The following sort by:

  • when

For example:

Note that if the filter does not include an 'at' directive then only messages involving the authorised account (OAuth) will be returned.

Use the 'markupType' parameter to markup message content - set to 'none', 'html' or 'text'. Markup includes internal links. If you do not set this parameter then the client will be responsible for the markup.

Use the 'truncate' parameter if you want to limit the message content length. Note that because message content can include html the truncate will nicely truncate at a word boundary shorter that the length specified.

Climbers

Not implemented

5.15 Text completion

There are some fast prefix lookup end points which can be used for text completion, for example in a crag search toolbar. Text completion examples:

For a crag search, if parameter 'mode' is set to 'region' then the search space is for regions only otherwise it is for areas identified as a Crag.

If you don't want a long list to be returned they you should specify the 'page-size' parameter.

For a climber search you can set the following mode behavious:

  • login: The search space returns prefix matches from the persons login.
  • name: The search space returns prefix matches from the persons name. Please note that because a person's name is in one field it does not prefix match somebodies last name.
  • email: The search space returns exact matches for an email address. Please note that partial email addresses are not matched.
  • id: The search space returns exact matches for an persons id. Please note that partial ids are not matched.
  • all: Matches all of the above. This uses more server resources and is slower, please use mode=server instead.
  • server: (default) This tells the server to decide which to match based on the search string. If it has an @ in the search space then it is assumed to be an email search, otherwise if all numbers then it is a login and id seach, otherwise if no spaces then it is a login and name search, otherwise a name search. This is the default search because it allows a user of an application to put in some text and the server can work out what the user meant without having the server overhead of processing 'all' modes.

7. Optimising down the wire

Because they are hash based, some of the endpoints described in this API have a heavy over-the-wire burden with unneccessary information. While this is fine for some clients, it is not ideal for others where data transfer rates are limited and/or client memory is limited.

This section describes how you can use the 'flatten' parameter to better optimise the data transfer over the wire. The flatten variable turns the result hash structures into an array only including values associated with keys you specified. The flatten spec can be nested so you can flatten sub hashes.

  flatten=key1,key2[subKeyA,subKeyB]

Below are a couple of examples of how this may work:

6. Update access points

Unless otherwise stated all API update access points require utf8 encoded text.

The update API end points require an application/json MIME type POST, with the POST content being json formatted utf8 text. The post can be a single update or multiple update. The format of a single update is:

  data: {
   …
  }

The format of a multiple update is:

  data: [{
     …
   },{
     …
  }]

Update API end points return either HTTP_ACCEPTED or HTTP_BAD_REQUEST, and application/json MIME type with the supplied data fields, and either an ‘ok’ or ‘error’ data field.

If an error was encountered the error message has the same structure as the data field, for example:

  error: [{
   loginError: “not unique”,
  }]

Where the ‘loginError’ corresponds to the ‘login’ input data field.

If the update was successful then an ‘ok’ field is returned, for example:

  ok: [{
   accountID: 1234
   uri: ‘/climber/1234’
  }]

Note that if an entity has been created then the id of that entity and the canonical uri is returned. Core entities that can be created using the API include:

  • climber: returns accountID if successfully created
  • area: returns nodeID if successfully created
  • route: returns nodeID if successfully created
  • ascent: returns ascentID if successfully created
  • trip: returns tripID if successfully created (not implemented yet)

There are separate end points for each of the core entities for creating, updating and deleting. Each of these end points has a paired validate call. For example 'climber/create' is paired with 'climber/create/validate'. The paired validate API call is an end point in it's own right, but is also called internally by the update end point.

Developer style note: You should always call the paired validate API end point before calling the update end point.

Note that none of the delete API end-points are implemented yet.

6.1 Create Climber

Access points:

  http://www.thecrag.com/api/climber/create
  http://www.thecrag.com/api/climber/create/validate

Data fields:

  • login: mandatory, must be unique in system.
  • password: mandatory
  • email: mandatory
  • name: highly recommended, but optional if you really cannot supply a name.
  • countryID: highly recommended, but optional if you really cannot supply a country ID.
  • termsVersionID: for web signup
  • list: flag to indicate whether to list account in public directories (default yes)
  • private: flag to indicate that it is a private account (default no)

The system has tens of thousands of login names registered so there is a very high probability that a create climber API request will return an error because the login already exists.

The countryID is the country identifier in the system. This is not the node identifier associated with the country. You may get a list of country identifiers by using the following API call (also see examples above):

  http://www.thecrag.com/api/country/list

The termsVersionID indicates that the user has accepted specific terms and conditions. Accepting terms and conditions is required if the user is accessing the system via thecrag.com website. If the user has not accepted the terms and conditions then they will be asked to accept them the first time they log into the website. It's good programing practice to get a user to accept terms and conditions, but from the API perspective this is seen as a client application responsibility. If you want to integrate your application to the systems terms and conditions then let us know because we will have to make some enhancements to the API.

Examples:

POSTResponse
 POST http://www.thecrag.com/api/climber/create/validate HTTP/1.1
  === header stuff === 

 {
   "data": {
     "email" : "bla",
     "password" : "abc",
     "name" : "simon dale",
     "login" : "SCD"
   }
 }
 {
   "error": {
     "loginError" : "login already in use"
   },
   "data": {
     "email" : "bla",
     "password" : "abc",
     "name" : "simon dale",
     "login" : "SCD"
   }
 }
 POST http://www.thecrag.com/api/climber/create/validate HTTP/1.1
  === header stuff === 

 {
   "data": [{
       "email" : "bla",
       "password" : "abc",
     },{
       "email" : "bla2",
   }]
 }
 {
   "error": [{
      "loginError" : "mandatory field",
     },{
      "loginError" : "mandatory field",
      "passwordError" : "mandatory field",
   }]
   "data": [{
       "email" : "bla",
       "password" : "abc",
     },{
       "email" : "bla2",
   }]
 }
 POST http://www.thecrag.com/api/climber/create HTTP/1.1
  === header stuff === 

 {
   "data": {
     "email" : "bla",
     "password" : "abc",
     "name" : "simon dale",
     "login" : "SOMEUNIQUENAME"
     "list" : "yes",
     "private" : 0,
   }
 }
 {
   "ok": {
     "accountID" : "1234",
     "uri" : "/climber/1234"
   },
   "data": {
     "email" : "bla",
     "password" : "abc",
     "name" : "simon dale",
     "login" : "SOMEUNIQUENAME"
     "list" : "yes",
     "private" : 0,
   }
 }

6.2 Update Climber

Access points:

  http://www.thecrag.com/api/climber/update
  http://www.thecrag.com/api/climber/update/validate

Data fields:

  • accountID:
  • favorite: hash identifying which node to (de)select as a shortcut.
  • follow: hash identifying which account to (un)link as a linked account.

The update climber accessp point is under development. Currently you can only (un)link to other accounts and (de)select shortcuts.

To (de)select a node as a shortcut use the favorite variable, which has the following format:

  node: 1234,
  status: 0/1

Set status to 1 to select as favorite, set to 0 to deselect as favorite.

To (un)link to another account use the follow variable, which has the following format:

  account: 1234,
  status: 0/1

Set status to 1 to follow an account, 0 to unfollow an account.

Examples:

POSTResponse
 POST http://www.thecrag.com/api/climber/update HTTP/1.1
  === header stuff === 

 {
   "data": {
     "accountID" : "1234",
     "favorite" : {
       "node": "6789",
       "status": "1",
     }
   }
 }
 {
   "ok": {
     "uri" : "/climber/1234"
   },
   "data": {
     "accountID" : "1234",
     "favorite" : {
       "node": "6789",
       "status": "1",
     }
   }
 }
 POST http://www.thecrag.com/api/climber/update HTTP/1.1
  === header stuff === 

 {
   "data": {
     "accountID" : "1234",
     "follow" : {
       "account": "4567",
       "status": "1",
     }
   }
 }
 {
   "ok": {
     "uri" : "/climber/1234"
   },
   "data": {
     "accountID" : "1234",
     "follow" : {
       "account": "4567",
       "status": "1",
     }
   }
 }

6.3 Create Area

Access points:

  http://www.thecrag.com/api/area/create
  http://www.thecrag.com/api/area/create/validate

Data fields:

  • submittor: mandatory accountID submitting the area.
  • parent: mandatory parent nodeID.
  • name: mandatory name of area.
  • alternateNames: optional hash describing alternate names.
  • type: mandatory area type.
  • insertBefore: optional nodeID for inserting before a sibling node.
  • beta: optional hash for description fields.
  • publisherID: optional publisherID if submission associated with a publisher.
  • publicationID: optional publicationID if submission associated with a publication.

The type variable may be one of (see Area Types article):

  • Area
  • Region
  • Crag
  • Cliff
  • Sector
  • Field
  • Boulder
  • Feature

The alternateNames variable is a hash with the following format:

  type: string,
  name: string

The type sub-variable may be one of:

  • Offensive
  • Language
  • Historical
  • Alternate

The beta variable is a hash with the following format:

  type: string,
  description: string

The type sub-variable may be one of (see Write Descriptions article):

  • Description
  • Access
  • Approach
  • Unique Features And Strengths
  • Where To Stay
  • Descent Notes
  • Ethic
  • Rest Day Activities
  • History

Examples:

POSTResponse
 POST http://www.thecrag.com/api/area/create HTTP/1.1
  === header stuff === 

 {
   "data": {
     "name": "somecliff",
     "type": "Cliff",
     "alternateNames": [{
       "type": "Historical",
       "name": "historical name",
     }],
     "beta": [{
       "type": "Description",
       "description": "some description",
     }],
     "parent": 5678,
     "submittor": 7890,
   }
 }
 {
   "ok": {
     "nodeID" : "1234",
     "uri" : "/area/1234"
   },
   "data": {
     "name": "somecliff",
     "type": "Cliff",
     "alternateNames": [{
       "type": "Historical",
       "name": "historical name",
     }],
     "beta": [{
       "type": "Description",
       "description": "some description",
     }],
     "parent": 5678,
     "submittor": 7890,
   }
 }

6.4 Update Area

Access points:

  http://www.thecrag.com/api/area/update
  http://www.thecrag.com/api/area/update/validate

Data fields:

  • submittor: mandatory
  • node: mandatory
  • name: optional, only use if updating principle name
  • alternateNames: optional hash if updating alternate names.
  • insertBefore: optional, only use if reordering
  • type: optional, only use if changing area type
  • beta: optional, only use if updating beta
  • publisher: optional, use if you want to add/update a description for a publisher.
  • publication: optional, only use if updating the publication an area description is associated with

The alternateNames variable includes an 'action' sub-variable which may be set to 'add' or 'delete'.

To update community beta then you do not include a publisher, otherwise if you include a publisher the publishers beta will be updated.

Examples:

POSTResponse
 POST http://www.thecrag.com/api/area/update HTTP/1.1
  === header stuff === 

 {
   "data": {
     "node": 1234,
     "submittor": 7890,
     "name": "new primary name",
   }
 }
 {
   "ok": {
     "uri" : "/area/1234"
   },
   "data": {
     "node": 1234,
     "submittor": 7890,
     "name": "new primary name",
   }
 }
 POST http://www.thecrag.com/api/area/update HTTP/1.1
  === header stuff === 

 {
   "data": {
     "node": 1234,
     "submittor": 7890,
     "alternateNames": [{
       "type": "Historical",
       "name": "historical name",
       "action": "delete",
     }],
   }
 }
 {
   "ok": {
     "uri" : "/area/1234"
   },
   "data": {
     "node": 1234,
     "submittor": 7890,
     "alternateNames": [{
       "type": "Historical",
       "name": "historical name",
       "action": "delete",
     }],
   }
 }

6.5 Create Route

Access points:

  http://www.thecrag.com/api/route/create
  http://www.thecrag.com/api/route/create/validate

Data fields:

  • submittor: mandatory
  • parent: mandatory
  • name: mandatory
  • alternateNames: optional hash of alternate names.
  • insertBefore: optional
  • beta: optional hash (same as creating area, but only 'Description' field is available).
  • publisher: optional publisherID
  • publication: optional publicationID
  • context: mandatory
  • heightText: optional
  • pitches: optional
  • bolts: optional
  • topRopeFlag: optional
  • isProjectFlag: optional
  • gearStyle: mandatory
  • history: optional
  • lat: optional
  • long: optional
  • gradeText: optional
  • citation: optional

The context variable sets the context for the system to parse grades. Note that globally some grading systems confict. You may get the context from the country and the country from the ancestor list. For example:.

  http://www.thecrag.com/api/area/id/11740915/ancestors
  http://www.thecrag.com/api/country/id/7478254

The gearStyle variable may be one of (see Route Styles article):

  • Unknown
  • Trad
  • Sport
  • DWS
  • Aid
  • Via ferrata
  • Boulder
  • Ice
  • Alpine
  • Top rope

The history variable is a hash with the following format:

  type: string,
  date: YYYY-MM-DD
  climbers: string,
  diary: string

The type sub-variable may be one of:

  • First Ascent
  • First Free Ascent

The date sub-variable may have either DD as '00' or both MM and DD as '00'.

The heightText variable is a text string describing the height. If it is a single number it is assumed to be in metres. You may input using feet by using ft units (eg '100ft') or you may input multiple pitches using comma (eg '20,45,27').

The gradeText variable is a text string describing the grade as it would be seen in a guidebook. This may be fairly complex and could include grade ranges, stars, protection ratings, partial grades, and aid. For example in the US context the system would understand the following grade texts:

  • 5.10a
  • 5.10
  • 10a
  • 5.11b-d
  • 5.11c/d
  • 5.11a A3
  • 5.9, 5.10a, 5.10d, 5.8
  • 5.10
  • 5.10d X
  • 5.10d **

The citation variable must be used with a publicationID and describes references where the route grade may be found in the publication (can be a URL or page number) depending on the nature of the publication.

Examples:

POSTResponse
 POST http://www.thecrag.com/api/route/create HTTP/1.1
  === header stuff === 

 {
   "data": {
     "name": "some route",
     "beta": [{
       "type": "Description",
       "description": "some description",
     }],
     "parent": 82079136,
     "submittor": 9068185,
     "context": "AU",
     "gearStyle": "Trad",
     "heightText": "24,26",
     "pitches": "3",
     "bolts": "4",
     "gradeText": "12,22M1",
     "history": [{
         "type" : "First Ascent",
         "date" : "2011-02-09",
         "climbers" : "some climber",
         "diary" : "diary entry"
       },{
         "type" : "First Free Ascent",
         "date" : "2011-00-00",
         "climbers" : "another climber",
         "diary" : "another entry"
     }],
     "lat": 45.45,
     "long": -22.45,
   }
 }
 {
   "ok": {
     "nodeID" : "1234",
     "uri" : "/route/1234"
   },
   "data": {
     "name": "some route",
     "beta": [{
       "type": "Description",
       "description": "some description",
     }],
     "parent": 82079136,
     "submittor": 9068185,
     "context": "AU",
     "gearStyle": "Trad",
     "heightText": "24,26",
     "pitches": "3",
     "bolts": "4",
     "gradeText": "12,22M1",
     "history": [{
         "type" : "First Ascent",
         "date" : "2011-02-09",
         "climbers" : "some climber",
         "diary" : "diary entry"
       },{
         "type" : "First Free Ascent",
         "date" : "2011-00-00",
         "climbers" : "another climber",
         "diary" : "another entry"
     }],
     "lat": 45.45,
     "long": -22.45,
   }
 }

6.6 Update Route

Access points:

  http://www.thecrag.com/api/route/create
  http://www.thecrag.com/api/route/create/validate

Data fields:

  • submittor: mandatory
  • node: mandatory
  • name: optional, use only if changing name
  • alternateNames: optional hash as per update area end point
  • insertBefore: optional, use if reordering
  • beta: optional hash as per update area end point (only the Description type is available for routes)
  • publisher: optional publisherID to be used with beta
  • publication: optional publicationID to be used with beta or citation
  • context: optional unless gradeText is used
  • heightText: optional, use if changing height
  • pitches: optional, use if changing pitches
  • bolts: optional, use if changing bolts
  • topRopeFlag: optional, use if changing top rope flag
  • isProjectFlag: optional, use if changing project flag
  • gearStyle: optional, use if changing gear style
  • lat: optional, use if changing latidude and longitude
  • long: optional, use if changing latidude and longitude
  • citation: optional, use if changing publicication citation
  • gradeText: optional, use if changing/adding grade contribution from a user or publication.
  • registeredGrade: optional hash that you can use to add/update the registered grade of the route.

Note that multiple users and/or publications may contribute a grade contribution. When you create a route it will initially have at most one grade contribution. To add multiple grade contributions you must use the update route end point. If a publication is provided with gradeText then then it is assumed that it is a publication contribution, otherwise the contribution is assumed to be a user contribution. If the publisher/user has already made a grade contribution then their entry is updated, otherwise a new entry is added.

Updating gradeText will not update the registered grade for the climb unless there are no existing grade contributions.

To update the registered grade for a route you must use the registeredGrade variable. This will not be associated with a user or publisher. The registeredGrade hash has the following format:

  system: string,
  lower: grade,
  upper: grade

The system sub-variable should be one the system labels defined by the following configuration end point:

  http://dev.thecrag.com/api/config/grade/system

The upper grade is optional and is used to specify a grade range.

If the lower grade is not specified then the registered grade is removed from the system, otherwise the registered grade is either updated or added to the system.

Both the lower and upper grades must exactly match the grade type (as defined by the grade system configuration end point above).

A route may have registered grades for multiple systems (eg French and Australian registered grades in Thailand).

Examples:

POSTResponse
 POST http://www.thecrag.com/api/route/update HTTP/1.1
  === header stuff === 

 {
   "data": {
     "node": 1234,
     "submittor": 5678,
     "registeredGrade": [{
       "system": "YDS",
       "lower": "5.10a",
     }],
   }
 }
 {
   "ok": {
     "uri" : "/route/1234"
   },
   "data": {
     "node": 1234,
     "submittor": 5678,
     "registeredGrade": [{
       "system": "YDS",
       "lower": "5.10a",
     }],
   }
 }
 POST http://www.thecrag.com/api/route/update HTTP/1.1
  === header stuff === 

 {
   "data": {
     "node": 1234,
     "submittor": 5678,
     "context": "YDS",
     "gradeText": "5.11a,5.11d,5.9,5.10",
   }
 }
 {
   "ok": {
     "uri" : "/route/1234"
   },
   "data": {
     "node": 1234,
     "submittor": 5678,
     "context": "YDS",
     "gradeText": "5.11a,5.11d,5.9,5.10",
   }
 }

6.7 Create Ascent

Access points:

  http://www.thecrag.com/api/ascent/create
  http://www.thecrag.com/api/ascent/create/validate

Data fields:

  • account: mandatory accountID
  • node: mandatory nodeID
  • tick: optional tick type (defaults to 'tick')
  • date: optional, YYYY-MM-DD
  • label: optional, use if you want to label the ascent with something other then the route name of the given node.
  • shot: optional shot number
  • quality: optional quality rating
  • gradeSystem: optional but mandatory if using grade
  • grade: optional, defaults to route grade of the given node.
  • relativeDifficulty: optional relative difficulty rating (relative to given grade)
  • trip: optional tripID
  • comment: optional markdown comment
  • isDefault: optional, use if you want to make this the default ascent for the node when you have multiple ascents associated with the node (please note that this feature is under review and may be automated at some point).
  • postOnFacebook: optional flag indicating whether to post onto the users Facebook account. Note that they must have pre-configured this option in their account for it to work.
  • shotAggregationToken: optional flag indicating that multiple ascent shots should be aggregated in a single facebook posting (must be used with the postOnFacebook flag)

The tick variable may be one of:

  • firstfreeascent
  • attempt
  • working
  • retreat
  • target
  • mark
  • tick
  • clean
  • lead
  • onsight
  • flash
  • redpoint
  • pinkpoint
  • dog
  • second
  • secondclean
  • secondrest
  • solo
  • toprope
  • topropeclean
  • toproperest
  • aid
  • aidsolo
  • firstascent
  • ghost
  • hit

The quality variable may be one of:

  • crap
  • poor
  • average
  • good
  • excellent
  • classic
  • megaclassic

The relativeDifficulty variable may be one of:

  • soft
  • easy
  • average
  • hard
  • sand

Examples:

POSTResponse
 POST http://www.thecrag.com/api/ascent/create HTTP/1.1
  === header stuff === 

 {
   "data": {
     "account": 1234,
     "submittor": 5678,
   }
 }
 {
   "ok": {
     "ascentID" : "3344"
     "uri" : "/ascent/3344"
   },
   "data": {
     "account": 1234,
     "submittor": 5678,
   }
 }
 POST http://www.thecrag.com/api/ascent/create HTTP/1.1
  === header stuff === 

 {
   "data": {
     "account": 1234,
     "submittor": 5678,
     "tick": "onsight",
     "quality": "classic",
   }
 }
 {
   "ok": {
     "ascentID" : "3344"
     "uri" : "/ascent/3344"
   },
   "data": {
     "account": 1234,
     "submittor": 5678,
     "tick": "onsight",
     "quality": "classic",
   }
 }

6.8 Send message

Access points:

  http://www.thecrag.com/api/message/send
  http://www.thecrag.com/api/message/send/validate

Data fields:

  • fromAccount: accountID - mandatory.
  • content: abc - optional, max 5096, either 'subject' or 'content' mandatory.
  • subject: abc - optional.
  • toAccount: [accountID] - optional, either 'toAccount', 'toGroup' or 'createGroup' mandatory. You cannot send to both an account and group.
  • toGroups: [groupID] - optional - groupID is synonym for forumID.
  • createGroup: {name:xyz, type:'Area Forum', prn:nodeID} - optional, if an area forum does not exist for a node then one can be created on-the-fly.
  • node: node - optional, this should be used when posting to an area forum as an additional field. It determines the 'rollup'.
  • ascent: ascentID - optional.
  • trip: tripID - optional - note you can post to a node, trip or and ascent, but not more than one of these.
  • responseTo: root message of a discussion thread - optional, if you are starting a new discussion then you omit this, otherwise you must use the root message id for discussion responses.

The create group type variable may be one of:

  • Area Forum
  • Global Forum

Examples:

POSTResponse
 POST http://www.thecrag.com/api/message/send HTTP/1.1
  === header stuff === 

 {
   "data": {
     "fromAccount": 9068185,
     "content": "some test message",
     "toAccounts": [9068185],
   }
 }
 {
   "ok": {
     "messageID=>1234,
     "subject" => undef,
     "surrogate" => "some test message",
     "markupHTML" => "<p>some test message</p>",
   },
   "data": {
     "fromAccount": 9068185,
     "content": "some test message",
     "toAccounts": [9068185],
   }
 }
 POST http://www.thecrag.com/api/message/create HTTP/1.1
  === header stuff === 

 {
   "data": {
     "fromAccount": 9068185,
     "subject": "test subject",
     "content": "test message",
     "toGroups": [172682874],
     "node": 11740915,
   }
 }
 {
   "ok": {
     "messageID=>1234,
     "subject" => "test subject",
     "surrogate" => "test subject",
     "markupHTML" => "<p>test message</p>",
   },
   "data": {
     "fromAccount": 9068185,
     "subject": "test subject",
     "content": "test message",
     "toGroups": [172682874],
     "node": 11740915,
   }
 }
 POST http://www.thecrag.com/api/message/create HTTP/1.1
  === header stuff === 

 {
   "data": {
     "fromAccount": 9068185,
     "content": "test response",
     "responseTo": 176966451,
   }
 }
 {
   "ok": {
     "messageID=>1234,
     "subject" => undef,
     "surrogate" => "test response",
     "markupHTML" => "<p>test response</p>",
   },
   "data": {
     "fromAccount": 9068185,
     "content": "test response",
     "responseTo": 176966451,
   }
 }

6.9 Subscribe

Thecrag offers third party apps an account subscription service for app charging. The third party app creates the subscription record. Subscriptions may be associated with a node. Account subscriptions can be queried by the app, which allows a developer to refresh an account or share subscriptions between apps.

Access points:

  http://www.thecrag.com/api/subscribe/create
  http://www.thecrag.com/api/subscribe/create/validate
  http://www.thecrag.com/api/subscribe/update
  http://www.thecrag.com/api/subscribe/update/validate

Creating a subscription

Data fields:

  • account: accountID - mandatory.
  • developer: developerID - mandatory.
  • tag: optional developer tag for managing subscriptions between a particular developers apps.
  • access: optional access label for managing subscriptions between developers. Currently the only valid non-null setting is 'thecrag' which allows a developer to share the subscriptions as an official thecrag app.
  • node: optional nodeID for associating a subscription with a crag.
  • type: optional subscription type for multiple subscriptions for a particular account.
  • expires: optional expires date (YYYY-MM-DD). A subscription without an expires should be interpreted as a once off payment.
  • currency: optional currency code.
  • payment: optional payment for audit purposes. Should be included if there was a payment associated with the subscription.
  • discount: optional discount if there was a discount associated with the payment.
  • trial: optional flag to indicate a trial subscription.
  • complementary: optional flag to indicate a complementary subscription.
  • transactionReference: optional third party transaction reference.
  • notes: notes associated with the subscription.

Examples:

POSTResponse
 POST http://www.thecrag.com/api/subscribe/create HTTP/1.1
  === header stuff === 

 {
   "data": {
    "account": 9068185,
    "developer": 156291588,
    "tag": "googleapp",
    "access": "thecrag",
    "node": 11740915,
    "type": "myapp category A",
    "expires": "2012-10-22",
    "currency": "AUD",
    "payment": "4.51",
    "discount": ".49",
    "transactionReference": "AA-THIRD-PARTY-ID",
    "notes": "test the notes functionality"
   }
 }
 {
   "ok" : {
      "subscriptionID" : 209424667
   },
   "data" : {
      "payment" : "4.51",
      "access" : "thecrag",
      "account" : 9068185,
      "discount" : ".49",
      "node" : 11740915,
      "currency" : "AUD",
      "notes" : "test the notes functionality",
      "developer" : 156291588,
      "tag" : "googleapp",
      "type" : "myapp category A",
      "expires" : "2012-10-22"
      "transactionReference": "AA-THIRD-PARTY-ID",
   }
 }

Updating a subscription

Data fields:

  • account: accountID - mandatory.
  • subscription: subscriptionID - mandatory.
  • transactionReference: optional third party transaction reference.

Examples:

POSTResponse
 POST http://www.thecrag.com/api/subscribe/update HTTP/1.1
  === header stuff === 

 {
   "data": {
    "account": 9068185,
    "subscription" : 251188651,
    "transactionReference" : "1234-B",
   }
 }
 {
   "ok" : {
      "subscriptionID" : 251188651
   },
   "data" : {
      "transactionReference" : "1234-B",
      "account" : 9068185,
      "subscription" : 251188651
   }
 }

6.10 Register Webhook Callbacks

You may register webhook callbacks. This is where thecrag server tells you about changes to the database. The following webhook samples are currently available for developers:

  /climber/1234/profile
  /climber/1234/messages/involved/all
  /climber/1234/ascent
  /climber/1234/ascent/following
  /climber/1234/favorite
  /climber/1234/following
  /climber/1234/followed-by
  /climber/1234/subscription
  /node/6789/update
  /node/6789/descendant/update

If you want to use webhook callbacks you must contact us and let us know your url stub, something like 'http://somedeveloper.com/callbacks', in which case the callbacks will be POST'ed to http://somedeveloper.com/callbacks/climber/1234/messages/involved/all' for example.

You register a callback for a context (eg climber 1234, or node 6789) and a known identifer (eg /messages/involved/all). Registering a callback for the context will overwrite the callbacks for the developer/context.

Note that you will only get subscription callbacks for your developerID or if the subscription has a cross developer identifier.

Data fields:

  • developer: developerID - mandatory.
  • climber: accountID - optional (but either climber or node is mandatory).
  • node: nodeID - optional (but either climber or node is mandatory).
  • callbacks: ["/callback/label",...] mandatory, but may be an empty array to reset all callbacks for that developer/entity.

Examples:

POSTResponse
 POST http://www.thecrag.com/api/subscribe/create HTTP/1.1
  === header stuff === 

 {
   "data": {
    "developer": 156291588,
    "climber": 9068185,
    "callbacks": [
      "/climber/9068185/messages/involved/all",
      "/climber/9068185/following"
    ]
   }
 }
 {
   "ok" : {},
   "data" : {
      "callbacks" : [
         "/climber/9068185/messages/involved/all",
         "/climber/9068185/following"
      ],
      "developer" : 156291588,
      "climber" : 9068185
   }
 }

6.11 Topo

You may create topos using thecrag API. Creating topos is a two step process:

  1. Upload the image file into a temporary file on the server.
  2. Create the topo record, using the name parameter to process the file you just uploaded.

Uploading the image file

This may be done by using a standard web POST with 'name' and 'file' form parameters to the following end point:

  http://www.thecrag.com/upload

For example you could use curl to upload the file like following:

  curl --form name=some-rand-name --form file=@topo-test-file.jpg http://www.thecrag.com/upload

NOTE server limitation: The uploaded file 'name' must be unique in a temporary directory on the server, so you should put a random hash/number/string in the 'name' parameter when uploading the file, otherwise you may clash with already uploaded files.

The 'name' parameter will be used in the JSON data for creating the actual topo record.

The upload endpoint returns JSON, you should check for error messages. For example if the upload was unsuccessful it may look like:

{
  "jsonrpc": "2.0",
  "error" : {
    "code": "101",
    "message": "no upload content"
  },
  "id" : "id"
}

Creating the topo record

Access points:

  http://www.thecrag.com/api/topo/create
  http://www.thecrag.com/api/topo/create/validate

Developers please note you should be uploading topos to the cliff node, and linking to routes as objects. The sourceType should almost always be 'API Client' and source your developer id. The apiUploadFilename should be the same as that which was use in the 'name' parameter for the upload endpoint.

Data fields:

  • submittor: accountID - mandatory.
  • node: nodeID - mandatory node ID of the cliff.
  • sourceType: string - mandatory one of 'Inhouse Photo', 'Uploaded', 'URL', 'API Client'.
  • source: string - mandatory should be the developer ID for API Client.
  • apiUploadFilename: string - mandatory when using sourceType='API Client', and should match the 'name' parameter used in the uploade POST endpoint.
  • label: string - optional string used to label the topo.
  • object: list of objectRefs [{id:routeID,number:topo-object-number,store:points},...].
  • publisher: optional publisherID to be used with beta
  • publication: optional publicationID to be used with beta or citation

Updating the topo record

Access points:

  http://www.thecrag.com/api/topo/update
  http://www.thecrag.com/api/topo/update/validate

Data fields:

  • submittor: accountID - mandatory.
  • topo: topoID - mandatory.
  • node: nodeID - optional, used to change the cliff the topo is associated with.
  • overhead: flag - optional, used to indicate that the topo is an overhead topo.
  • name: string - optional.
  • linkObject: list of objectRefs [{id:routeID,number:topo-object-number},...]. Used to link a topo to a route,area,annotation,topo or anything.
  • unlinkObject: list of objectRefs [{id:routeID},...]. Used to unlink a topo object from the topo (eg the route is no longer needed in the topo).
  • object: list of objectRefs [{id:routeID,store:points},...]. Used to draw topo lines representing the object in the topo.

Examples:

POSTResponse
 curl --form name=some-rand-name --form file=@topo-test-file.jpg http://www.thecrag.com/upload
 POST http://www.thecrag.com/api/topo/create HTTP/1.1
  === header stuff === 

 {
   "data": {
    "submittor": 9068185,
    "node": 11960467,
    "sourceType": "API Client",
    "source": "1111",
    "apiUploadFilename": "some-rand-name",
    "object": [{
      "id": 12859423,
      "store": "9 15,49 55",
    }]
   }
 }
 {
   "ok" : {
     "topoID" : "210081091",
   },
   "data" : {
      "source" : "1111",
      "object" : [
         {
            "store" : "9 15,49 55",
            "id" : 12859423
         }
      ],
      "sourceType" : "API Client",
      "apiUploadFilename" : "somerandname",
      "submittor" : 9068185,
      "node" : 11960467
   }
 }