API Reference

Welcome to Ulule’s API documentation.

Do you want to dig Ulule’s data or operate crowdfunding campaigns on you own website? This should be a good start.

You must have a Ulule account and provide your API key to retrieve data from API.

If you have any question, just ping us on twitter:

We will keep you posted shortly with new features and business cases. Enjoy!

Overview

HTTP Verbs

Where possible, API strives to use appropriate HTTP verbs for each action.

Currently, we are supporting the following verbs:

Verb Description
OPTIONS Can be issued against any resource to get the HTTP supported methods
HEAD Can be issued against any resource to get just the HTTP header info.
GET Used for retrieving resources.
POST Used for creating resources.

Schema

All API access is over HTTPS, and accessed from the api.ulule.com domain

All data is sent and received as JSON.

$ curl -I https://api.ulule.com/v1/users/3048

HTTP/1.1 200 OK
Server: nginx/1.4.2
Date: Thu, 06 Feb 2014 09:16:48 GMT
Content-Type: application/json
Connection: keep-alive
Vary: Accept-Encoding
Vary: Accept, Accept-Encoding, Accept-Language, Cookie
Content-Language: en
Cache-Control: no-cache
X-Nginx-Cache: BYPASS
X-Cache: NO
X-RateLimit-Remaining: 940
X-RateLimit-Reset: 456156
X-RateLimit-Limit: 1000

Blank fields are included as null instead of being omitted.

All timestamps are returned in ISO 8601 format:

YYYY-MM-DDTHH:MM:SSZ

Representations is this documentation

When you fetch a list of resources, the response includes a subset of the attributes for that resource.

In this documentation we will focus on status codes and summary of representations.

Some attributes are very long to describe, the main website is in five languages so we will not print all attributes.

Parameters

Many API methods take optional parameters. For GET requests, any parameters not specified as a segment in the path can be passed as an HTTP query string parameter:

$ curl -i "https://api.ulule.com/v1/users/3048/projects?filter=followed"

In this example, the thoas value are provided for the :user parameter in the path while :filter is passed in the query string.

As we don’t support POST, PATH, PUT and DELETE requests for that moment (our API is currently in read-only), we will provide the documentation for these verbs later.

Authentication

There are two ways to authenticate through the API.

  • HTTP Basic authentication
  • API key authentication

Requests that require authentication will return 404 Not Found, instead of 401 UNAUTHORIZED, in some places.

HTTP Basic authentication

$ curl --basic --user "username:password" https://api.ulule.com/v1/...

The username:password pair is the same authentication information to log in Ulule.

API key authentication

Instead of the username and password couple you can provide the API key which can be found in your account settings

$ curl -H "Authorization: ApiKey username:YOUR_API_KEY_HERE"  https://api.ulule.com/v1/...

Errors

HTTP errors

There are five possible types of client errors on API calls that receive request bodies:

  1. Sending invalid JSON will result:
HTTP/1.1 400 Bad Request
  1. Sending the wrong type of JSON values will result:
HTTP/1.1 400 Bad Request
  1. An error occured in the application server will result:
HTTP/1.1 500 Internal Error
  1. Accessing resources without the permissions will result:
HTTP/1.1 401 UNAUTHORIZED
  1. Generating too many API calls will result:
HTTP/1.1 429 Too Many Requests

Validation errors

Required field

When you submit a form and forget a required field, the response will return a 422 status code with the following JSON:

[
    {
        "message": "Required",
        "classification": "RequiredError",
        "fieldNames": [
            "field_name"
        ]
    }
]
Invalid value

When you submit a form with an invalid value, the response will return a 422 status code with the following JSON:

[
    {
        "message": "Error description",
        "classification": "ValueError",
        "fieldNames": [
            "field_name"
        ]
    }
]

HTTP Redirects

API uses HTTP redirection where appropriate. Clients should assume that any request may result in a redirection. Receiving an HTTP redirection is not an error and clients should follow that redirect. Redirect responses will have a Location header field which contains the URI of the resource to which the client should repeat the requests.

Status code Description
301 Permanent redirection. The URI you used to make the request has been superseded by the one specified in the Location header field. This and all future requests to this resource should be directed to the new URI.
302, 307 Temporary redirection. The request should be repeated verbatim to the URI specified in the Location header field but clients should continue to use the original URI for future requests.

Rate limit

For requests using Basic Authentication or API Key Authentication, you can make up to 500 requests per hour, for DDoS protection you can’t make more than 10 requests per seconds.

You can check the returned HTTP headers of any API request to see your current rate limit status:

X-RateLimit-Remaining: 940
X-RateLimit-Reset: 456156
X-RateLimit-Limit: 1000

The headers tell you everything you need to know about your current rate limit status:

Header name Description
X-RateLimit-Limit The maximum number of requests that the consumer is permitted to make per hour.
X-RateLimit-Remaining The number of requests remaining in the current rate limit window.
X-RateLimit-Reset The time at which the current rate limit window resets in UTC epoch seconds.

Once you go over the rate limit you will receive an error response:

HTTP/1.1 429 Too Many Requests

Languages

Currently api.ulule.com supports the following languages:

Language Code
English en
French fr
Portuguese pt
German de
Italian it
Spanish es

If you want to switch urls provided by our API to another language, you must pass the query string lang in the url.

For example, if I want all urls localized in spanish:

$ curl https://api.ulule.com/v1/projects/9892/comments?lang=es

If you are sending a language not supported by our platform, you will receive following http status code:

HTTP/1.1 501 Not Implemented

Developers

User

Get detail

Retrieve user detail.

GET /users/:id

User detail.

Request

GET /users/3048 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Response

HTTP/1.1 200 OK
Vary: Accept
Content-Type: text/javascript

{
  "date_joined": "2011-02-02T12:29:06",
  "id": 3048,
  "is_active": true,
  "last_login": "2014-02-03T10:11:26.586862",
  "public_url": "http://www.ulule.com/thoas/",
  "resource_uri": "/api/v1/users/thoas/",
  "username": "thoas"
}

Path parameters

id required, the user ID

List created projects

Retrieve projects created by the user.

You will see a projects section in the response.

GET /users/:id/projects?filter=created

Projects created by the user.

Request

GET /users/3048/projects HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

Query parameters

filter the current filter for projects

List followed projects

Retrieve projects followed by the user.

You will see a projects section in the response.

GET /users/:id/projects?filter=followed

Projects followed by the user.

Request

GET /users/3048/projects HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

Query parameters

filter the current filter for projects

List supported projects

Retrieve projects supported by the user.

You will see a projects section in the response.

GET /users/:id/projects?filter=supported

Projects supported by the user.

Request

GET /users/3048/projects HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

ID required, the user ID

Query parameters

filter the current filter for projects

List orders

Retrieves user orders (organized in a pagination).

GET /users/:id/orders

User orders.

Request

GET /users/3048/orders HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

username required, the user ID

List all proposals

Retrieve user proposals (organized in a pagination).

GET /users/:id/proposals

User proposals (new, valid and invalid).

Request

GET /users/3048/proposals HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

List new proposals

Retrieve user new proposals (organized in a pagination).

GET /users/:id/proposals?filter=new

User new proposals.

Request

GET /users/3048/proposals?filter=new HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

Query parameters

filter the current filter for proposals

List valid proposals

Retrieve user valid proposals (organized in a pagination).

GET /users/:id/proposals?filter=valid

User valid proposals.

Request

GET /users/3048/proposals?filter=valid HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

Query parameters

filter the current filter for proposals

List invalid proposals

Retrieve user invalid proposals (organized in a pagination).

GET /users/:id/proposals?filter=invalid

User invalid proposals.

Request

GET /users/3048/proposals?filter=invalid HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

Query parameters

filter the current filter for proposals

Project

Get detail

Retrieve project detail.

GET /projects/:id

Project detail.

Request

GET /projects/9892 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

List comments

Retrieve project comments (organized in a pagination).

GET /projects/:id/comments

Project comments.

Request

GET /projects/9892/comments HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

List news

Retrieve project news (organized in a pagination).

GET /projects/:id/news

Project news.

Request

GET /projects/9892/news HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

List supporters

Retrieve project supporters (organized in a pagination).

GET /projects/:id/supporters

Project supporters.

Request

GET /projects/9892/supporters HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

News

Get detail

Retrieve news detail.

GET /news/:id

News detail.

Request

GET /news/1 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the news ID

List comments

Retrieve news comments (organized in a pagination).

GET /news/:id/comments

News comments.

Request

GET /news/1/comments HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the news ID

Third Party Authentication

Most POST operations will require you to have a registered application on Ulule.

To do so you must contact the Technical support, we will give you a pair of credentials (client_id and client_secret) which will allow you to request an access_token for a dedicated user.

Access token

The access_token will allow you to log as a user by passing it in each request.

You can pass the access_token directly in a GET parameter:

http://www.ulule.com/discover?access_token=[INSERT YOUR ACCESS TOKEN HERE]

Or you can pass it in each request as an authorization header:

$ curl -H "Authorization: Bearer USER-ACCESS-TOKEN"  https://api.ulule.com/v1/...

Retrieve an access token

To retrieve an access token, we will use this Python script:

# access_token.py
import base64
import os

import requests

# Your partner client ID.
CLIENT_ID = os.getenv('CLIENT_ID')

# Your partner client secret.
CLIENT_SECRET = os.getenv('CLIENT_SECRET')

# Your Ulule user username.
USERNAME = os.getenv('USERNAME')

# Your Ulule user password.
PASSWORD = os.getenv('PASSWORD')

# We need to encode the client ID and client secret in base64 before
# passing it as a header.
def get_basic_auth_header(user, password):
    user_pass = '{0}:{1}'.format(user, password)
    auth_string = base64.b64encode(user_pass.encode('utf-8'))
    auth_headers = {'AUTHORIZATION': 'Basic ' + auth_string.decode("utf-8")}
    return auth_headers

# Execute the POST request with: grant_type, username and password as
# POST parameters. Do not forget to add HTTP Basic header.
response = requests.post(
    'https://www.ulule.com/oauth2/token/',
    data={
        'grant_type': 'password',
        'username': USERNAME,
        'password': PASSWORD,
    },
    headers=get_basic_auth_header(CLIENT_ID, CLIENT_SECRET))

# Our response.
data = response.json()

# We expect a 200 status code.
assert response.status_code == 200

print('Access-Token: %s' % data.get('access_token'))
print('Refresh-Token: %s' % data.get('refresh_token'))

This script can be easily translatable in your favorite langage.

You can run this script by installing requests package and passing variables as environment variables:

$ pip install requests
$ CLIENT_ID=your-client-id CLIENT_SECRET=your-client-secret USERNAME=user-username PASSWORD=user-password python access_token.py

Access-Token: user-access-token
Refresh-Token: user-refresh-token

You have now an access token to authenticate automatically the user on Ulule.

Refresh your access token

An access token will be only available 10 hours.

As we assume you don’t store your user passwords in plain text in your database you don’t have a way to generate a new access token automatically without asking the user credentials again.

In term of user experience it will be a disaster for your application.

We are introducing the concept of refresh token which will allow you to generate a new access token:

# refresh_token.py
import base64
import os

import requests

# Your partner client ID.
CLIENT_ID = os.getenv('CLIENT_ID')

# Your partner client secret.
CLIENT_SECRET = os.getenv('CLIENT_SECRET')

# Your refresh token.
REFRESH_TOKEN = os.getenv('REFRESH_TOKEN')

# We need to encode the client ID and client secret in base64 before
# passing it as a header.
def get_basic_auth_header(user, password):
    user_pass = '{0}:{1}'.format(user, password)
    auth_string = base64.b64encode(user_pass.encode('utf-8'))
    auth_headers = {'AUTHORIZATION': 'Basic ' + auth_string.decode("utf-8")}
    return auth_headers

# Execute the POST request with: grant_type and refresh_token
# POST parameters. Do not forget to add HTTP Basic header.
response = requests.post(
    'https://www.ulule.com/oauth2/token/',
    data={
        'grant_type': 'refresh_token',
        'refresh_token': REFRESH_TOKEN,
    },
    headers=get_basic_auth_header(CLIENT_ID, CLIENT_SECRET))

# Our response.
data = response.json()

# We expect a 200 status code.
assert response.status_code == 200

print('Access-Token: %s' % data.get('access_token'))

You can run this script by installing requests package and passing variables as environment variables:

$ pip install requests
$ CLIENT_ID=your-client-id CLIENT_SECRET=your-client-secret REFRESH_TOKEN=user-refresh-token python refresh_token.py

Access-Token: user-access-token

You have now a new access token to re-authenticate the user on Ulule.

Checkout integration

Currently checkout pages will stay on Ulule to avoid you reimplementing payment workflow (credit card, paypal, etc.), sign up workflow, ...

Now you know how to retrieve an access_token for a user, you have to send a POST request to the project checkout page on Ulule website.

To integrate the checkout worflow of a project, this one has to be currently funding and online.

Example

We will integrate Noob, le film ! checkout page.

You will send a POST request from your website to https://fr.ulule.com/noob-le-film/checkout/ with the following parameters:

Parameter Description
reward The id of the reward you want to select
amount The amount you want to give

The reward parameter value can be found the rewards section in project api.

Control the workflow

When redirecting the user to the checkout page on Ulule, you can also control the return of the user after his contribution to your website and flag his contribution to your partner.

Parameter Description
partner The partner unique id
return_url The return url which will be inserted at the end of the process

These parameters must be added to the checkout url as query string:

https://www.ulule.com/noob-le-film/checkout/?access_token=[user-access-token]&partner=[partner-key]&return_url=http://your-site.com/

Ulule Connect

Ulule Connect allows users to connect their Ulule account to partner websites.

The worklow is:

  1. User is on partner website
  2. Partner needs to access user data
  3. User clicks on “Sign In” button on partner website
  4. This button redirects on Ulule Connect URL
  5. If the user does not have an existing Ulule account, she can create one
  6. If the user already has an account, she can sign in with her Ulule credentials
  7. At the end of sign in / sign up process, user will be redirected to the redirect_uri
  8. The user access token will be returned in the redirect_uri

Ulule Connect is based on OAuth2 protocol.

The Ulule Connect URL is https://www.ulule.com/oauth2/authorize.

This URL requires three GET parameters.

Parameter Description
client The partner client ID
response_type The OAuth2 response type (token or code)
redirect_uri The registered partner redirect URI

Ulule Connect URL examples:

https://www.ulule.com/oauth2/authorize?client_id=1a2b3c4d&response_type=code&redirect_uri=http://example.com
https://www.ulule.com/oauth2/authorize?client_id=1a2b3c4d&response_type=token&redirect_uri=http://example.com

A convenient way is to use this URL in a pop-up.

Ulule Connect sign in / sign up form Ulule Connect authorization page

Response Types

Type Description
code OAuth2 authorization code to request a token
token Directly returns access token in redirect URI

If you choose code as response type (OAuth2 authorization grant method), you can obtain a token back with the returned code.

To do so, simply make a POST request on https://www.ulule.com/oauth2/token/ with your partner client ID and client secret in HTTP Basic header and the following POST parameters:

Parameter Value
grant_type authorization_code
code The returned code
redirect_uri The redirected URI used to obtain the code

Take a look with this Python script:

# access_token_from_code.py
import base64
import os

import requests

# Your partner client ID.
CLIENT_ID = os.getenv('CLIENT_ID')

# Your partner client secret.
CLIENT_SECRET = os.getenv('CLIENT_SECRET')

# Your grant code.
GRANT_CODE = os.getenv('GRANT_CODE')

# Your registered redirect URI.
REDIRECT_URI = os.getenv('REDIRECT_URI')

# We need to encode in base64 the client_id and client_secret before
# before passing it as a header.
def get_basic_auth_header(user, password):
    user_pass = '{0}:{1}'.format(user, password)
    auth_string = base64.b64encode(user_pass.encode('utf-8'))
    auth_headers = {'AUTHORIZATION': 'Basic ' + auth_string.decode("utf-8")}
    return auth_headers

# Execute the POST request with: grant_type, code and redirect_uri as
# POST parameters. Do not forget to add HTTP Basic header.
response = requests.post(
    'https://www.ulule.com/oauth2/token/',
    data={
        'grant_type': 'authorization_code',
        'code': GRANT_CODE,
        'redirect_uri': REDIRECT_URI,
    },
    headers=get_basic_auth_header(CLIENT_ID, CLIENT_SECRET))

# Our response.
data = response.json()

# We expect a 200 status code.
assert response.status_code == 200

print('Access-Token: %s' % data.get('access_token'))
print('Refresh-Token: %s' % data.get('refresh_token'))

You can run this script by installing requests package and passing variables as environment variables:

$ pip install requests
$ CLIENT_ID=your-client-id CLIENT_SECRET=your-client-secret GRANT_CODE=your-grant-code REDIRECT_URI=your-redirect-uri python access_token_from_code.py

Access-Token: user-access-token
Refresh-Token: user-refresh-token

If you choose token, you don’t have to do anything else. The access token will be returned in the redirect URI as URL fragment.

Redirect URI

The redirect URI, or “redirection endpoint”, is used to redirect user after sign in or sign up. Only registered redirect URIs are allowed. You can use, obviously, only one registered URI in Ulule Connect URL but you can register as many ones as you need.

Webhooks

Use webhooks to be notified about events that happen in a Ulule account.

Webhooks solve multiple problems by letting you register a URL that we will notify you anytime an event happens in your account.

When the event occurs—for example when a successful order is made in one of your projects, Ulule creates an Event object. This object contains all the relevant information, including the type of event and the URI of the resource associated with that event.

Ulule then sends an HTTP POST request with the Event object to the registered URL in your partner account.

Configuring webhook

Configuring your server to receive a new webhook is no different from creating any page on your website.

With PHP, you might create a new .php file on your server; with a framework like Flask, you would add a new route with the desired URL.

Remember, with webhooks, your server is the server receiving the request.

Webhook data is sent as JSON in the request’s body. The full event details are included and can be used directly.

To retrieve the resource attached to the Event you may need to request the API with the uri attribute:

{
    "type": "project.created",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "project",
        "uri": "https://api.ulule.com/v1/projects/noob-le-film"
    }
}

Event list

project.created

Occurs when a project is created.

{
    "type": "project.created",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "project",
        "uri": "https://api.ulule.com/v1/projects/noob-le-film"
    }
}
project.published

Occurs when a project is put online by the project owner or the moderation team.

{
    "type": "project.published",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "project",
        "uri": "https://api.ulule.com/v1/projects/noob-le-film"
    }
}
project.submitted

Occurs when a project is submitted to moderation by a project owner.

{
    "type": "project.submitted",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "project",
        "uri": "https://api.ulule.com/v1/projects/noob-le-film"
    }
}
project.updated

Occurs whenever a project property has changed.

{
    "type": "project.updated",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "project",
        "uri": "https://api.ulule.com/v1/projects/noob-le-film"
    }
}
order.completed

Occurs when an order is completed and validated by a contributor, the following order will be reported to the project gauge.

{
    "type": "order.completed",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "order",
        "uri": "https://api.ulule.com/v1/orders/225885"
    }
}
order.cancelled

Occurs when an order is cancelled by a contribution, project properties will be updated.

{
    "type": "order.cancelled",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "order",
        "uri": "https://api.ulule.com/v1/orders/225885"
    }
}
order.reimbursed

Occurs when an order is reimbursed, project properties will be updated.

User should be redirected to its wallet settings. The user wallet settings URL is returned in the urls attribute of user resource.

{
    "type": "order.reimbursed",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "order",
        "uri": "https://api.ulule.com/v1/orders/225885"
    }
}
order.paid

Occurs when an order is set as paid, the project is successfully funded and the billing team launch payments, each order will be marked as paid.

{
    "type": "order.paid",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "order",
        "uri": "https://api.ulule.com/v1/orders/225885"
    }
}
order.updated

Occurs when an order property has changed.

{
    "type": "order.updated",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "order",
        "uri": "https://api.ulule.com/v1/orders/225885"
    }
}
proposal.validated

Occurs when a proposal is validated by the moderation team, it will create a project with the proposal properties.

{
    "type": "proposal.validated",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "proposal",
        "uri": "https://api.ulule.com/v1/proposals/6047"
    }
}
proposal.created

Occurs when a proposal is created by a user.

{
    "type": "proposal.created",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "proposal",
        "uri": "https://api.ulule.com/v1/proposals/6047"
    }
}
user.created

Occurs when a user is created.

{
    "type": "user.created",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "user",
        "uri": "https://api.ulule.com/v1/users/thoas"
    }
}
user.updated

Occurs when a user property has changed.

{
    "type": "user.updated",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "user",
        "uri": "https://api.ulule.com/v1/users/thoas"
    }
}
avatar.updated

Occurs when a user avatar has changed.

{
    "type": "avatar.updated",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "user",
        "uri": "https://api.ulule.com/v1/users/thoas"
    }
}
news.updated

Occurs when a project news property has changed.

{
    "type": "news.updated",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "news",
        "uri": "https://api.ulule.com/v1/news/72653"
    }
}
news.published

Occurs when a project news is published.

{
    "type": "news.published",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "news",
        "uri": "https://api.ulule.com/v1/news/72653"
    }
}
news.created

Occurs when a project news is created.

{
    "type": "news.created",
    "object": "event",
    "created": "2015-09-01T16:40:05.805422",
    "resource": {
        "type": "news",
        "uri": "https://api.ulule.com/v1/news/72653"
    }
}

Partners

To activate your partner account, you must contact the Technical support.

For all POST operations you will ask to ask to enable the third party authentication.

User

List orders

You will only retrieve information for users which had been registered via your partner website.

Retrieve valid orders from a specific user.

GET /users/:id/orders

User orders.

Request

GET /users/3048/orders HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

Order

Get detail

Retrieve order detail.

GET /orders/:id

Order detail.

GET /orders/1 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Response

HTTP/1.1 200 OK
Vary: Accept
Content-Type: text/javascript

{
  "order_total": "80.00",
  "order_subtotal": "80.00",
  "shipping_address": null,
  "billing_address": null,
  "items": [
      {
          "product": 1337,
          "quantity": 1,
          "line_total": "80.00",
          "unit_price": "80.00"
      }
  ],
  "id": 1,
  "resource_uri": "https://api.ulule.com/v1/orders/1",
  "project_uri": "https://api.ulule.com/v1/projects/noob-le-film",
  "status": 4
  "status_display": "Payment completed"
}

Path parameters

id required, the order identifier

When you are retrieving an order you will except these statuses:

Label Code
Processing 1
Selecting payment 2
Awaiting confirmation 3
Payment completed 4
Shipped 5
Cancelled 6
Payment done 7
Aborted 8
Payment invalid 9
Payment reimbursed to e-wallet 10
Payment reimbursed 11
Error 12

Cancel

Cancel a given order.

As order cancelling is processed asynchronously, once cancelling is effective, refunded attribute will be set to true. User should be redirected to its wallet settings. The user wallet settings URL is returned in the urls attribute of user resource.

POST /orders/:id/cancel

Cancels a given order.

POST /orders/1/cancel HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Response

HTTP/1.1 200 OK
Vary: Accept
Content-Type: text/javascript

{
  "order_total": "80.00",
  "order_subtotal": "80.00",
  "shipping_address": null,
  "billing_address": null,
  "items": [
      {
          "product": 1337,
          "quantity": 1,
          "line_total": "80.00",
          "unit_price": "80.00"
      }
  ],
  "id": 1,
  "refunded": true,
  "resource_uri": "https://api.ulule.com/v1/orders/1",
  "project_uri": "https://api.ulule.com/v1/projects/noob-le-film",
  "status": 6,
  "status_display": "Cancelled"
}

Path parameters

id required, the order identifier

News

Create comment

Create a new comment on the news.

POST /news/:id/comments

Create a new comment on the news.

Request

POST /news/1/comments HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the news ID

POST parameters

comment the comment text

Projects

List orders

You will only retrieve information for projects which are online via your partner website.

Retrieve valid orders from a specific project.

GET /projects/:id/orders

Project orders.

Request

GET /projects/9892/orders HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

Partner

Projects

List projects

Retrieve all your projects linked to your partner website.

GET /partners/:slug/projects

Partner projects.

Request

GET /partners/ulule/projects HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

slug required, the partner key identifier

Proposals

A proposal must be affected to an existing user. Before creating a proposal, your must create a new user on your partner or use an existing one and send us the access_token of the user in the workflow:

$ curl -H "Authorization: Bearer USER-ACCESS-TOKEN"  https://api.ulule.com/v1/...

There are two types of project on Ulule, when you are creating a new proposal you must specify if the proposal is for a presale or a project.

When you are submitting the type in your POST parameters you must specify the following codes:

Type Code
Presale 1
Project 2
Create “project” proposal

Create a new “project” proposal for a user.

POST /users/:id/proposals

Create a new “project” proposal for a user.

Request

POST /users/3048/proposals HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

POST parameters

first_name required, the first name (30 characters max.) last_name required, the last name (30 characters max.) name required, the name of the project (255 characters max.) type required, the type of your proposal goal required, the amount you have to raised currency required, the currency used, you must use a valid currency code (3 characters max.) lang required, the lang used, you must use a valid language code (5 characters max.) description required rewards required references required phone_number required (15 characters max.) nationality required, the project owner nationality, you must use a valid country code country required, you must use a valid country code (2 characters) address required birthday required, the birthday of the project owner (format: YYYY-MM-DD) structure optional, the proposal structure (150 characters max.)

Response

HTTP/1.1 201 CREATED
Vary: Accept
Content-Type: text/javascript
Create “presale” proposal

Create a new “presale” proposal for a user.

POST /users/:id/proposals

Create a new “presale” proposal for a user.

Request

POST /users/3048/proposals HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

POST parameters

first_name required, the first name (30 characters max.) last_name required, the last name (30 characters max.) name required, the name of the project (255 characters max.) type required, the type of your proposal nb_products_min required, the number of products you have to sell currency required, the currency used, you must use a valid currency code (3 characters max.) lang required, the lang used, you must use a valid language code (5 characters max.) description required rewards required references required phone_number required (15 characters max.) nationality required, the project owner nationality, you must use a valid country code country required, you must use a valid country code (2 characters) address required birthday required, the birthday of the project owner (format: YYYY-MM-DD) structure optional, the proposal structure (150 characters max.)

Response

HTTP/1.1 201 CREATED
Vary: Accept
Content-Type: text/javascript
List proposals

Retrieve all your proposals which had been registered in your partner website.

GET /partners/:slug/proposals

Partner proposals.

Request

GET /partners/ulule/proposals HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

partner required, the partner key identifier

List valid proposals

Retrive proposals which have been validated by the partner.

GET /partners/:slug/proposals?filter=valid

Users for a partner

Request

GET /partners/ulule/proposals HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

slug required, the partner key identifier

Query parameters

filter the current filter for proposals

List invalid proposals

Retrieve proposals which have been not validated by the partner.

GET /partners/:slug/proposals?filter=invalid

Users for a partner

Request

GET /partners/ulule/proposals HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

partner required, the partner key identifier

Query parameters

filter the current filter for proposals

List new proposals

Retrieve new proposals which have to be processed by the partner.

GET /partners/:slug/proposals?filter=new

Users for a partner

Request

GET /partners/ulule/proposals HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

slug required, the partner key identifier

Query parameters

filter the current filter for proposals

Users

Create user
POST /partners/:slug/users

Create a new user for a dedicated partner.

Request

POST /partners/ulule/users HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

partner required, the partner key identifier

POST parameters

username required, the username (80 characters max.) password1 required, the password email required, the email (75 characters max.)

Response

HTTP/1.1 201 CREATED
Vary: Accept
Content-Type: text/javascript

{
  "date_joined": "2011-02-02T12:29:06",
  "id": 3048,
  "is_active": true,
  "last_login": "2014-02-03T10:11:26.586862",
  "public_url": "http://www.ulule.com/thoas/",
  "resource_uri": "/api/v1/users/thoas/",
  "username": "thoas"
}
List users

Retrieve all your users which had been registered in your partner website.

GET /partners/:slug/users

Users for a partner

Request

GET /partners/ulule/users HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

slug required, the partner key identifier

Examples

Generate stats for a project

Generate supporters by years, months and days for a project.

We want a sortable result which will returns the number of supporters for a project organized by years, months and days, for example

{
    2014: {
        1: {
            30: 9, # 30 january 2014 - 9 supporters
            31: 10 # 31 january 2014 - 10 supporters
        },
        2: {
            1: 3 # 1 february 2014 - 2 supporters
        }
    }
}

Let’s get to work!

To send requests to api.ulule.com we will use a couple of dependencies, the first part is to install them in Python:

$ pip install requests
$ pip install python-dateutil

Now we are done, we can start our tiny script to crawl the API:

import requests

from dateutil import parser
from collections import defaultdict

ULULE_USERNAME = 'YOUR USERNAME HERE'
ULULE_PASSWORD = 'YOUR PASSWORD HERE'

def stats(slug, username, password):
    base_url = u'https://api.ulule.com/v1/%s/supporters' % slug

    results = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))

    path = '?offset=0&limit=10'

    while path is not None:
        url = base_url + path

        r = requests.get(url, auth=(username, password))

        if r.status_code != 200:
            raise Exception(u'URL %s has returned an invalid http code(%s): %s' % (
                url,
                r.status_code,
                r.text
            ))

        result = r.json()

        path = result['meta']['next']

        for supporter in supporters:
            d = parser.parse(supporter['date_creation'])

            results[d.year][d.month][d.day] += 1

    return results

results = stats('noob-le-film', ULULE_USERNAME, ULULE_PASSWORD)

Et voilà! A quick way to generate statistics for a project, be careful of the rate of your requests to not fall in rate limit.

Export project contributors in JSON format

We want to export the contributors list in plain JSON using the API.

To use this script, you will have to have special permissions on the project or be the project owner.

As the previous example, we must install third party dependencies:

$ pip install requests

Now we are done, we can start our tiny script:

# export.py
import argparse
import requests
import json

BASE_URL = 'https://api.ulule.com/v1/projects/%s/orders'

parser = argparse.ArgumentParser(description='Export contributions in .json')
parser.add_argument('--username', dest='username',
                    help='Username of the Ulule account')
parser.add_argument('--slug', dest='slug',
                    help='Slug of the project on Ulule')
parser.add_argument('--api_key', dest='api_key',
                    help='Api key of the Ulule account')
parser.add_argument('--file', dest='file',
                    help='File to export contributions in json')


def get_basic_auth_header(user, password):
    """
    Return a dict containg the correct headers to set to make HTTP Basic Auth request
    """
    user_pass = '{0}:{1}'.format(user, password)
    auth_headers = {
        'AUTHORIZATION': 'ApiKey ' + user_pass,
    }

    return auth_headers


def main(ns):
    base_url = BASE_URL % ns.slug

    url = base_url

    headers = get_basic_auth_header(ns.username, ns.api_key)

    items = {}

    while True:
        response = requests.get(url, headers=headers)

        if response.status_code != 200:
            break

        results = response.json()

        print 'Fetching %s... %s items' % (url, len(results['orders']))

        for item in results['orders']:
            if item['status'] != 7:
                continue

            items[item['id']] = item

        next_page = results['meta']['next']

        if next_page is None:
            break

        url = base_url + next_page

    return items.values()


if __name__ == '__main__':
    args = parser.parse_args()

    results = main(args)

    if args.file:
        print 'Exporting %d items to %s' % (len(results), args.file)

        with open(args.file, 'w') as file:
            file.write(json.dumps(results))

Let’s use this script:

$ python export.py --username={username-on-ulule} --api_key={my-api-key} --slug={project-identifier} --file=contributors.json

Inspirations

To build this documentation, we have taken some parts and ideas from great documentations.

We would like to thank their authors: