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.

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

There are two types of error:

Type (classification) Description
RequiredError A required attribute is missing.
ValueError An attribute value is invalid (wrong format, unsupported, etc).

Errors always go with:

  • fieldNames: array of required/invalid fields
  • message: error description

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"
        ]
    }
]

Example

HTTP/1.1 422 UNPROCESSABLE ENTITY
Vary: Accept
Content-Type: text/javascript

 [
     {
         "classification": "RequiredError",
         "fieldNames": [
             "amount"
         ],
         "message": "Required"
     },
     {
         "classification": "RequiredError",
         "fieldNames": [
             "country"
         ],
         "message": "Country is required"
     },
     {
         "classification": "ValueError",
         "fieldNames": [
             "nationality"
         ],
         "message": "Nationality is invalid"
     },
     {
         "classification": "ValueError",
         "fieldNames": [
             "lang"
         ],
         "message": "Language is invalid"
     }
 ]

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
Catalan ca
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 the following http status code:

HTTP/1.1 501 Not Implemented

I18n attributes

Some payloads and resources take or include “i18n attributes”. An i18n attribute is a JSON object that contains field translations. Object keys can be any supported language. Object values are related translation strings.

Example:

"description": {
  "en": "This is a description in english",
  "fr": "Ceci est une description en français"
}

In this documentation, i18n attributes are referenced as object (i18n) type to clearly distinguish them from generic object type.

In order to get all the translations of an i18n field in the resource, the query string parameter ?lang=all must be specified in the URL for the three methods GET, POST and PATCH.

$ curl 'https://api.ulule.com/v1/rewards/9892/variants?lang=all'
"description": {
  "en": "This is a description in english",
  "fr": "Ceci est une description en français",
  "it": "Questo è descritto in italiano",
  "de": "",
  "ca": "",
  "es": ""
}

If the parameter lang is not specified in the URL, the resource returned will contain the translation for the parent object lang and the translations provided by the request.

Let’s take a project example with its main language set to en, if you update a reward with the following payload:

"description": {
  "fr": "ma superbe description"
}

The returned resource will contain the description in two languages:

  • en because it’s the main language
  • fr because it’s provided in the request
"description": {
  "en": "my awesome description",
  "fr": "ma superbe description"
}

Versioning

Ulule API has a system of versioning to manage upgrades. The API version controls the API behavior you see (e.g., what properties you see in responses, etc.).

When we introduce a backward incompatible change, we release a new dated version, but to avoid breaking your code, we don’t change your version until you’re ready to upgrade.

In order to use a version defined in the changelog, the version date must be specified in the header of the request with the parameter Ulule-Version.

GET /v1/projects/123 HTTP/1.1
Host: api.ulule.com
Ulule-Version: 2017-09-19

Changelog

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 your partner account with a pair of credentials (client_id and client_secret) which will allow you to request an access_token for a dedicated user.

There are three ways to authenticate through the API.

  • HTTP Basic authentication
  • API key authentication
  • OAuth2 token

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

HTTP Basic

$ 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

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 YOUR_API_KEY_HERE"  https://api.ulule.com/v1/...

OAuth2

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

You can pass it in each request as an authorization header:

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

Or can pass the access_token directly in a GET parameter:

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

Retrieve an access token

To retrieve an access token, we will use this REST endpoint

Request
POST https://www.ulule.com/oauth2/token/

Please, do not forget the slash at the end, just after “token”. This slash is required.

Request must be executed as an HTTP Basic Authentication request with your partner client_id and client_secret as credentials.

POST Parameters

Name Type Description
grant_type String Grant type (value must be password).
username String User username.
password String User password.

Example

$ curl -X POST \
       -d "grant_type=password&username=<username>&password=<password>" \
       -H "Authorization: basic PGNsaWVudF9pZD46PGNsaWVudF9zZWNyZXQ+" https://www.ulule.com/oauth2/token/

PGNsaWVudF9pZD46PGNsaWVudF9zZWNyZXQ+ is base64 of <client_id>:<client_secret>

Response
{
    "access_token": "PKs6dso48MPRPa4pcKjskjIFwpQMA3",
    "token_type": "Bearer",
    "expires_in": 36000,
    "refresh_token": "8Pbypw13OqJDeggvymoUc26djkPZ",
    "scope": "read write"
}

Or 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 only be 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.

Ulule Connect (OAuth2)

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, the interface will propose to create a new one
  6. If the user already has an account, it 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.

Core resources

Find below all resources endpoints. The API is based on a RESTful architecture (without HATEOAS). The request body and response body are always formatted in JSON.

User

For partner permissions, you will only retrieve information for users which had been registered via your partner website.

Get me

GET /me

Retrieve authenticated user details.

Access rights

Permissions:

  • User

Authentication mode:

Request

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

Response

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

{
  "id": 1257099,
  "date_joined": "2016-10-08T15:37:48Z",
  "first_name": "Julien",
  "has_avatar": true,
  "lang": "fr",
  "last_login": "2016-12-22T14:05:09.258787Z",
  "last_name": "FOO",
  "birthday": "1955-09-17",
  "country": "FR",
  "nationality": "FR",
  "location": "8 rue saint Fiacre, Paris",
  "name": "Julien FOO",
  "is_staff": false,
  "username": "julien-foo",
  "timezone": "Europe/Paris",
  "is_completed": true,
  "absolute_url": "https://www.ulule.com/julien-foo",
  "resource_uri": "https://api.ulule.com/v1/users/123",
  "avatar": {
    "id": 123,
    "versions": {
      "20x20": {
        "width": 20,
        "height": 20,
        "url": "https://img.ulule.com/display/d1b7.../user.092557.jpeg"
      },
      "30x30":{
        "width": 30,
        "height": 30,
        "url": "https://img.ulule.com/display/dc27.../user.092557.jpeg"
      },
      "40x40":{
        "width": 40,
        "height": 40,
        "url": "https://img.ulule.com/display/feac.../user.092557.jpeg"
      },
      "55x55":{
        "width": 55,
        "height": 55,
        "url": "https://img.ulule.com/display/fc6a.../user.092557.jpeg"
      },
      "75x75":{
        "width": 75,
        "height": 75,
        "url": "https://img.ulule.com/display/6821.../user.092557.jpeg"
      },
      "90x90":{
        "width": 90,
        "height": 90,
        "url": "https://img.ulule.com/display/8968.../user.092557.jpeg"
      },
      "128x128":{
        "width": 128,
        "height": 128,
        "url": "https://img.ulule.com/display/243.../user.092557.jpeg"
      },
      "180x180":{
        "width": 180,
        "height": 180,
        "url": "https://img.ulule.com/display/538.../user.092557.jpeg"
      },
      "230x230":{
        "width": 230,
        "height": 230,
        "url": "https://img.ulule.com/display/e7c.../user.092557.jpeg"
      },
      "290x290":{
        "width": 290,
        "height": 290,
        "url": "https://img.ulule.com/display/674.../user.092557.jpeg"
      },
      "full":{
        "width": null,
        "height": null,
        "url": "https://drfhlmcehrc34.cloudfront.net/avatar/.../user.092557.jpeg"
      }
    },
    "name": "avatar.jpeg",
    "value": "avatar/.../user.092550.092557.jpeg"
  },
  "description": {
    "en": "my description",
    "fr": "ma description",
    "de": "",
    "it": "",
    "ca": "",
    "nl": "",
    "es": ""
  },
  "presentation": {
    "en": "my presentation",
    "fr": "ma presentation",
    "de": "",
    "it": "",
    "ca": "",
    "nl": "",
    "es": ""
  },
  "screenname": "julien-foo",
  "email": "foo@email.com",
  "personal_id_number": null
}

Get user

GET /users/:id

Retrieve user detail.

Access rights

Permissions:

  • User
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the user ID

Response

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

{
  "id": 1257099,
  "date_joined": "2016-10-08T15:37:48Z",
  "first_name": "Julien",
  "has_avatar": true,
  "lang": "fr",
  "last_login": "2016-12-22T14:05:09.258787Z",
  "last_name": "FOO",
  "birthday": "1955-09-17",
  "country": "FR",
  "nationality": "FR",
  "location": "8 rue saint Fiacre, Paris",
  "name": "Julien FOO",
  "is_staff": false,
  "username": "julien-foo",
  "timezone": "Europe/Paris",
  "is_completed": true,
  "absolute_url": "https://www.ulule.com/julien-foo",
  "resource_uri": "https://api.ulule.com/v1/users/123",
  "avatar": {
    "id": 123,
    "versions": {
      "20x20": {
        "width": 20,
        "height": 20,
        "url": "https://img.ulule.com/display/d1b7.../user.092557.jpeg"
      },
      "30x30":{
        "width": 30,
        "height": 30,
        "url": "https://img.ulule.com/display/dc27.../user.092557.jpeg"
      },
      "40x40":{
        "width": 40,
        "height": 40,
        "url": "https://img.ulule.com/display/feac.../user.092557.jpeg"
      },
      "55x55":{
        "width": 55,
        "height": 55,
        "url": "https://img.ulule.com/display/fc6a.../user.092557.jpeg"
      },
      "75x75":{
        "width": 75,
        "height": 75,
        "url": "https://img.ulule.com/display/6821.../user.092557.jpeg"
      },
      "90x90":{
        "width": 90,
        "height": 90,
        "url": "https://img.ulule.com/display/8968.../user.092557.jpeg"
      },
      "128x128":{
        "width": 128,
        "height": 128,
        "url": "https://img.ulule.com/display/243.../user.092557.jpeg"
      },
      "180x180":{
        "width": 180,
        "height": 180,
        "url": "https://img.ulule.com/display/538.../user.092557.jpeg"
      },
      "230x230":{
        "width": 230,
        "height": 230,
        "url": "https://img.ulule.com/display/e7c.../user.092557.jpeg"
      },
      "290x290":{
        "width": 290,
        "height": 290,
        "url": "https://img.ulule.com/display/674.../user.092557.jpeg"
      },
      "full":{
        "width": null,
        "height": null,
        "url": "https://drfhlmcehrc34.cloudfront.net/avatar/.../user.092557.jpeg"
      }
    },
    "name": "avatar.jpeg",
    "value": "avatar/.../user.092550.092557.jpeg"
  },
  "description": {
    "en": "my description",
    "fr": "ma description",
    "de": "",
    "it": "",
    "ca": "",
    "nl": "",
    "es": ""
  },
  "presentation": {
    "en": "my presentation",
    "fr": "ma presentation",
    "de": "",
    "it": "",
    "ca": "",
    "nl": "",
    "es": ""
  },
  "screenname": "julien-foo",
  "email": "foo@email.com",
  "personal_id_number": null
}

Deprecated

Deprecated fields are present in the avatar subresource for backward compatibility

{
  ...,
  "avatar": {
    "20": "https://img.ulule.com/.../20x20.../julien-foo.jpg",
    "30": "https://img.ulule.com/.../30x30.../julien-foo.jpg",
    "40": "https://img.ulule.com/.../40x40.../julien-foo.jpg",
    "55": "https://img.ulule.com/.../55x55.../julien-foo.jpg",
    "75": "https://img.ulule.com/.../75x75.../julien-foo.jpg",
    "90": "https://img.ulule.com/.../90x90.../julien-foo.jpg",
    "128": "https://img.ulule.com/.../128x128.../julien-foo.jpg",
    "180": "https://img.ulule.com/.../180x180.../julien-foo.jpg",
    "230": "https://img.ulule.com/.../230x230.../julien-foo.jpg",
    "290": "https://img.ulule.com/.../290x290.../julien-foo.jpg",
    "full": "https://drfhlmcehrc34.cloudfront.net.../julien-foo.jpg",
  },
  ...
}

Create user

POST /partners/:slug/users

Create a new user for a dedicated partner.

Access rights

Permissions:

  • Partner

Authentication mode:

Request

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

Path parameters

partner the partner key identifier

POST parameters

username string Username – max 80 characters (required) password1 string Password – max 128 characters (required) email string Email – max 254 characters (required) lang string Default user language (optional) ip_address string IP address (optional)

(for ip_address use IPv4 format or IPv6 format)

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"
}

Update user

PATCH /users/:id

Update attributes for a given user.

Access rights

Permissions:

  • User
  • Partner

Authentication mode:

Request

PATCH /users/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

PATCH parameters

nationality string Nationality – ISO 3166-1 code (optional) country string Country of residence – ISO 3166-1 code (optional) birthday string Birth date – formatted as YYYY-MM-DD and year must be higher to 1901 (optional) location string Location – max. 250 characters (optional) screenname string Screen name – max. 30 characters (optional) first_name string First name – max. 30 characters (optional) last_name string Last name – max. 30 characters (optional) email string Email (optional) lang string Any supported language – de, en, es, fr, it, nl (optional) ip_address string IP address (optional) description object Description in different languages (optional) presentation object Presentation in different languages (optional)

The parameter “ip_address” must be conform to IPv4 or IPv6 format.

Example

{
  "nationality": "FR",
  "screenname": "Gilles Fabio",
  "country": "FR",
  "birthday": "1982-11-01",
  "location": "14, rue saint Fiacre, Paris",
  "first_name": "Gilles",
  "last_name": "Fabio",
  "email": "gilles@ulule.com",
  "lang": "fr",
  "description": {
    "fr": "ma description",
    "en": "my description"
  },
  "presentation": {
    "fr": "ma présentation",
    "en": "my presentation"
  }
}

Response

If a user has provided all required information, is_completed attribute will be set to true.

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

  {
   "id": 52547,
   "avatar": {
      "id": 123,
      "versions": {
        "20x20": {
          "width": 20,
          "height": 20,
          "url": "https://img.ulule.com/display/d1b7.../user.092557.jpeg"
        },
        "30x30":{
          "width": 30,
          "height": 30,
          "url": "https://img.ulule.com/display/dc27.../user.092557.jpeg"
        },
        "40x40":{
          "width": 40,
          "height": 40,
          "url": "https://img.ulule.com/display/feac.../user.092557.jpeg"
        },
        "55x55":{
          "width": 55,
          "height": 55,
          "url": "https://img.ulule.com/display/fc6a.../user.092557.jpeg"
        },
        "75x75":{
          "width": 75,
          "height": 75,
          "url": "https://img.ulule.com/display/6821.../user.092557.jpeg"
        },
        "90x90":{
          "width": 90,
          "height": 90,
          "url": "https://img.ulule.com/display/8968.../user.092557.jpeg"
        },
        "128x128":{
          "width": 128,
          "height": 128,
          "url": "https://img.ulule.com/display/243.../user.092557.jpeg"
        },
        "180x180":{
          "width": 180,
          "height": 180,
          "url": "https://img.ulule.com/display/538.../user.092557.jpeg"
        },
        "230x230":{
          "width": 230,
          "height": 230,
          "url": "https://img.ulule.com/display/e7c.../user.092557.jpeg"
        },
        "290x290":{
          "width": 290,
          "height": 290,
          "url": "https://img.ulule.com/display/674.../user.092557.jpeg"
        },
        "full":{
          "width": null,
          "height": null,
          "url": "https://drfhlmcehrc34.cloudfront.net/avatar/.../user.092557.jpeg"
        }
      },
      "name": "avatar.jpeg",
      "value": "avatar/.../user.092550.092557.jpeg"
   },
   "date_joined": "2012-06-07T11:10:50Z",
   "first_name": "Gilles",
   "has_avatar": true,
   "lang": "fr",
   "last_login": "2016-07-06T15:58:21.144092Z",
   "last_name": "Fabio",
   "birthday": "1982-11-01",
   "name": "gillesfabio",
   "is_staff": true,
   "country": "FR",
   "nationality": "FR",
   "location": "14, rue saint Fiacre, Paris",
   "username": "gillesfabio",
   "timezone": "Europe/Paris",
   "absolute_url": "https://www.ulule.com/gillesfabio",
   "resource_uri": "https://api.ulule.com/v1/users/52547",
   "screenname": "gilles-fabio",
   "email": "gilles@ulule.com",
   "description": {
     "en": "my description",
     "fr": "ma description",
     "de": "",
     "it": "",
     "ca": "",
     "nl": "",
     "es": ""
   },
  "presentation": {
    "en": "my presentation",
    "fr": "ma presentation",
    "de": "",
    "it": "",
    "ca": "",
    "nl": "",
    "es": ""
   },
   "is_completed": true
}

Deprecated

Deprecated fields are present in the avatar subresource for backward compatibility

{
  ...,
  "avatar": {
    "20": "https://img.ulule.com/.../20x20.../julien-foo.jpg",
    "30": "https://img.ulule.com/.../30x30.../julien-foo.jpg",
    "40": "https://img.ulule.com/.../40x40.../julien-foo.jpg",
    "55": "https://img.ulule.com/.../55x55.../julien-foo.jpg",
    "75": "https://img.ulule.com/.../75x75.../julien-foo.jpg",
    "90": "https://img.ulule.com/.../90x90.../julien-foo.jpg",
    "128": "https://img.ulule.com/.../128x128.../julien-foo.jpg",
    "180": "https://img.ulule.com/.../180x180.../julien-foo.jpg",
    "230": "https://img.ulule.com/.../230x230.../julien-foo.jpg",
    "290": "https://img.ulule.com/.../290x290.../julien-foo.jpg",
    "full": "https://drfhlmcehrc34.cloudfront.net.../julien-foo.jpg",
  },
  ...
}

List partner users

GET /partners/:slug/users

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

Access rights

Permissions:

  • Partner

Authentication mode:

Request

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

Path parameters

slug the partner key identifier

List project supporters

For partner permissions, you will only retrieve information for projects which are online via your partner website.

GET /projects/:id/supporters

Retrieve project supporters (organized in a pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Address

Get address

GET /addresses/:id

Retrieve a given address.

Access rights

Permissions:

  • Address owner
  • Partner

Authentication mode:

Request

GET /addresses/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the address ID

Response

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

{
   "id": 1,
   "first_name": "Florent",
   "last_name": "Foo",
   "entity_name": "work",
   "address1": "8 Rue Saint-Fiacre",
   "address2": "",
   "postal_code": "75002",
   "city": "Paris",
   "state": "",
   "country": "FR",
   "user_id": 3048,
   "type": "business"
}

Create user address

POST /users/:id/addresses

Create an address for a given user.

Access rights

Permissions:

  • User
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the user ID

POST parameters

type string Type – “personal”, “business” or “association” (defaults to “personal”) first_name string First name – max 30 characters (required if type is “personal”) last_name string Last name – max 30 characters (required if type is “personal”) entity_name string Name of business or association – max 250 characters (required if type is “business” or “association”) address1 string Street – max 255 characters (optional) address2 string Street complementary – max 255 characters (optional) postal_code string Postal code – max 140 characters (optional) city string City – max 140 characters (optional) state string State – max 255 characters (optional) country string Country – ISO 3166-1 code (optional)

Example

{
   "entity_name": "work",
   "first_name": "Florent",
   "last_name": "Foo",
   "address1": "8 Rue Saint-Fiacre",
   "postal_code": "75002",
   "city": "Paris",
   "country": "FR",
   "type": "business"
}

Response

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

{
   "id": 555200,
   "first_name": "Florent",
   "last_name": "Foo",
   "entity_name": "work",
   "address1": "8 Rue Saint-Fiacre",
   "address2": "",
   "postal_code": "75002",
   "city": "Paris",
   "state": "",
   "country": "FR",
   "user_id": 3048,
   "type": "business"
}

Update address

PATCH /addresses/:id

Update a given address.

Access rights

Permissions:

  • Address owner
  • Partner

Authentication mode:

Request

PATCH /addresses/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

PATCH parameters

type string Type – “personal”, “business” or “association” first_name string First name – max 30 characters last_name string Last name – max 30 characters entity_name string Name of business or association – max 250 characters address1 string Street – max 255 characters address2 string Street complementary – max 255 characters postal_code string Postal code – max 140 characters city string City – max 140 characters state string State – max 255 characters country string Country – ISO 3166-1 code

The country can’t be updated if the address belongs to an order with shippings.

Example

{
   "entity_name": "work",
   "first_name": "Florent",
   "last_name": "Foo",
   "address1": "8 Rue Saint-Fiacre",
   "postal_code": "75002",
   "city": "Paris",
   "country": "FR",
   "type": "business"
}

Response

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

{
   "id": 555200,
   "first_name": "Florent",
   "last_name": "Foo",
   "entity_name": "work",
   "address1": "8 Rue Saint-Fiacre",
   "address2": "",
   "postal_code": "75002",
   "city": "Paris",
   "state": "",
   "country": "FR",
   "user_id": 3048,
   "type": "business"
}

Delete address

DELETE /addresses/:id

Delete a given address.

Access rights

Permissions:

  • Address owner
  • Partner

Authentication mode:

Request

DELETE /addresses/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the address ID

Response

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

List user addresses

GET /users/:id/addresses

Retrieve addresses for a given user.

Access rights

Permissions:

  • User
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the user ID

Response

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

{
   "addresses": [
         {
            "id": 555200,
            "first_name": "Florent",
            "last_name": "Foo",
            "entity_name": "",
            "address1": "8 Rue Saint-Fiacre",
            "address2": "",
            "postal_code": "75002",
            "city": "Paris",
            "state": "",
            "country": "FR",
            "user_id": 3048
         }
   ]
}

Project

There are two kinds of project on Ulule: presales and projects.

They are represented by a string in the type field: presale or project.

In addition, the value of the goal field depends on the project type: it is a number of presales for a presale and an amount for a project.

Kind Type Goal
Presale 1 Number of presales
Project 2 Amount

The project status can have the following values:

Status Description
new Project has been created from a validated proposal
pending Project owner has submitted the project to validation
pending-owner Staff is waiting for a change or an answer from project owner
pending-final-validation Staff has sent the project to final validation
validated Staff has validated the project
online Project owner has published the project
refused Staff has refused the project
waiting Staff has put the project to a waiting state

The duration of the founding campaign is described with two fields: nb_days and date_end. If both fields are set, date_end takes precedence over nb_days. date_end is required for a project to go online.

Get project

GET /projects/:id

Retrieve project detail.

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

{
  "id": 19895,
  "amount_raised": 33928,
  "comments_count": 255,
  "committed": 33928,
  "country": "FR",
  "currency": "EUR",
  "currency_display": "€",
  "date_end": "2014-11-21T21:59:59Z",
  "nb_days": null,
  "date_start": "2014-10-17T00:00:00Z",
  "finished": true,
  "goal": 30000,
  "goal_raised": true,
  "is_online": true,
  "is_cancelled": false,
  "lang": "fr",
  "nb_products_sold": 1082,
  "news_count": 27,
  "percent": 113,
  "slug": "2dark",
  "status": "online",
  "supporters_count": 1082,
  "timezone": "Europe/Paris",
  "type": "project",
  "payment_methods": [
    "check",
    "creditcard",
    "paypal"
  ],
  "lowest_contribution_amount": 5,
  "background": {
    "color": "",
    "url": "https://drfhlmcehrc34.cloudfront.net/presales/5/9/8/19895/fond_ulule_02.png"
  },
  "main_image": {
    "value": "presales/5/9/8/19895/fin.jpg",
    "versions": {
      "small": {
        "width": 230,
        "heigth": 126,
        "url": "https://.../230x126/images/my_picture.jpg"
      },
      "medium": {
        "width": 258,
        "heigth": 145,
        "url": "https://.../258x145/images/my_picture.jpg"
      },
      "large": {
        "width": 640,
        "heigth": 360,
        "url": "https://.../640x360/images/my_picture.jpg"
      },
      "full": {
        "width": null,
        "heigth": null,
        "url": "https://.../images/my_picture.jpg"
      }
    }
  },
  "video": {
    "id": 16122,
    "language": "en",
    "author_name": "Gloomywood",
    "author_url": "https://www.youtube.com/channel/UCfzEuq8J8KzDlpDM_RXeOLg",
    "height": 270,
    "html": "<iframe width=\"480\" height=\"270\" src=\"https://www.youtube.com/embed/tLqlNvv7KiI?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
    "provider_name": "YouTube",
    "provider_url": "https://www.youtube.com/",
    "thumbnail_height": 360,
    "thumbnail_url": "https://i.ytimg.com/vi/tLqlNvv7KiI/hqdefault.jpg",
    "thumbnail_width": 480,
    "title": "2Dark - Ulule campaign",
    "type": "video",
    "url": "http://youtu.be/tLqlNvv7KiI",
    "version": "",
    "width": 480
  },
  "main_tag": {
    "id": 10,
    "position": 5,
    "slug": "games",
    "absolute_url": "https://www.ulule.com/discover/tags/games",
    "name": {
      "en": "Games",
      "fr": "Jeux"
    }
  },
  "rewards": [
    {
      ... // reward resource
    },
    ...
  ],
  "location": {
    "name": "Lyon, FR",
    "full_name": "Lyon, Rhone-Alpes, FR",
    "country": "FR",
    "region": "Rhone-Alpes",
    "city": "Lyon"
  },
  "absolute_url": "https://www.ulule.com/2dark/",
  "resource_uri": "https://api.ulule.com/v1/projects/19895",
  "urls": {
    "web": {
      "checkout": "https://www.ulule.com/projects/19895/checkout/",
      "detail": "https://www.ulule.com/2dark/",
      "edit": {
        "address": "https://www.ulule.com/projects/19895/edit/billing/",
        "main": "https://www.ulule.com/projects/19895/edit/",
        "media": "https://www.ulule.com/projects/19895/edit/layout/",
        "news": {
          "add": "https://www.ulule.com/projects/19895/edit/news/add",
          "index": "https://www.ulule.com/projects/2dark/news/"
        },
        "orders": "https://www.ulule.com/projects/19895/edit/orders/",
        "products": "https://www.ulule.com/projects/19895/edit/products/",
        "rib": "https://www.ulule.com/projects/19895/edit/billing/",
        "ticket": "https://www.ulule.com/discussions/view/130404"
      }
    }
  },
  "name": {
    "en": "2Dark",
    "fr": "2Dark"
  },
  "subtitle": {
    "en": "A Survival Horror video game from the creator of the genre!",
    "fr": "Un jeu vidéo de Survival Horror par le créateur du genre !"
  },
  "description": {
    "en": "An Ulule campaign full of suspense... Once the first goal was achieved, we had...",
    "fr": "Nous vous recontacterons très prochainement par e-mail. Mais, d’ores et déjà, n’oubliez pas de..."
  },
  "description_funding": {
    "en": "<p>There are two reasons behind this Ulule campaign: to find a source of funds in order to remain...",
    "fr": "<p>Nous avons eu deux motivations pour cette campagne Ulule : trouver une source de financement pour pouvoir rester..."
  },
  "description_yourself": {
    "en": "has been interested in gameplay mechanics ever since he was a kid. And it's still his favourite...",
    "fr": "s’est intéressé aux mécaniques de jeu depuis sa plus tendre enfance.  Et c’est toujours son mode de communication préféré..."
  },
  "owner": {
    ... // user resource
  }

Additional fields

Some fields are present only when the project status is not “online”:

{
  "fields_needed": {
    "owner.country",
    "account.is_completed",
     ...
  }
}

Deprecated

Deprecated fields are present in the main_image subresource for backward compatibility

{
  "main_image": {
     "230x126": "https://img.ulule.com/.../230x126/presales/5/9/8/19895/fin.jpg",
     "258x145": "https://img.ulule.com/.../258x145/presales/5/9/8/19895/fin.jpg",
     "640x360": "https://img.ulule.com/.../640x360/presales/5/9/8/19895/fin.jpg",
     "full": "https://drfhlmcehrc34.cloudfront.net/presales/5/9/8/19895/fin.jpg",
     ...
  }
}

Update project

Parameters like name, description, subtitle, description_funding, description_yourself are i18n attributes with languages as keys and translation strings as values.

The translations must exist for the main language of the project. For example, if the project main language is it then description.it cannot be deleted. Moreover, if the language is changed to de, then name.de, description.de, subtitle.de, description_funding.de, description_yourself.de must exist. This is also the case for the i18n attributes of the reward and variant project-related resources.

If the status is different from new, pending or pending-owner, the following fields may not be updated by the project owner: country, currency, lang, goal, date_end, main_tag_id and account_id. Similarly, project-related reward and variant resources can’t be created, updated, nor deleted.

The project slug must be unique across the platform: it can’t be updated to a slug that is already used in another project.

PATCH /projects/:id

Update attributes for a given project.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

PATCH /projects/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

PATCH parameters

country string Project owner country of residence – ISO 3166-1 code lang string Project owner language – de, en, es, fr, it, nl currency string Project currency –- can be any valid currency code of max 3 characters slug string Project slug – max 30 characters goal int Project goal – cannot be equal to 0 nb_products_min int Project minimal number of products – cannot be equal to 0 date_end string Project end date – ISO 8601 nb_days int Project funding duration in days. main_tag_id int Project main tag account_id int Account ID tags int array Project tags timezone string Project timezone – max 63 characters name object (i18n) Project name in different languages subtitle object (i18n) Project subtitle in different languages description object (i18n) Project description in different languages description_funding object (i18n) Funding description in different languages description_yourself object (i18n) Project owner description in different languages

Example

{
  "country": "FR",
  "currency": "EUR",
  "lang": "fr",
  "goal": 1500,
  "slug": "my-awesome-project",
  "date_end": "2017-04-11T16:20:00Z",
  "nb_days": 30,
  "main_tag_id": 2,
  "account_id": null,
  "tags": [ 10, 13, 16 ],
  "timezone": "Europe/Paris",
  "description": {
    "fr": "mon super projet",
    "en": "my awesome project"
  },
  "name": {
    "fr": "super projet",
    "en": "awesome project"
  },
  "subtitle": {
    "fr": "mon sous-titre",
    "en": "my subtitle"
  },
  "description_funding": {
    "en": "my description funding"
  },
  "description_yourself": {
    "en": "my description"
  }
}

Response

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

{
   "id": 15,
   "amount_raised": 0,
   "comments_count": 0,
   "committed": 0,
   "country": "FR",
   "currency": "EUR",
   "currency_display": "€",
   "date_end": "2017-05-27T22:24:32Z",
   "nb_days": null,
   "date_start": null,
   "finished": false,
   "goal": 9999,
   "goal_raised": false,
   "is_online": true,
   "is_cancelled": false,
   "lang": "de",
   "nb_products_sold": 0,
   "news_count": 0,
   "percent": 0,
   "slug": "my-awesome-project",
   "status": "new",
   "supporters_count": 0,
   "timezone": "America/New_York",
   "type": "project",
   "payment_methods": [
     "creditcard"
   ],
   "lowest_contribution_amount": 0,
   "background": null,
   "main_image": null,
   "video": null,
   "main_tag": {
    "id": 10,
    "position": 5,
    "slug": "games",
    "absolute_url": "https://www.ulule.com/discover/tags/games",
    "name": {
      "en": "Games",
      "fr": "Jeux"
    }
   },
   "rewards": null,
   "location": null,
   "absolute_url": "https://www.ulule.com/my-awesome-project/",
   "resource_uri": "https://api.ulule.com/v1/projects/15",
   "urls": {
     "web": {
       "checkout": "https://www.ulule.com/projects/15/checkout/",
       "detail": "https://www.ulule.com/my-awesome-project/",
       "edit": {
         "address": "https://www.ulule.com/projects/15/edit/billing/",
         "main": "https://www.ulule.com/projects/15/edit/",
         "media": "https://www.ulule.com/projects/15/edit/layout/",
         "news": {
           "add": "https://www.ulule.com/projects/15/edit/news/add",
           "index": "https://www.ulule.com/projects/my-awesome-project/news/"
         },
         "orders": "https://www.ulule.com/projects/15/edit/orders/",
         "products": "https://www.ulule.com/projects/15/edit/products/",
         "rib": "https://www.ulule.com/projects/15/edit/billing/",
         "ticket": "https://www.ulule.com/discussions/view/1"
         }
      }
  },
  "name": {
     "en": "yepyep",
     "fr": "awesome project"
  },
  "subtitle": {
    "en": "",
    "fr": ""
  },
  "description": {
    "en": "my awesome project",
    "fr": "mon super projet"
  },
  "description_funding": {
    "en": "",
    "fr": "Those are rewards"
  },
  "description_yourself": {
    "en": "",
    "fr": "Those are references"
  },
  "owner": {
    ... // user resource
  }
}

Additional fields

Some fields are present only when the project status is not “online”:

{
  "fields_needed": {
    "owner.country",
    "account.is_completed",
     ...
  }
}

Staff stuff

PATCH /projects/:id

Staff users may update any field of a project whatever the status is.

In addition, the following fields are only accessible to staff users.

PATCH parameters

comments_enabled string Project comments enabled – everyone, supporters or disabled type string Project type – project or presale visible bool Project visibility supporters_disabled bool Project supporters tab disabled

Submit project

The project will be submitted to the Ulule team for review.

The status must be new.

A project can’t be submitted if any of the following fields is null or empty:

  • slug
  • currency
  • date_end or nb_days
  • lang
  • country
  • rewards
  • nb_products_min (or goal depending on type)
  • name (in project default language)
  • subtitle (in project default language)
  • description (in project default language)
  • description_funding (in project default language)
  • description_yourself (in project default language)
  • owner.avatar (must not be the default avatar)
  • owner.email
  • owner.location

In addition, the account linked to the project must have the is_completed field set to true.

POST /projects/:id/submit

Submit the given project.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

POST /projects/123/submit HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

Response

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

Publish project

The project will go online and be publicly visible.

The status must be validated.

The timezone and date_end fields may be updated with this endpoint, but date_end can’t be updated to a date that is more than 5 days before or after the original date_end or current day plus nb_days: old date_end - 5 < new date_end < old date_end + 5 where old date_end is the previous date_end or current date + nb_days if date_end is null.

date_end is required for a project to go online.

POST /projects/:id/publish

Publish the given project.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

POST /projects/123/publish HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

PATCH parameters

date_end string Project end date (optional) timezone string Project timezone (optional)

Example

{
  "date_end": "2014-11-21T21:59:59Z",
  "timezone": "Europe/Paris"
}

Response

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

List user projects

If a user is connected, projects embed a notifications resource which describes the subscribed notifications for the user.

GET /users/:id/projects

Retrieve user projects (all, created, followed and supported).

You will see a projects section in the response.

Access rights

Permissions:

  • User
  • Partner

Authentication mode:

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

state Optional, the current filter for projects: created | followed | supported

GET /users/3048/projects?state=created HTTP/1.1

Response

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

{
  "projects": [
    {
      ... // project resource
      "notifications": {
        "news": true
      }
    },
    ...
  ]
}

List partner projects

GET /partners/:slug/projects

Retrieve all your projects linked to your partner website.

Access rights

Permissions:

  • Partner

Authentication mode:

Request

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

Path parameters

slug the partner key identifier

List project sponsorships

For partner permissions, you will only retrieve information for projects which are online via your partner website.

GET /projects/:id/sponsorships

Retrieve project sponsorships (without pagination).

coefficient refers to the multiply factor, for 1€ the sponsor adds 1*coefficient €. E.g. if coefficient equals 2, when a backer gives 1€, the sponsor gives 2€. amount value indicates the maximum amount a sponsor will add to a project. The sponsor can no longer contribute once this amount is reached.

Access rights

Permissions:

  • Project owner
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

{
   "sponsorships": [
      {
         "id": 1,
         "project_id": 2,
         "coefficient": 1,
         "amount": 5,
         "sponsor": {
            "id": 1,
            "name": "sponsorFoo",
            "type": "premium",
            "link": "https://fr.ulule.com/discover/",
            "position": 1,
            "image": {
               "230x126": "https://...sponsors/...aa8e8709b7d8a5.jpg",
               "258x145": "https://...sponsors/...aa8e8709b7d8a5.jpg",
               "640x360": "https://...sponsors/...aa8e8709b7d8a5.jpg",
               "full": "https://.../sponsors/...aa8e8709b7d8a5.jpg",
               "value": "sponsors/...aa8e8709b7d8a5.jpg"
            },
            "user": {
              ... // user resource
            }
         },
         "title": {
           "en": "a sponsor title",
           "fr": "un titre de sponsor",
           "it": "",
           "nl": "",
           "ca": "",
           "de": "",
           "es": ""
         },
         "description":
           "en": "a sponsor description",
           "fr": "une description de sponsor",
           "it": "",
           "nl": "",
           "ca": "",
           "de": "",
           "es": ""
         }
      }
   ]
}

Staff stuff

The following endpoints are only available to staff users.

Unpublish project

This endpoint switches the project status from online to validated.

This endpoint is typically used when the project owner mistakenly published the project too soon.

POST /projects/:id/unpublish

Unpublish the given project.

Access rights

Authentication mode:

Request

POST /projects/123/unpublish HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

Response

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

Reward

Get reward

GET /rewards/:id

Retrieve reward detail.

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

GET /rewards/325736 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the reward ID

Response

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

 {
   "id": 325736,
   "price": 20,
   "stock": null,
   "stock_available": null,
   "stock_taken": 924,
   "available": true,
   "address_required": true,
   "date_delivery": "2017-07-01T00:00:00Z",
   "description": {
     "fr": "PACK LIGHT NOVEL NOOB"
   },
   "resource_uri": "https://api.ulule.com/v1/rewards/325736",
   "shipping_nat": null,
   "shipping_int": null,
   "has_shippings": false,
   "shippings": null
 }

Create reward

POST /projects/:id/rewards

Create a reward for a given project.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

POST /projects/123/rewards HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

POST parameters

description object (i18n) Reward description in different languages (required) price int|float Reward price must be either an integer for a project or a float for a presale (required) stock int Reward stock (optional) shipping_nat float Reward shipping price for the project country (optional) shipping_int float Reward shipping price for the international (optional) date_delivery string Reward delivery date (required, format must be YYYY-MM-DD) address_required bool Reward delivery address is required (required)

Example

{
  "description": {
    "en": "this t-shirt is collector"
  },
  "price": 25,
  "stock": 100,
  "shipping_nat": 2.5,
  "shipping_int": 11.5,
  "date_delivery": "2017-09-01",
  "address_required": true
}

Response

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

{
  "id": 189301,
  "description": {
    "en": "this t-shirt is collector"
  },
  "price": 25,
  "stock": null,
  "stock_available": null,
  "stock_taken": 0,
  "available": true,
  "shipping_nat": 2.5,
  "shipping_int": 11.5,
  "shippings": null,
  "has_shippings": false,
  "date_delivery": "2017-09-01T00:00:00Z",
  "created_at": "2022-05-27T22:24:32Z",
  "updated_at": "2022-05-27T22:24:32Z"
}

Update reward

PATCH /rewards/:id

Update a reward for a given project.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

PATCH /rewards/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

PATCH parameters

description object (i18n) Reward description in different languages (optional) price int|float Reward price must be either an integer for a project or a float for a presale (optional) stock int Reward stock (optional) shipping_nat int Reward shipping price for the project country (optional) shipping_int int Reward shipping price for the international (optional) date_delivery string Reward delivery date (optional, format must be YYYY-MM-DD) address_required bool Reward delivery address is required (optional)

Example

{
  "description": {
    "fr": "ce t-shirt est collector"
  },
  "price": 25,
  "stock": 100,
  "shipping_nat": 2.5,
  "shipping_int": 11.5,
  "date_delivery": "2017-09-01",
  "address_required": true
}

Response

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

{
  "id": 189301,
  "description": {
    "en": "this t-shirt is collector", // translation for project lang
    "fr": "ce t-shirt est collector"   // updated translation
  },
  "price": 25,
  "stock": null,
  "stock_available": null,
  "stock_taken": 0,
  "available": true,
  "shipping_nat": null,
  "shipping_int": null,
  "shippings": null,
  "has_shippings": false,
  "date_delivery": "2017-09-01T00:00:00Z",
  "created_at": "2022-05-27T22:24:32Z",
  "updated_at": "2023-05-27T22:24:32Z"
}

Delete reward

DELETE /rewards/:id

Delete a reward.

Access rights

Permissions:

  • Project owner

Authentication mode:

Path parameters

id required, the reward ID

Response

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

List project rewards

GET /projects/:id/rewards

Retrieve project rewards.

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

{
  "rewards": [
    {
      "id": 315834,
      "price": 10,
      "stock": null,
      "stock_available": null,
      "stock_taken": 24,
      "available": true,
      "address_required": false,
      "date_delivery": "2017-09-01T00:00:00Z",
      "description": {
        "en": "<p>Thank you!</p>",
        "fr": "<p>Merci !</p>"
      },
      "shipping_nat": null,
      "shipping_int": null,
      "has_shippings": false,
      "shippings": null
    },
    ... // more reward resources
  ]
}

Variant

Create variant

POST /rewards/:id/variants

Create a reward variant.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

POST /rewards/123/variants HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

POST parameters

description object (i18n) Description in different languages (required) stock int Stock (optional) date_delivery string Delivery date (optional, format must be YYYY-MM-DD, default is the same as the reward)

Example

{
  "description": {
    "en": "this red t-shirt is collector"
  },
  "stock": 100,
  "date_delivery": "2017-09-01"
}

Response

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

{
  "id": 189301,
  "description": {
    "en": "this red t-shirt is collector"
  },
  "price": 25,
  "stock": null,
  "stock_available": null,
  "stock_taken": 0,
  "available": true,
  "shipping_nat": 2.5,
  "shipping_int": 11.5,
  "shippings": null,
  "has_shippings": false,
  "date_delivery": "2017-09-01T00:00:00Z",
  "created_at": "2022-05-27T22:24:32Z",
  "updated_at": "2022-05-27T22:24:32Z"
}

Update variant

PATCH /variants/:id

Update a reward variant.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

PATCH /variants/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

PATCH parameters

description object (i18n) Description in different languages (optional) stock int Stock (optional) date_delivery string Delivery date (optional, format must be YYYY-MM-DD)

Example

{
  "description": {
    "fr": "ce t-shirt rouge est collector"
  },
  "stock": 100,
  "date_delivery": "2017-09-01"
}

Response

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

{
  "id": 189301,
  "description": {
    "en": "this red t-shirt is collector",     // translation for project lang
    "fr": "ce t-shirt rouge est collector" // updated translation
  },
  "price": 25,
  "stock": null,
  "stock_available": null,
  "stock_taken": 0,
  "available": true,
  "shipping_nat": null,
  "shipping_int": null,
  "shippings": null,
  "has_shippings": false,
  "date_delivery": "2017-09-01T00:00:00Z",
  "created_at": "2022-05-27T22:24:32Z",
  "updated_at": "2023-05-27T22:24:32Z"
}

Delete variant

DELETE /variants/:id

Delete a variant.

Access rights

Permissions:

  • Project owner

Authentication mode:

Path parameters

id required, the variant ID

Response

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

List variants

GET /rewards/:id/variants

Retrieve reward variants (without pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

GET /rewards/2/variants HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the reward ID

Response

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

{
  "variants": [
    {
      "id": 189301,
      "description": {
        "en": "this t-shirt is collector"
      },
      "price": 25,
      "stock": null,
      "stock_available": null,
      "stock_taken": 0,
      "available": true,
      "date_delivery": "2017-07-01T00:00:00Z",
      "created_at": "2022-05-27T22:24:32Z",
      "updated_at": "2023-05-27T22:24:32Z"
    },
    {
     "id": 189301,
      "description": {
        "en": "this t-shirt is collector"
      },
      "price": 25,
      "stock": null,
      "stock_available": null,
      "stock_taken": 0,
      "available": true,
      "date_delivery": "2017-07-01T00:00:00Z",
      "created_at": "2022-05-27T22:24:32Z",
      "updated_at": "2023-05-27T22:24:32Z"
    }, ...
  ]
}

Shipping

Create shipping

POST /rewards/:id/shippings

Create a reward shipping.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

POST /rewards/123/shippings HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the reward ID

POST parameters

amount float Shipping amount (required) countries []string Shipping countries – ISO 3166-1 codes (required)

Example

{
  "amount": 11.1,
  "countries": ["FR", "US"]
}

Response

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

{
  "id": 189301,
  "amount": 11.1,
  "countries": ["FR", "US"]
}

Update shipping

PATCH /shippings/:id

Update a reward shipping.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

PATCH /shippings/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the shipping ID

PATCH parameters

amount float Shipping amount countries []string Shipping countries – ISO 3166-1 codes

Example

{
  "amount": 40.5,
  "countries": ["NZ"]
}

Response

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

{
  "id": 123,
  "amount": 40.5,
  "countries": ["NZ"]
}

Delete shipping

DELETE /shippings/:id

Delete a shipping.

Access rights

Permissions:

  • Project owner

Authentication mode:

Path parameters

id required, the shipping ID

Response

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

List shippings

GET /rewards/:id/shippings

Retrieve reward shippings (without pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

GET /rewards/2/shippings HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the reward ID

Response

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

{
  "shippings": [
    {
      "id": 189301,
      "amount": 10,
      "countries": ["FR", "US"]
    },
    {
      "id": 189301,
      "amount": 30.5,
      "countries": ["NZ"]
    }, ...
  ]
}

Order

The order status field can have the following values.

Status Description
processing Order is processing
awaiting-confirmation User is filling payment info
payment-completed Order is complete
cancelled User has cancelled order during campaign
payment-done Campaign has succeeded, funds have been transfered to project owner
payment-invalid PSP needs more info to transfer payment to project owner
payment-reimbursed Campaign has failed, user has been reimbursed
error  

Get order

GET /orders/:id

Retrieve order detail.

Access rights

Permissions:

  • Order owner
  • Project owner
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the order identifier

Response

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

{
   "id": 246636,
   "order_subtotal": "50.00",
   "order_total": "50.00",
   "order_shipping_total": 0,
   "payment_method": "creditcard",
   "status": "awaiting-confirmation",
   "absolute_url": "https://www.ulule.com/9892/edit/order/246636/detail/",
   "resource_uri": "https://api.ulule.com/v1/orders/246636",
   "billing_address": null,
   "shipping_address": null,
   "note": null,
   "items": [
         {
            "line_total": 50,
            "line_subtotal": 50,
            "line_shipping_total": 0,
            "quantity": 1,
            "unit_price": 50,
            "reward_id": 1234,
            "reward": {
              ... // reward resource
            }
         }
   ],
   "created_at": "2013-07-12T21:58:44.603949Z",
   "user": {
        ... // user resource
   },
   "project_id": 9892,
   "payment_url": "https://www.ulule.com/projects/9892/checkout/pay/236636"
}

Create order

With this endpoint you will be able to create an order with a specific user, the response will return you the payment_url and you will have to redirect your user to this url.

Project types

Order creation payload depends on the project type:

  • Presale: orders are quantity-based (type 1)
  • Project: orders are amount-based (type 2)

The difference is very important and affects your request.

For a quantity-based project (type 1), or “presale”, an order must provide an array of rewards (in contrast to amount-based project that can only contain a single one).

The provided array must contain, at least, one reward. For each reward, we need to provide the given reward ID and the desired quantity. For example, we have a “sticker” reward with ID 54 and we want two stickers. So: {"reward_id": 54, "quantity": 2}.

For an amount-based project (type 2), an order can provide either only one existing project’s reward with the related amount (or more, it’s up to your user) or we can skip the reward and only give the amount we wish.

For example, we can either choose the “Super” €100 reward (and even decide to give even more money) or we can just give €200 without selecting any reward.

One important point, when you won’t select any rewards, there is a minimum amount for project (type 2) that you can find in project detail attribute lowest_contribution_amount.

Rewards

Project rewards can be retrieved via the endpoint: project detail

This endpoint returns project detail information with related rewards and their respective IDs in the rewards array attribute.

Response example:

{
    // Other project detail attributes...
    "rewards": [
      {
        ... // reward resource
      },
      ...
    ]
}

Presale

POST /projects/:id/orders

Create an order for a given presale.

Requirements

  • User must have is_completed attribute set to true

Access rights

Permissions:

  • Authenticated user

Authentication mode:

Request

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

Path parameters

id required, the project ID

POST parameters

Order attributes

rewards []object Selected rewards – object with id and quantity (required) payment_method string Payment method – creditcard, maestro or directdebit (required) return_url string Return URL – user will be redirected to this URL after payment (required) country string Country – ISO 3166-1 code (required if the order contains shippings) shipping_address_id string The shipping address ID (optional) billing_address_id string The billing address ID (optional)

Reward attributes

reward_id int Reward ID – must be a project’s reward (required) quantity int Reward quantity – must be less or equal to reward’s stock_available attribute value (required)

In case the shipping_address_id is not present, a blank address will be created. The order must then be updated with a correct shipping address, as explained in the shipping workflow section.

Example

{
  "return_url": "https://example.com",
  "payment_method": "creditcard",
  "country": "FR",
  "rewards": [
    {"reward_id": 189301, "quantity": 1}
  ]
}

Response

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

{
   "id": 246636,
   "order_subtotal": "50.00",
   "order_total": "50.00",
   "order_shipping_total": 0,
   "payment_method": "creditcard",
   "status": "awaiting-confirmation",
   "absolute_url": "https://www.ulule.com/9892/edit/order/246636/detail/",
   "resource_uri": "https://api.ulule.com/v1/orders/246636",
   "billing_address": null,
   "shipping_address": null,
   "items": [
         {
            "line_total": 50,
            "line_subtotal": 50,
            "line_shipping_total": 0,
            "quantity": 1,
            "unit_price": 50,
            "reward_id": 1234,
            "reward": {
              ... // reward resource
            }
         }
   ],
   "created_at": "2013-07-12T21:58:44.603949Z",
   "user": {
     ... // user resource
   },
   "project_id": 9892,
   "payment_url": "https://www.ulule.com/projects/9892/checkout/pay/236636"
}

Project

POST /projects/:id/orders

Create an order for a given project.

Requirements

  • User must have is_completed attribute set to true

Access rights

Permissions:

  • Authenticated user

Authentication mode:

Request

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

Path parameters

id required, the project ID

POST parameters

reward_id int Reward ID – must be a project’s reward (optional) amount int Contribution amount – if ``reward_id`` is provided, amount must be higher or equal to the selected reward (optional) payment_method string Payment method – creditcard, maestro or directdebit (required) return_url string Return URL – user will be redirected to this URL after payment (required) country string Country – ISO 3166-1 code (required if the order contains shippings) shipping_address_id string The shipping address ID (optional) billing_address_id string The billing address ID (optional)

Why reward ID can be optional?

A user can contribute without choosing any reward. He is also free to give any amount but this amount must be higher or equal to the project attribute lowest_contribution_amount value.

If you send a reward_id, the amount value must be higher or equal to the selected reward.

For example, if project’s rewards are:

{
    // other project detail attributes
    "lowest_contribution_amount": 5,
    "rewards": [
        {
           ... // reward resource
        },
        ...
    ]
}

The project example has the lowest_contribution_amount attribute equal to 5 euro. The amount must be higher or equal to 5 euro if any reward isn’t selected. If the selected item is the “Reward #2”, 50 euro or more must be given.

Example

I can give 12 euro and select a reward of 10 euro.

{
   "return_url": "https://example.com",
   "payment_method": "creditcard",
   "country": "FR",
   "reward_id": 1234,
   "amount": 12
}

Response

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

{
   "id": 246636,
   "order_subtotal": "12.00",
   "order_total": "12.00",
   "order_shipping_total": 0,
   "payment_method": "creditcard",
   "status": "awaiting-confirmation",
   "absolute_url": "https://www.ulule.com/9892/edit/order/246636/detail/",
   "resource_uri": "https://api.ulule.com/v1/orders/246636",
   "billing_address": null,
   "shipping_address": null,
   "note": null,
   "items": [
         {
            "line_total": 50,
            "line_subtotal": 50,
            "line_shipping_total": 0,
            "quantity": 1,
            "unit_price": 50,
            "reward_id": 1234,
            "reward": {
              ... // reward resource
            }
         }
   ],
   "created_at": "2013-07-12T21:58:44.603949Z",
   "user": {
        ... // user resource
   },
   "project_id": 9892,
   "payment_url": "https://www.ulule.com/projects/9892/checkout/pay/236636"
}

Update order

PATCH /orders/:id

Update address of a given order.

Access rights

Permissions:

  • Order owner
  • Project owner
  • Partner

Authentication mode:

Request

PATCH /orders/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript
  • Provided addresses should belong to the order user
  • You will not be able to update the shipping address if an order already contains a shipping address and a reward has shippings

Path parameters

id required, the order ID

PATCH parameters

shipping_address_id string The shipping address ID (optional) billing_address_id string The billing address ID (optional) note string A note about this order

Example

{
   "shipping_address_id": 555200,
   "note": "Should be shipped with precaution"
}

Response

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

{
   "id": 267272,
   "order_subtotal": "20.00",
   "order_total": "20.00",
   "order_shipping_total": 0,
   "payment_method": "creditcard",
   "status": "payment-completed",
   "absolute_url": "https://www.ulule.com/11805/edit/order/267272/detail/",
   "resource_uri": "https://api.ulule.com/v1/orders/267272",
   "note": "Should be shipped with precaution",
   "billing_address": null,
   "shipping_address": {
         "id": 555200,
         "first_name": "Florent",
         "last_name": "Foo",
         "entity_name": "",
         "address1": "8 Rue Saint-Fiacre",
         "address2": "",
         "postal_code": "75002",
         "city": "Paris",
         "state": "",
         "country": "FR",
         "user_id": 258344
   },
   "items": [
         {
            "line_total": 50,
            "line_subtotal": 50,
            "line_shipping_total": 0,
            "quantity": 1,
            "unit_price": 50,
            "reward_id": 1234,
            "reward": {
              ... // reward resource
            }
         }
   ],
   "created_at": "2013-09-04T19:44:10.852035Z",
   "user": {
        ... // user resource
   },
   "project_id": 11805
}

Cancel order

POST /orders/:id/cancel

Cancel a given order.

As order cancelling is processed asynchronously, once cancelling is effective, refunded attribute will be set to true.

Access rights

Permissions:

  • Order owner
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the order identifier

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,
  "note": 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": "cancelled"
}

List user orders

GET /users/:id/orders

Retrieve valid orders from a specific user (organized in a pagination).

Access rights

Permissions:

  • User
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the user ID

Query parameters

status Optional, a filter by order status: selecting-payment | awaiting-confirmation | payment-completed, shipped | cancelled | aborted | payment-done | payment-invalid | payment-reimbursed | payment-refunded | error

GET /users/3048/orders?filter=selecting-payment HTTP/1.1

List project orders

For partner permissions, you will only retrieve information for projects which are online via your partner website.

GET /projects/:id/orders

Retrieve valid orders from a specific project.

Access rights

Permissions:

  • Project owner
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the project ID

Query parameters

status Optional, a filter by order status: selecting-payment | awaiting-confirmation | payment-completed, shipped | cancelled | aborted | payment-done | payment-invalid | payment-reimbursed | payment-refunded | error reward_id Optional payment_method Optional, a filter by order payment method: creditcard | check | paypal | directdebit | maestro | ideal

News

A project owner can add news to keep the supporters informed about the project during and after the crowdfunding campaign.

The news status field can have the following values:

status
online
waiting

Get news

GET /news/:id

Retrieve news detail.

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the news ID

Response

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

{
  "id": 123456,
  "comments_count": 0,
  "date_publication": "2017-06-01T15:15:23.17483Z",
  "absolute_url": "https://www.ulule.com/this-is-the-project-name/news/english-title/",
  "resource_uri": "https://api.ulule.com/v1/news/123456",
  "reserved": false,
  "status": "online",
  "title": {
    "en": "English title"
  },
  "content": {
    "en": "<p>English content</p>"
  },
  "author": {
    ...
  },
  "project": {
    ...
  }
}

Create project news

The project status field must be online for a news to be created.

POST /projects/:id/news

Create news for a given project.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

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

Path parameters

id required, the project ID

POST parameters

title object (i18n) News title in different languages - max 255 characters (required) content object (i18n) News content in different languages (required) reserved bool If true, only supporters will be able to see the news, otherwise it is public (optional, default is false)

Example

{
  "content": {
    "en": "<p>English content</p>",
    "fr": "<p>Contenu français</p>"
  },
  "title": {
    "en": "English title",
    "fr": "Titre français"
  },
  "reserved": true
}

Response

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

{
  "id": 123456,
  "comments_count": 0,
  "date_publication": null,
  "absolute_url": "https://www.ulule.com/news/english-title/",
  "resource_uri": "https://api.ulule.com/v1/news/123456",
  "reserved": true,
  "status": "waiting",
  "title": {
    "en": "English title",
    "fr": "Titre français"
  },
  "content": {
    "en": "<p>English content</p>",
    "fr": "<p>Contenu français</p>"
  }
}

Update news

PATCH /news/:id

Update news.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

PATCH /news/123456 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the news ID

PATCH parameters

title object (i18n) News title in different languages content object (i18n) News content in different languages reserved bool If true, only supporters will be able to see the news, otherwise it is public

Example

{
  "content": {
    "en": "<p>Updated English content</p>"
  }
}

Response

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

{
  "id": 123456,
  "comments_count": 0,
  "date_publication": null,
  "absolute_url": "https://www.ulule.com/news/english-title/",
  "resource_uri": "https://api.ulule.com/v1/news/123456",
  "reserved": true,
  "status": "waiting",
  "title": {
    "en": "English title",
    "fr": "Titre français"
  },
  "content": {
    "en": "<p>Updated English content</p>",
    "fr": "<p>Contenu français</p>"
  }
}

Delete news

The news status field must be waiting for a news to be deleted.

DELETE /news/:id

Delete news.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

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

Path parameters

id required, the news ID

Response

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

Test news

POST /news/:id/try

Send a test email to project owner with news content.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

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

Path parameters

id required, the news ID

Publish news

The news status field must be waiting for a news to be published.

POST /news/:id/publish

Publish news.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

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

Path parameters

id required, the news ID

Unpublish news

The news status field must be online for a news to be unpublished.

POST /news/:id/unpublish

Unpublish news.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

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

Path parameters

id required, the news ID

List project news

GET /projects/:id/news

Retrieve project news (organized in a pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

{
  "news": [
    {
      "id": 123456,
      "comments_count": 0,
      "date_publication": "2017-06-01T15:15:23.17483Z",
      "absolute_url": "https://www.ulule.com/this-is-the-project-name/news/english-title/",
      "resource_uri": "https://api.ulule.com/v1/news/123456",
      "reserved": false,
      "status": "online",
      "title": {
        "en": "English title"
      },
      "content": {
        "en": "<p>English content</p>"
      }
    }
  ],
  "meta": {
    "limit": 20,
    "next": null,
    "offset": 0,
    "total_count": 1,
    "previous": null
  }
}

Comment

Create news comment

POST /news/:id/comments

Create a new comment on the news.

Access rights

Permissions:

  • Authenticated user

Authentication mode:

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 string Comment text (required)

Example

{
  "comment": "a comment message"
}

Response

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

{
  "id": 12,
  "comment": "Very nice news",
  "submit_date": "2017-09-26T09:31:45.154578602Z",
  "user": {
    ... // user resource
  }
}

Create project comment

Permission to comment for the authenticated user depends on the project comments_enabled status.

POST /projects/:id/comments

Create a comment on the project.

Access rights

Permissions:

  • Authenticated user

Authentication mode:

Request

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

Path parameters

id required, the project ID

POST parameters

comment string Comment text (required)

Example

{
  "comment": "a comment message"
}

Response

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

{
  "id": 12,
  "comment": "Very nice project",
  "submit_date": "2017-09-26T09:31:45.154578602Z",
  "user": {
    ... // user resource
  }
}

List project comments

GET /projects/:id/comments

Retrieve project comments (organized in a pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

{
  "comments": [
    {
      "id": 12,
      "comment": "Very nice project",
      "submit_date": "2017-09-26T09:31:45.154578602Z",
      "user": {
        ... // user resource
      }
    }
  ],
  "meta": {
    "limit": 20,
    "next": null,
    "offset": 0,
    "total_count": 1,
    "previous": null
  }
}

List news comments

GET /news/:id/comments

Retrieve news comments (with pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the news ID

Response

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

{
  "comments": [
    {
      "id": 12,
      "comment": "Very nice news",
      "submit_date": "2017-09-26T09:31:45.154578602Z",
      "user": {
        ... // user resource
      }
    }
  ],
  "meta": {
    "limit": 20,
    "next": null,
    "offset": 0,
    "total_count": 1,
    "previous": null
  }
}

Export

Project owners can export data from their projects to files, typically for bookkeeping.

The following types of export are available:

type
orders

The following file formats are available:

format
csv
xls

The typical workflow is the following:

  1. The project owner creates an export.
  2. The export is created asynchronously. Its status goes from waiting to processing to succeeded, it can also be failed or cancelled by the staff.
  3. The project owner receives an email with the export file attached.

Get export

GET /exports/:id

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

GET /exports/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the export ID

Response

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

{
   "id": 123,
   "type": "orders"
   "url": "https://.../orders.xls",
   "format": "xls",
   "status": "succeeded",
   "project_id": 80,
   "created_at": "2017-08-24T12:29:48.8734218Z",
   "user": {
     ... // user resource
   }
}

Create export

POST /projects/:id/exports

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

POST /projects/123/exports HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

POST parameters

type string Export type (required, must be “orders”). format string Export format (required, “csv” or “xls”).

Example

{
  "type": "orders",
  "format": "xls"
}

Response

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

{
   "id": 15,
   "type": "orders"
   "url": "",
   "format": "xls"
   "status": "waiting",
   "project_id": 80,
   "created_at": "2017-08-24T12:29:48.8734218Z",
   "user": {
     ... // user resource
   }
}

List project exports

GET /projects/:id/exports

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

[
  {
     "id": 15,
     "type": "orders"
     "url": "https://.../orders.xls",
     "format": "xls"
     "status": "succeeded",
     "project_id": 80,
     "created_at": "2017-08-24T12:29:48.8734218Z",
     "user": {
       ... // user resource
     }
  },
  ...
]

Partnership

Get partnership

GET /partnerships/:id

Retrieve partnership detail.

Access rights

Permissions:

  • Partner

Authentication mode:

Request

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

Path parameters

id required, the partnerships ID

Response

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

{
  "id": 1,
  "status": "new",
  "is_default": true,
  "is_support": false,
  "partner": {
    "id": 1,
    "name": "Ulule",
    "slug": "ulule",
    "url": "https://www.ulule.com"
  },
  "presale": {
    ... // project resource
  }
}

Create partnership

POST /projects/:id/partnerships

Create partnership for a given project.

Access rights

Permissions:

  • Partner

Authentication mode:

Request

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

Path parameters

id required, the project ID

POST parameters

partner_id int Partner ID (required) is_default bool Set partnership as default – only one partnership can be set as default (optional) is_support bool Set partnership as support (optional)

Example

{
  "partner_id": 1,
  "is_default": false,
  "is_support": false
}

Response

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

{
  "id": 1,
  "status": "new",
  "is_default": false,
  "is_support": false,
  "partner": {
    "id": 1,
    "name": "Ulule",
    "slug": "ulule",
    "url": "https://www.ulule.com"
  },
  "presale": {
    ... // project resource
  }
}

Update partnership

PATCH /partnerships/:id

Update a given partnership.

Access rights

Permissions:

  • Partner

Authentication mode:

Request

PATCH /partnerships/1 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the partnership ID

PATCH parameters

partner_id int Partner ID (required) status string Partnership status (required) is_default bool Set partnership as default – only one partnership can be set as default (optional) is_support bool Set partnership as support (optional)

Example

{
  "partner_id": 1,
  "status": "new",
  "is_default": false,
  "is_support": false
}

Response

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

{
  "id": 1,
  "status": "new",
  "is_default": false,
  "is_support": false,
  "partner": {
    "id": 1,
    "name": "Ulule",
    "slug": "ulule",
    "url": "https://www.ulule.com"
  },
  "presale": {
    ... // project resource
  }
}

Delete partnership

DELETE /partnerships/:id

Delete a given partnership.

Access rights

Permissions:

  • Partner

Authentication mode:

Request

DELETE /partnerships/1 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the partnership ID

Response

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

List partnerships

For partner permissions, you will only retrieve information for projects which are online via your partner website.

GET /projects/:id/partnerships

Retrieve project partnerships (without pagination).

Access rights

Permissions:

  • Project owner
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the project ID

Category and tag

There are two kind of tags, with the same REST resource. Tag resource can have a parent_id. Category is a main tag, without parent_id. Tag is a sub tag for one Category, parent_id = id of one Category.

List tags

GET /tags

Retrieve list of all tags (categories and tags) Category is a parent of one tag

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Response

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

{
  "tags": [
    {
      "id": 1,
      "name": {
        "fr": "jeux",
        "en": "game",
        "de": "",
        "it": "",
        "ca": "",
        "nl": "",
        "es": ""
      },
      "position": 0,
      "slug": "jeux",
      "absolute_url": "https://www.ulule.com/discover/tags/jeux"
    },
    {
      "id": 2,
      "name": {
        "fr": "jeux de société",
        "en": "board game",
        "de": "",
        "it": "",
        "ca": "",
        "nl": "",
        "es": ""
      },
      "position": 0,
      "slug": "jeux-societe",
      "absolute_url": "https://www.ulule.com/discover/tags/jeux-societe"
      "category": {
        "id": 1,
        "name": {
          "fr": "jeux",
          "en": "game",
          "de": "",
          "it": "",
          "ca": "",
          "nl": "",
          "es": ""
        },
        "position": 0,
        "slug": "jeux",
        "absolute_url": "https://www.ulule.com/discover/tags/jeux"
      },
    }
  ]
}

List categories

GET /categories

Retrieve list of categories

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Response

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


{
  "categories": [
    {
      "id": 1,
      "name": {
        "fr": "jeux",
        "en": "game",
        "de": "",
        "it": "",
        "ca": "",
        "nl": "",
        "es": ""
      },
      "position": 0,
      "slug": "jeux",
      "absolute_url": "https://www.ulule.com/discover/tags/jeux"
    }, ...
  ]
}

List category tags

GET /categories/:id/tags

Retrieve tags from a specific category.

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

GET /category/5/tags HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the category ID

Response

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


{
  "tags": [
    {
      "id": 2,
      "name": {
        "fr": "jeux de société",
        "en": "board game",
        "de": "",
        "it": "",
        "ca": "",
        "nl": "",
        "es": ""
      },
      "position": 0,
      "slug": "jeux-societe",
      "absolute_url": "https://www.ulule.com/discover/tags/jeux-societe"
    }, ...
  ]
}

List project tags

GET /projects/:id/tags

Retrieve project tags (without pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

{
  "tags": [
    {
      "id": 2,
      "position": 0,
      "slug": "jeux-societe",
      "absolute_url": "https://www.ulule.com/discover/tags/jeux-societe",
      "name": {
        "fr": "jeux de société",
        "en": "board game",
        "de": "",
        "it": "",
        "ca": "",
        "nl": "",
        "es": ""
      }
    },
    {
      "id": 3,
      "position": 0,
      "slug": "sci-fi",
      "absolute_url": "https://www.ulule.com/discover/tags/sci-fi",
      "name": {
        "fr": "livres SF",
        "en": "sci-fi books",
        "de": "",
        "it": "",
        "ca": "",
        "nl": "",
        "es": ""
      }
    }
  ]
}

Proposal

A proposal can be affected to an existing user or not. It depends on which endpoint is used:

The manager field is shown only to staff member, else it is null.

Below, the proposal statuses:

Status Value
new 1
valid 2
invalid 3
pending 4
updated 5
waiting 6

Create an initial proposal (pending or new), a pending proposal is not complete it’s like a pre-proposal.

It will need an update with to complete proposal information.

After the creation, there are 3 ways:

  • valid proposal has been accepted by the success manager, a presale/project is created
  • invalid proposal has been refused by the success manager
  • waiting proposal is considered as incomplete and the success manager asks the proposal owner more information
  • updated proposal has been updated by the user

The proposal references are not in the proposal resource and a dedicated endpoint is used to retrieve the list.

Get proposal

GET /proposals/:id

Retrieve proposal detail.

Access rights

Permissions:

  • Proposal owner
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the proposal ID / token

Response

If authenticated user is staff, manager resource is returned with proposal resource. Otherwise, manager resource is set to null. (see update proposal endpoint for an example of proposal resource with manager)

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

  {
    "id": 1,
    "address": "424, my address",
    "country": "FR",
    "currency": "EUR",
    "date_creation": "2017-02-14T10:14:47.343564Z",
    "date_update": "2017-03-06T00:00:00Z",
    "description": "This is a short description upd",
    "first_name": "John up",
    "last_name": "Doe up",
    "lang": "fr",
    "goal": 1500,
    "name": "Project live test update",
    "nb_products_min": 0,
    "phone_number": "123456999",
    "references": "Those are references update",
    "rewards": "Those are rewards update",
    "status": 6,
    "status_display": "Waiting",
    "structure": "Something cool update",
    "type": 2,
    "type_display": "Project",
    "email": "foo@ulule.com",
    "resource_uri": "https://api.ulule.com/v1/proposals/1",
    "user": {
       ... // user resource
    },
    "project": null,
    "partner": {
      "id": 3,
      "name": "Gamesplanet",
      "slug": "gamesplanet",
      "url": "http://gamesplanet.com/"
    },
    "manager": null
  }

Create proposal

Create user proposal

A proposal can be affected to an existing user. Fields and partner are not null.

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.

See the complet workflow.

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

Type Code
Presale 1
Project 2
POST /users/:id/proposals

Create an authenticated proposal. Default status is: “New”.

Access rights

Permissions:

  • User
  • Partner

Authentication mode:

Request

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

Path parameters

id the user ID

POST parameters

first_name string First name – max 30 characters (optional) last_name string Last name – max 30 characters (optional) email string Owner email (required for anonymous proposal) name string Project name – max 255 characters (required) type int Type – “1” for a presale, “2” for project (required) nb_products_min int Number of products to sell for a presale (type 1) (optional) goal int Amount you have to raised for a project (type 2) (optional) lang string Language used – de, en, es, fr, it, nl (optional) decription string Description (optional) rewards string Rewards (optional) currency string Currency used – can be any valid currency code of max 3 characters (optional) phone_number string Phone number – max 15 characters (optional) nationality string Project owner nationality – ISO 3166-1 code (optional) country string Project owner country – ISO 3166-1 code (required) address string Address (optional) structure string Structure – max 150 characters (optional) birthday string Project owner birthday – format: YYYY-MM-DD (optional) links []string References - Facebook page, YouTube channel, Twitter, website, etc… (optional) category_id int Category ID (optional)

Example

{
  "address":      "123, my address",
  "country":      "FR",
  "currency":     "EUR",
  "description":  "This is a short description",
  "first_name":   "John",
  "last_name":    "Doe",
  "lang":         "fr",
  "goal":         1500,
  "name":         "Project live test",
  "phone_number": "123456999",
  "rewards":      "Those are rewards",
  "type":         2,
  "category_id":  2,
  "structure":    "Something cool",
  "nationality":  "FR",
  "birthday":     "1987-09-17",
  "email":        "doe@ulule.com",
  "links": [
    "https://twitter.com/proposal-project",
    "https://www.facebook.com/proposal-project",
    "https://www.my-site.com/proposal-project"
  ]
}

Response

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

  {
    "id": 21,
    "address":
    "123, my address",
    "country": "FR",
    "currency": "EUR",
    "date_creation": "2017-03-21T09:54:52.890936719Z",
    "date_update": "2017-03-21T09:54:52.890644102Z",
    "description": "This is a short description",
    "first_name": "John",
    "last_name": "Doe",
    "lang": "fr",
    "goal": 1000,
    "name": "Project live test",
    "nb_products_min": 0,
    "phone_number": "123456789",
    "rewards": "Those are rewards",
    "status": 4,
    "status_display": "Pending",
    "structure": "Something cool",
    "type": 2,
    "category_id": 2,
    "token": "4M10BuwWW816bsedkCKa",
    "type_display": "Project",
    "email": "doe@ulule.com",
    "resource_uri": "https://api.ulule.com/v1/proposals/21",
    "category": {
      ... // category resource
    },
    "user": {
      ... // user resource
     },
    "project": null,
    "partner": {
       "id": 2,
       "name": "Ulule",
       "slug": "ulule",
       "url": "http://www.ulule.com/"
    },
    "manager": null
 }

Create anonymous proposal

A proposal is anonymous if it isn’t attached to a user (created without authentication).

By default a proposal status after the creation is new but if the proposal is anonymous, the status is pending. See the complete workflow for more details.

In the HTTP response body there is a token. It should be saved in your system (send an email to the proposal owner, etc). It’s the only way to get the right to GET or PATCH an anonymous proposal (replace the id by token in the request url)

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
POST /proposals

Create an anonymous proposal. Default status is : “Pending”.

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

  • Anonymous

Request

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

POST parameters

first_name string First name – max 30 characters (required) last_name string Last name – max 30 characters (required) email string Owner email (required for anonymous proposal) name string Project name – max 255 characters (required) type int Type – “1” for a presale, “2” for project (required) nb_products_min int Number of products to sell for a presale (type 1) (optional) goal int Amount you have to raised for a project (type 2) (optional) lang string Language used – de, en, es, fr, it, nl (optional) decription string Description (optional) rewards string Rewards (optional) currency string Currency used – can be any valid currency code of max 3 characters (optional) phone_number string Phone number – max 15 characters (optional) nationality string Project owner nationality – ISO 3166-1 code (optional) country string Project owner country – ISO 3166-1 code (required) address string Address (optional) structure string Structure – max 150 characters (optional) birthday string Project owner birthday – format: YYYY-MM-DD (optional) links []string References - Facebook page, YouTube channel, Twitter, website, etc… (optional) category_id int Category ID (optional)

Example

{
  "address":      "123, my anonymous address",
  "country":      "FR",
  "currency":     "EUR",
  "description":  "This is a short anonymous description",
  "first_name":   "John",
  "last_name":    "anonymous",
  "lang":         "fr",
  "goal":         1500,
  "name":         "anonymous Project live test",
  "phone_number": "123456999",
  "rewards":      "Those are anonymous rewards",
  "type":         2,
  "structure":    "Something cool",
  "nationality":  "FR",
  "birthday":     "1987-09-17",
  "email":        "anonymous@ulule.com",
  "category_id":  3,
  "links": [
    "https://twitter.com/proposal-test-project-live",
    "https://www.facebook.com/proposal-test-project-live",
    "https://www.my-site.com/proposal-test-project-live"
  ]
}

Response

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

  {
    "id": 21,
    "address": "123, my anonymous address",
    "country": "FR",
    "currency": "EUR",
    "date_creation": "2017-03-21T09:54:52.890936719Z",
    "date_update": "2017-03-21T09:54:52.890644102Z",
    "description": "This is a short anonymous description",
    "first_name": "John",
    "last_name": "anonymous",
    "lang": "fr",
    "goal": 1000,
    "name": "anonymous Project live test",
    "nb_products_min": 0,
    "phone_number": "123456789",
    "rewards": "Those are anonymous rewards",
    "status": 4,
    "status_display": "Pending",
    "structure": "Something cool",
    "type": 2,
    "category_id": 3,
    "token": "4M10BuwWW816bsedkCKa",
    "type_display": "Project",
    "email": "anonymous@ulule.com",
    "resource_uri": "https://api.ulule.com/v1/proposals/21",
    "category": {
      ... // category resource
    },
    "user": null,
    "project": null,
    "partner": null,
    "manager": null
 }

Update proposal

If the patched proposal is anonymous, the token and an OAuth2 access is mandatory to get the right to update the proposal and attach the authenticated user.

For user access, the new status depends on the previous:

  • set to new for pending (anonymous) proposal
  • set to updated for waiting proposal.

See the complet workflow for more details.

PATCH /proposals/:id

Update attributes for a given proposal.

Access rights

Permissions:

  • Proposal owner

Some fields are restricted to the staff users: status, user_id, manager_id,

Authentication mode:

Request

PATCH /proposals/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the proposal ID / token

PATCH parameters

nationality string User nationality – ISO 3166-1 code country string User country of residence – ISO 3166-1 code birthday string User birth date – formatted as YYYY-MM-DD and year must be higher to 1901 first_name string User first name – max 30 characters last_name string User last name – max 30 characters email string Owner email lang string User language (de, en, es, fr, it, nl) decription string Description address string User address currency string Currency goal int Goal nb_products_min int Minimum number of products name string Name phone_number string Phone Number references string References links []string Links rewards string Rewards type int Type structure string Structure user_id int User ID manager_id int Manager ID partner string Partner slug status string Status category_id int Category ID

Example

{
  "address":      "666, my address",
  "country":      "FR",
  "currency":     "EUR",
  "description":  "This is a short description upd",
  "first_name":   "John up",
  "last_name":    "Doe up",
  "manager_id": 2,
  "lang":         "fr",
  "goal":         1500,
  "name":         "Project live test update",
  "phone_number": "123456999",
  "references":   "Those are references update",
  "rewards":      "Those are rewards update",
  "type":         2,
  "category_id":  2,
  "structure":    "Something cool update",
  "nationality":  "FR",
  "birthday":     "1987-09-17",
  "email":    "foo@ulule.com",
  "links": [
    "https://twitter.com/proposal-test-project-liveUp",
    "https://www.facebook.com/proposal-test-project-liveUp",
    "https://www.my-site.com/proposal-test-project-liveUp"
  ]
}

Response

If authenticated user is staff, manager resource is returned with proposal resource else manager resource is set to null.

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

  {
     "id": 1,
     "address": "666, my address",
     "country": "FR",
     "currency": "EUR",
     "date_creation": "2017-02-14T10:14:47.343564Z",
     "date_update": "2017-03-16T00:00:00Z",
     "description": "This is a short description upd",
     "first_name": "John up",
     "last_name": "Doe up",
     "lang": "fr",
     "goal": 1500,
     "name": "Project live test update",
     "nb_products_min": 0,
     "phone_number": "123456999",
     "references": "Those are references update",
     "rewards": "Those are rewards update",
     "status": 6,
     "status_display": "Waiting",
     "structure": "Something cool update",
     "type": 2,
     "category_id": 2,
     "token": "4M10BuwWW816bsedkCKa",
     "type_display": "Project",
     "email": "foo@ulule.com",
     "resource_uri": "https://api.ulule.com/v1/proposals/1",
     "category": {
        ... // category resource
     },
     "user": {
        ... // user resource
     },
     "project": null,
     "partner": {
         "id": 3,
         "name": "Gamesplanet",
         "slug": "gamesplanet",
         "url": "http://gamesplanet.com/"
     },
     "manager": {
        ... // user resource
     }}

List user proposals

GET /users/:id/proposals

User proposals (all, new, valid and invalid) organized in a pagination.

Access rights

Permissions:

  • User
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the user ID

Query parameters

status Optional, the current filter for proposals: new | valid | invalid.

GET /users/3048/proposals?status=new HTTP/1.1

List partner proposals

GET /partners/:slug/proposals

Retrieve your proposals which had been registered in your partner website (all, new, valid and invalid).

Access rights

Permissions:

  • Partner

Authentication mode:

Request

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

Path parameters

partner the partner key identifier

Query parameters

status Optional, the current filter for proposals: new | valid | invalid

GET /partners/ulule/proposals?status=valid HTTP/1.1

List references

Get references for a given proposal.

Access rights

Permissions:

  • Proposal owner
  • Partner

Authentication mode:

Request

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

Path parameters

id required, the proposal ID

Response

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

  {
    "links": [
      {
        "id": 63,
        "url": "https://www.my-site.com/proposal-test-project-liveUp"
      },
      {
        "id": 62,
        "url": "https://www.facebook.com/proposal-test-project-liveUp"
      },
      {
        "id": 61,
        "url": "https://twitter.com/proposal-test-project-liveUp"
      }
    ]
  }

Staff stuff

The following endpoints are only available to staff users.

Validate proposal

POST /proposals/:id/validate

Change proposal status to valid and create a new project linked to the proposal.

Access rights

Permissions:

  • Staff

Authentication mode:

Request

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

Path parameters

id required, the proposal ID

POST parameters

answer string Answer – text (optional)

Example

{
  "answer": "Greetings, we choose to validate your proposal"
}

Response

Response is the same as Update proposal endpoint with status updated.

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

  {
    ...,      // proposal resource
    "status": 2,
    "status_display": "valid",
    "answer": "Greetings, we choose to validate your proposal",
    "project" {
      ... // project resource
    }
    ...
  }

Refuse proposal

POST /proposals/:id/refuse

Change proposal status to invalid.

Access rights

Permissions:

  • Staff

Authentication mode:

Request

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

Path parameters

id required, the proposal ID

POST parameters

answer string Answer – text (optional)

Example

{
  "answer": "Your proposal was refused, because..."
}

Response

Response is the same as Update proposal endpoint with status updated.

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

  {
    ...,      // proposal resource
    "status": 3,
    "status_display": "invalid",
    "answer": "Your proposal was refused, because...",
    ...
  }

Suspend proposal

POST /proposals/:id/waiting

Change proposal status to waiting.

Access rights

Permissions:

  • Staff

Authentication mode:

Request

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

Path parameters

id required, the proposal ID

POST parameters

answer string Answer – text (optional)

Example

{
  "answer": "Please, could you specify more..."
}

Response

Response is the same as Update proposal endpoint with status updated.

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

  {
    ...,      // proposal resource
    "status": 6,
    "status_display": "invalid",
    "answer": "Please, could you specify more...",
    ...
  }

List proposals

GET /proposals

Retrieve proposal list with pagination.

Access rights

Permissions:

  • Staff

Authentication mode:

Request

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

Query parameters

status Optional, the current filter for proposals: new | valid | invalid partner_id Optional lang Optional, the current filter for proposals: de | en | es | fr | it | ls country Optional, ISO 3166-1 code

Response

manager is returned null to keep the response not too heavy.

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

[
  {
    "id": 1,
    "address": "424, my address",
    "country": "FR",
    "currency": "EUR",
    "date_creation": "2017-02-14T10:14:47.343564Z",
    "date_update": "2017-03-06T00:00:00Z",
    "description": "This is a short description upd",
    "first_name": "John up",
    "last_name": "Doe up",
    "lang": "fr",
    "goal": 1500,
    "name": "Project live test update",
    "nb_products_min": 0,
    "phone_number": "123456999",
    "references": "Those are references update",
    "rewards": "Those are rewards update",
    "status": 6,
    "status_display": "Waiting",
    "structure": "Something cool update",
    "type": 2,
    "category_id": 2,
    "token": "4M10BuwWW816bsedkCKa",
    "type_display": "Project",
    "email": "foo@ulule.com",
    "resource_uri": "https://api.ulule.com/v1/proposals/1",
    "category": {
      ... // category resource
    },
    "user": {
      ... // user resource
    },
    "project": null,
    "partner": {
      "id": 3,
      "name": "Gamesplanet",
      "slug": "gamesplanet",
      "url": "http://gamesplanet.com/"
    },
    "manager": {
      ... // manager resource
    }
  }, ...
]

Analytics tag

A project can have three different analytics tags.

  • Google Analytics tracking ID
  • Facebook pixel
  • Twitter website tag

There can’t be more than one tag of each type for a project.

Create project analytics tag

POST /projects/:id/analytics

Create an analytics tag for a given project.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

POST /projects/123/analytics HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

POST parameters

type string Type – “google”, “facebook” or “twitter” (required) tag string Tag (required)

Example

{
  "type": "google",
  "tag": "UA-12345-43"
}

Response

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

{
  "id": 1,
  "tag": "UA-12345-43",
  "type": "google"
}

Update analytics tag

PATCH /analytics/:id

Update attributes for a given analytics tag.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

PATCH /analytics/1 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the analytics tag ID

POST parameters

type string Type – “google”, “facebook” or “twitter” tag string Tag

Example

{
  "tag": "UA-12345-43",
  "type": "google"
}

Response

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

{
  "id": 1,
  "tag": "UA-12345-43",
  "type": "google"
}

Delete analytics tag

DELETE /analytics/:id

Delete a given analytics tag.

Access rights

Permissions:

  • Project owner

Authentication mode:

Request

DELETE /analytics/1 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the analytics tag ID

Response

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

List project analytics tags

GET /projects/:id/analytics

Retrieve project analytics tags (without pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

{
  "analytics": [
    {
      "id": 1,
      "tag": "UA-12345-43",
      "type": "google"
    },
    {
      "id": 2,
      "tag": "9876",
      "type": "facebook"
    }
  ]
}

Video

Create project video

POST /projects/:id/videos

Create a video for a given project.

A video must be unique for a given URL and language.

Access rights

Permissions:

  • Project owner
  • Partner

Authentication mode:

Request

POST /projects/123/videos HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

POST parameters

url string Video URL (required) language string Any supported language (required)

Example

{
  "url": "https://www.youtube.com/watch?v=IgWpDub8nnY",
  "language": "fr"
}

Response

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

{
  "id": 30133,
  "language": "fr",
  "author_name": "Ulule Channel",
  "author_url": "https://www.youtube.com/user/UluleChouette",
  "height": 0,
  "html": "<iframe width=\"480\" height=\"270\" src=\"https://www.youtube.com/embed/IgWpDub8nnY?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
  "provider_name": "YouTube",
  "provider_url": "https://www.youtube.com/",
  "thumbnail_height": 0,
  "thumbnail_url": "https://i.ytimg.com/vi/IgWpDub8nnY/hqdefault.jpg",
  "thumbnail_width": 0,
  "title": "Ulule TV #2",
  "type": "video",
  "url": "https://www.youtube.com/watch?v=IgWpDub8nnY",
  "version": "",
  "width": 0
}

Delete video

DELETE /videos/:id

Delete a video.

Access rights

Permissions:

  • Project owner
  • Partner

Authentication mode:

Request

DELETE /videos/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the video ID

Response

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

List project videos

GET /projects/:id/videos

Retrieve project videos (without pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Response

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

{
  "videos": [
    {
      "id": 1,
      "language": "fr",
      "author_name": "The Psychedelic Muse",
      "author_url": "https://www.youtube.com/user/ThePsychedelicMuse",
      "height": 0,
      "html": "<iframe src=\"https://www.youtube.com/...\"></iframe>",
      "provider_name": "YouTube",
      "provider_url": "https://www.youtube.com/",
      "thumbnail_height": 0,
      "thumbnail_url": "https://i.ytimg.com/vi/RI2x1NmsTh8/hqdefault.jpg",
      "thumbnail_width": 0,
      "title": "Solaris - Aeon V [Full Album]",
      "type": "video",
      "url": "https://www.youtube.com/watch?v=RI2x1NmsTh8",
      "version": "",
      "width": 0
    }, ...
  ]
}

Image

A project has three types of images:

  • main: one image required per project and cannot be deleted for the project’s language
  • background: allows an optional color attribute
  • secondary: any other image

For each image, a language is required (see supported languages).

Images with types main and background must be unique for a given language.

Create project image

POST /projects/:id/images

Create an image for a given project.

The content-type is multipart/form-data and not application/json

Access rights

Permissions:

  • Project owner
  • Partner

Authentication mode:

Request

POST /projects/123/images HTTP/1.1
Host: ulule.com
Accept: multipart/form-data

Path parameters

id required, the project ID

POST parameters

type text Type – “main”, “background” or “secondary” (required) lang text Any supported language (required) image file Image file – max 5 MB (required) color text HTML hex color code – ex: #ffffff (only required for “background”)

Response if type: main or secondary

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

 {
   "id": 1,
   "type": "main",
   "lang": "fr",
   "name": "my_picture.jpg",
   "versions": {
     "small": {
       "width": 230,
       "heigth": 126,
       "url": "https://.../230x126/images/my_picture.jpg"
     },
     "medium": {
       "width": 258,
       "heigth": 145,
       "url": "https://.../258x145/images/my_picture.jpg"
     },
     "large": {
       "width": 640,
       "heigth": 360,
       "url": "https://.../640x360/images/my_picture.jpg"
     },
     "full": {
       "url": "https://.../images/my_picture.jpg"
     }
   },
   "value": "images/my_picture.jpg"
 }

Response if type: background

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

 {
   "id": 1,
   "type": "main",
   "lang": "fr",
   "name": "my_picture.jpg",
   "url": "https://.../images/my_picture.jpg",
   "color": "#4286f4",
   "value": "images/my_picture.jpg"
 }

Update image

PATCH /images/:id

Update an image

The content-type is multipart/form-data and not application/json

Access rights

Permissions:

  • Project owner
  • Partner

Authentication mode:

Request

PATCH /images/123 HTTP/1.1
Host: ulule.com
Accept: multipart/form-data

Path parameters

id required, the image ID

PATCH parameters

image file Image file – max 5 MB (required) color text HTML hex color code – ex: #ffffff (only required for “background”)

Response if type: main or secondary

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

 {
   "id": 123,
   "type": "main",
   "lang": "fr",
   "name": "my_picture.jpg",
   "versions": {
     "small": {
       "width": 230,
       "heigth": 126,
       "url": "https://.../230x126/images/my_picture.jpg"
     },
     "medium": {
       "width": 258,
       "heigth": 145,
       "url": "https://.../258x145/images/my_picture.jpg"
     },
     "large": {
       "width": 640,
       "heigth": 360,
       "url": "https://.../640x360/images/my_picture.jpg"
     },
     "full": {
       "width": null,
       "heigth": null,
       "url": "https://.../images/my_picture.jpg"
     }
   },
   "value": "images/my_picture.jpg"
 }

Response if type: background

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

 {
   "id": 123,
   "type": "main",
   "lang": "fr",
   "name": "my_picture.jpg",
   "url": "https://.../images/my_picture.jpg",
   "color": "#4286f4",
   "value": "images/my_picture.jpg"
 }

Delete image

DELETE /images/:id

Delete an image. The main image linked to the project language cannot be deleted.

Access rights

Permissions:

  • Project owner
  • Partner

Authentication mode:

Request

DELETE /images/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the image ID

Response

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

List project images

GET /projects/:id/images

Retrieve project images (with pagination).

Access rights

Permissions:

  • None (anonymous)

Authentication mode:

Request

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

Path parameters

id required, the project ID

Query parameters

type Optional, the image type: main | secondary | background

GET /projects/2/images?type=main HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Response

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

{
  "images": [
    {
      "id": 5,
      "type": "main",
      "lang": "en",
      "versions": {
        "small": {
          "width": 230,
          "height": 126,
          "url": "https://.../230x126/presales/2/2/funny_cow.jpg"
        },
        "medium": {
          "width": 258,
          "height": 145,
          "url": "https://.../258x145/presales/2/2/funny_cow.jpg"
        },
        "large": {
          "width": 640,
          "height": 360,
          "url": "https://.../640x360/presales/2/2/funny_cow.jpg"
        },
        "full": {
          "width": null,
          "heigth": null,
          "url": "https://cloudfront.net/presales/2/2/funny_cow.jpg"
        }
      },
      "value": "presales/2/2/funny_cow.jpg",
      "name": "funny_cow.jpg"
    },
    {
      "id": 4,
      "type": "secondary",
      "lang": "fr",
      "versions": {
        "small": {
          "width": 230,
          "height": 126,
          "url": "https://.../230x126/presales/2/2/my_secondary.jpg"
        },
        "medium": {
          "width": 258,
          "height": 145,
          "url": "https://.../258x145/presales/2/2/my_secondary.jpg"
        },
        "large": {
          "width": 640,
          "height": 360,
          "url": "https://.../640x360/presales/2/2/my_secondary.jpg"
        },
        "full": {
          "width": null,
          "heigth": null,
          "url": "https://cloudfront.net/presales/2/2/my_secondary.jpg"
        }
      },
      "value": "presales/2/2/my_secondary.jpg",
      "name": "my_secondary.jpg"
    },
    {
      "id": 2,
      "type": "background",
      "lang": "fr",
      "color": "#49acfc",
      "url": "https://cloudfront.net/presales/2/2/my_background.jpg",
      "name": "my_background.jpg"
      "value": "presales/2/2/my_background.jpg",
    }, ...
  ],
  "meta": {
    "limit": 10,
    "next": "?limit=10&since=1494597959"
  }
}

Avatar

Create user avatar

POST /users/:id/avatars

Create an avatar for a given user.

The content-type is multipart/form-data and not application/json

Access rights

Permissions:

  • User

Authentication mode:

Request

POST /users/123/avatars HTTP/1.1
Host: ulule.com
Accept: multipart/form-data

Path parameters

id required, the user ID

POST parameters

image file Avatar file – max 5 MB (required)

Response

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

 {
    "id": 123,
    "versions": {
      "20x20": {
        "width": 20,
        "height": 20,
        "url": "https://img.ulule.com/display/d1b7.../user.092550.092557.jpeg"
      },
      "30x30":{
        "width": 30,
        "height": 30,
        "url": "https://img.ulule.com/display/dc27.../user.092550.092557.jpeg"
      },
      "40x40":{
        "width": 40,
        "height": 40,
        "url": "https://img.ulule.com/display/feac.../user.092550.092557.jpeg"
      },
      "55x55":{
        "width": 55,
        "height": 55,
        "url": "https://img.ulule.com/display/fc6a.../user.092550.092557.jpeg"
      },
      "75x75":{
        "width": 75,
        "height": 75,
        "url": "https://img.ulule.com/display/6821.../user.092550.092557.jpeg"
      },
      "90x90":{
        "width": 90,
        "height": 90,
        "url": "https://img.ulule.com/display/8968.../user.092550.092557.jpeg"
      },
      "128x128":{
        "width": 128,
        "height": 128,
        "url": "https://img.ulule.com/display/243.../user.092550.092557.jpeg"
      },
      "180x180":{
        "width": 180,
        "height": 180,
        "url": "https://img.ulule.com/display/538.../user.092550.092557.jpeg"
      },
      "230x230":{
        "width": 230,
        "height": 230,
        "url": "https://img.ulule.com/display/e7c.../user.092550.092557.jpeg"
      },
      "290x290":{
        "width": 290,
        "height": 290,
        "url": "https://img.ulule.com/display/674.../user.092550.092557.jpeg"
      },
      "full":{
        "width": null,
        "height": null,
        "url": "https://drfhlmcehrc34.cloudfront.net/avatar/.../user.092550.092557.jpeg"
      }
    },
    "name": "avatar.jpeg",
    "value": "avatar/.../user.092550.092557.jpeg"
 }

Update avatar

PATCH /avatars/:id

Updates an avatar.

The content-type is multipart/form-data and not application/json

Access rights

Permissions:

  • User

Authentication mode:

Request

PATCH /avatars/123 HTTP/1.1
Host: ulule.com
Accept: multipart/form-data

Path parameters

id required, the avatar ID

POST parameters

image file Avatar file – max 5 MB (required)

Response

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

 {
    "id": 123,
    "versions": {
      "20x20": {
        "width": 20,
        "height": 20,
        "url": "https://img.ulule.com/display/d1b7.../user.092550.092557.jpeg"
      },
      "30x30":{
        "width": 30,
        "height": 30,
        "url": "https://img.ulule.com/display/dc27.../user.092550.092557.jpeg"
      },
      "40x40":{
        "width": 40,
        "height": 40,
        "url": "https://img.ulule.com/display/feac.../user.092550.092557.jpeg"
      },
      "55x55":{
        "width": 55,
        "height": 55,
        "url": "https://img.ulule.com/display/fc6a.../user.092550.092557.jpeg"
      },
      "75x75":{
        "width": 75,
        "height": 75,
        "url": "https://img.ulule.com/display/6821.../user.092550.092557.jpeg"
      },
      "90x90":{
        "width": 90,
        "height": 90,
        "url": "https://img.ulule.com/display/8968.../user.092550.092557.jpeg"
      },
      "128x128":{
        "width": 128,
        "height": 128,
        "url": "https://img.ulule.com/display/243.../user.092550.092557.jpeg"
      },
      "180x180":{
        "width": 180,
        "height": 180,
        "url": "https://img.ulule.com/display/538.../user.092550.092557.jpeg"
      },
      "230x230":{
        "width": 230,
        "height": 230,
        "url": "https://img.ulule.com/display/e7c.../user.092550.092557.jpeg"
      },
      "290x290":{
        "width": 290,
        "height": 290,
        "url": "https://img.ulule.com/display/674.../user.092550.092557.jpeg"
      },
      "full":{
        "width": null,
        "height": null,
        "url": "https://drfhlmcehrc34.cloudfront.net/avatar/.../user.092550.092557.jpeg"
      }
    },
    "name": "avatar.jpeg",
    "value": "avatar/.../user.092550.092557.jpeg"
 }

Delete avatar

DELETE /avatars/:id

Delete an avatar.

Access rights

Permissions:

  • User

Authentication mode:

Request

DELETE /avatars/123 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the avatar ID

Response

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

Account

The account resource is where project owners declare their legal status and bank details in order to get the funds after their project has been successfully funded.

The typical workflow is the following:

  1. Create an account.
  2. Update the project account_id.
  3. Get the account edit_url.
  4. Let the project owner visit the edit_url and fill all the required fields.

The web page behind edit_url can be customized with the logo_url and return_url url parameters.

Get account

GET /accounts/:id

Retrieve a given account.

Access rights

Permissions:

  • Authenticated user

Authentication mode:

Request

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

Path parameters

id required, the account ID

Response

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

{
   "id": 1,
   "edit_url": "http://app.kolkt.com/accounts/1/edit",
   "status": "validated",
   "is_completed": true,
   "type": "business",
   "first_name": "Jony",
   "last_name": "Ive",
   "entity_name": "Apple",
   "email": "ive@apple.com",
   "birthday": "1967-02-27",
   "nationality": "US",
   "country": "US"
}

Create account

POST /accounts

Create an account.

Access rights

Permissions:

  • Account owner

Authentication mode:

Request

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

POST parameters

type string Type – “personal”, “business” or “association” (optional, default is “personal”) first_name string First name – between 3 and 30 characters (required) last_name string Last name – between 3 and 30 characters (required) entity_name string Name of business or association – max 250 characters (required if type is “business” or “association”) email string Email – max 254 characters (required) birthday string Birthday – format: YYYY-MM-DD (required) nationality string Nationality – ISO 3166-1 code (required) country string Country – ISO 3166-1 code (required)

Example

{
   "type": "business",
   "first_name": "Jony",
   "last_name": "Ive",
   "entity_name": "Apple",
   "email": "ive@apple.com",
   "birthday": "1967-02-27",
   "nationality": "US",
   "country": "US"
}

Response

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

{
   "id": 1,
   "edit_url": "",
   "is_completed": false,
   "status": "waiting",
   "type": "business",
   "first_name": "Jony",
   "last_name": "Ive",
   "entity_name": "Apple",
   "email": "ive@apple.com",
   "birthday": "1967-02-27",
   "nationality": "US",
   "country": "US"
}

Notifications

By default, users are notified when the following events happen.

Name Description
follow I’m followed by someone new
receive_message Someone sent me a private message
join Someone from my connections joined Ulule
support Someone from my connections has supported a new project
new_badge I received a new badge
new_badge_following Someone I’m following received a new badge
new_support I received a new support on my projects
new_comment_on_project I received a new comment on my projects
new_comment_on_project_news I received a new comment on one of my posted news
cancelled_support I received a cancellation of a support on my projects
new_faq I received a new question on one of my projects

The list of those notifications can be read via the get user notifications endpoint, and updated via the update user notifications endpoint.

By default, they also receive notifications when a news is published from a project they are fan of. Those notifications can be read via the get user projects endpoint, and updated via the patch project notifications endpoint.

Get user notifications

GET /users/:id/notifications

Access rights

Permissions:

  • User

Authentication mode:

Request

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

Path parameters

id required, the user ID

Response

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

 {
  "follow": true,
  "receive_message":true,
  "join": true,
  "support": true,
  "new_badge": true,
  "new_badge_following": true,
  "new_support": true,
  "new_comment_on_project": false,
  "new_comment_on_project_news": true,
  "cancelled_support": true,
  "new_faq": false,
}

Update user notifications

PATCH /users/:id/notifications

Access rights

Permissions:

  • User

Authentication mode:

Request

PATCH /users/123/notifications HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the user ID

Example

{
  "follow": true,
  "receive_message":true,
  "join": true,
  "support": true,
  "new_badge": true,
  "new_badge_following": true,
  "new_support": true,
  "new_comment_on_project": false,
  "new_comment_on_project_news": true,
  "cancelled_support": true,
  "new_faq": false
}

Response

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

 {
  "follow": true,
  "receive_message":true,
  "join": true,
  "support": true,
  "new_badge": true,
  "new_badge_following": true,
  "new_support": true,
  "new_comment_on_project": false,
  "new_comment_on_project_news": true,
  "cancelled_support": true,
  "new_faq": false
}

Update project notifications

PATCH /projects/:id/notifications

Access rights

Permissions:

  • User

Authentication mode:

Request

PATCH /projects/123/notifications HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the project ID

Example

{
  "news": true
}

Response

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

 {
   "news": true
 }

Workflow

Payment workflow

To create orders, we must follow this workflow:

  1. Create an access token or use Ulule Connect pop-up to retrieve this token. (endpoints are only available by access token)
  2. Update user profile to provide required information (see below)
  3. Create orders

To create orders, the order user must provide these requirements:

  • Nationality
  • Country
  • Birthday
  • First name
  • Last name
  • Email

If all these required attributes have been provided, is_completed attribute in user resource will be set to true and user will be authorized to create orders. Otherwise, is_completed attribute will be set to false and user will not be able to create any order.

To set or update these attributes, we can use the update user endpoint:

PATCH https://api.ulule.com/v1/users/:user_id

This endpoint will return the given user resource with is_completed attribute updated.

Once is_completed is true, user can create orders via the endpoint:

POST https://api.ulule.com/v1/projects/:project_id/orders

Shipping workflow

Each reward can contain shipping information, except variants.

Reward shipping attributes

Name Type Description
shipping_nat Float National shipping cost
shipping_int Float International shipping cost
shippings Array Shipping costs for specific countries
has_shippings Boolean Reward contains shippings

All these attributes can be null.

Shipping attributes

Objects contained in reward’s shippings array.

Name Type Description
countries Array Array of country codes
amount Float Shipping cost for these countries

Example

"rewards": [
    {
        "id": 160851,
        "name_de": "",
        "name_en": "",
        "name_es": "",
        "name_fr": "",
        "name_it": "",
        "name_nl": "",
        "name_pt": "",
        "description_de": "",
        "description_en": "",
        "description_es": "",
        "description_fr": "",
        "description_it": "",
        "description_nl": "",
        "description_pt": "",
        "price": 109,
        "stock": null,
        "stock_available": 100,
        "stock_taken": 347,
        "available": true,
        "shipping_nat": 10.0,
        "shipping_int": 20.0,
        "has_shippings": true,
        "shippings": [
            {
                "countries": ["FR", "ES"],
                "amount": 10.0
            },
            {
                "countries": ["RO"],
                "amount": 20.0
            }
        ]
    }
]

If we want to create an order that has rewards with shipping, we must provide the delivery country in country attribute at the order creation. Otherwise, a RequiredError error (see errors) will be returned.

For example, let’s create a presale order.

POST https://api.ulule.com/v1/projects/28994/orders

Our JSON payload:

{
    "payment_method": "creditcard",
    "return_url": "http://ulule.com",
    "rewards": [
        {"reward_id": 160851, "quantity": 1}
    ],
    "country": "FR"
}

As we are from France, we provided FR as country, this value will not be changed later. The shipping cost will be calculated for France and added to the order total amount.

A shipping address will be auto-created for this order. We will have to update this address later to fill missing attributes.

We get the created shipping address back with the shipping_address attribute:

{
    "id": 915213,
    "order_subtotal": "109.00",
    "order_total": "118.00",
    "payment_method": "creditcard",
    "status": 3,
    "status_display": "Awaiting confirmation",
    "absolute_url": "https://www.ulule.com/28994/edit/order/915213/detail/",
    "resource_uri": "https://api.ulule.com/v1/orders/915213",
    "billing_address": null,
    "shipping_address": {
        "id": 555200,
        "first_name": "",
        "last_name": "",
        "entity_name": "",
        "address1": "",
        "address2": "",
        "postal_code": "",
        "city": "",
        "state": "",
        "country": "FR",
        "user_id": 3048
    },
    "items": [
        {
            "line_total": "109.00",
            "reward_id": 160851,
            "quantity": 1,
            "unit_price": "109.00"
        }
    ],
    "created_at": "2015-06-24T14:14:33.030753Z",
    "payment_url": "https://www.ulule.com/projects/28994/checkout/pay/915213",
    "user": {
        ... // user resource
    },
    "project_id": 28994
}

We redirect the user to the payment_url as our previous examples, nothing changed.

The user will pay on the payment form (on kolkt.com) and will return eventually on your website.

If the user returns on your website, you can ask him to update the existing shipping address:

PATCH https://api.ulule.com/v1/addresses/555200

Our JSON payload:

{
    "first_name": "Florent",
    "last_name": "Foo",
    "address1": "8 Rue Saint-Fiacre",
    "postal_code": "75002",
    "city": "Paris"
}

The country cannot be updated because the shipping amount is already calculated and the user has already paid for this amount.

We get the following response:

{
    "id": 555200,
    "first_name": "Florent",
    "last_name": "Foo",
    "entity_name": "",
    "address1": "8 Rue Saint-Fiacre",
    "address2": "",
    "postal_code": "75002",
    "city": "Paris",
    "state": "",
    "country": "FR",
    "user_id": 3048
}

Now, let’s check our previous order:

GET https://api.ulule.com/v1/orders/915213

The shipping address has been updated:

{
    "id": 915213,
    "order_subtotal": "109.00",
    "order_total": "118.00",
    "payment_method": "creditcard",
    "status": 3,
    "status_display": "Awaiting confirmation",
    "absolute_url": "https://www.ulule.com/28994/edit/order/915213/detail/",
    "resource_uri": "https://api.ulule.com/v1/orders/915213",
    "billing_address": null,
    "shipping_address": {
        "id": 555200,
        "first_name": "Florent",
        "last_name": "Foo",
        "entity_name": "",
        "address1": "8 Rue Saint-Fiacre",
        "address2": "",
        "city": "Paris",
        "postal_code": "94140",
        "country": "FR",
        "state": "",
        "user_id": 3048
    },
    "items": [
        {
            "line_total": "109.00",
            "reward_id": 160851,
            "quantity": 1,
            "unit_price": "109.00"
        }
    ],
    "created_at": "2015-06-24T14:14:33.030753Z",
    "user": {
       ... // user resource
    },
    "project_id": 28994
}

Now, we have covered the case with reward which has shippings, even if your reward doesn’t have shippings, you can still update the order with a shipping address.

Checkout

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/

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 will be notified 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 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.

{
    "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"
    }
}

reward.deleted

Occurs when a reward is deleted.

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

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

Thread

Get thread

GET /threads/:id

Get thread details

Access rights

Permissions:

  • Thread recipients

Authentication mode:

Request

GET /threads/12345 HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the thread ID

Response

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

{
  "id": 12345,
  "sender_id": 54321,
  "created_at": "2014-11-21T21:59:59Z",
  "updated_at": "2015-10-21T22:59:59Z",
  "sender_deleted_at": "2015-10-21T22:59:59Z",
  "latest_message_id": 53421,
  "subject": "Questions about your last project",
  "recipient_count": 2,
  "messages_count": 11,
  "status": "unread",
  "latest_message": {
      ... // Message resource
  },
  "recipients": [
      {
          ... // User resource
      }, ...
  ]
}

List threads

GET /threads

List all threads for authenticated user

Access rights

Authentication mode:

Request

GET /threads/12345 HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

Response

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

{
  "threads": [
      {
          "id": 12345,
          "sender_id": 54321,
          "created_at": "2014-11-21T21:59:59Z",
          "updated_at": "2015-10-21T22:59:59Z",
          "sender_deleted_at": "2015-10-21T22:59:59Z",
          "latest_message_id": 53421,
          "subject": "Questions about your last project",
          "recipient_count": 2,
          "messages_count": 11,
          "status": "unread",
          "latest_message": {
              ... // Message resource
          },
          "recipients": [
              {
                  ... // User resource
              }, ...
          ]
     }, ...
  ],
  "meta": {
      "limit": 20,
      "next": null
  }
}

Create thread

POST /threads

Create a new thread.

Access rights

Permissions:

  • User

Authentication mode:

Request

POST /threads HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

POST parameters

subject string the thread subject.

Example

{
    "subject": "Questions about your last project"
}

Response

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

{
  "id": 12345,
  "sender_id": 54321,
  "created_at": "2014-11-21T21:59:59Z",
  "updated_at": "2015-10-21T22:59:59Z",
  "sender_deleted_at": "2015-10-21T22:59:59Z",
  "latest_message_id": 53421,
  "subject": "Questions about your last project",
  "recipient_count": 2,
  "messages_count": 11,
  "status": "read",
  "latest_message": {
      ... // Message resource
  },
  "recipients": [
      {
          ... // User resource
      },...
  ]
}

Update thread

PATCH /threads/:id

Update the given thread.

Access rights

Permissions:

  • Thread owner

Authentication mode:

Request

PATCH /threads/123 HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

PATCH parameters

subject string the thread subject.

Example

{
    "subject": "Questions about your last project"
}

Response

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

{
  "id": 12345,
  "sender_id": 54321,
  "created_at": "2014-11-21T21:59:59Z",
  "updated_at": "2015-10-21T22:59:59Z",
  "sender_deleted_at": "2015-10-21T22:59:59Z",
  "latest_message_id": 53421,
  "subject": "Questions about your last project",
  "recipient_count": 2,
  "messages_count": 11,
  "status": "read",
  "latest_message": {
      ... // Message resource
  },
  "recipients": [
      {
          ... // User resource
      },...
  ]
}

Read thread

POST /threads/:id/read

Mark thread as read.

Access rights

Permissions:

  • Thread recipient

Authentication mode:

Request

POST /threads/123/read HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

Response

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

Unread thread

POST /threads/:id/unread

Mark thread as unread.

Access rights

Permissions:

  • Thread recipient

Authentication mode:

Request

POST /threads/123/unread HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

Response

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

Unwatch thread

POST /threads/:id/unwatch

Unwatch a thread

Access rights

Permissions:

  • Thread recipient

Authentication mode:

Request

POST /threads/123/unwatch HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

Response

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

Recipient

List thread recipients

GET /threads/:id/recipients

List thread recipients

Access rights

Permissions:

  • Thread recipients

Authentication mode:

Request

GET /threads/123/recipients HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

Response

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

{
    "recipients": [
        {
            "id": 123,
            "user": {
              ... // User resource
            }
      }, ...
  ]
}

Create thread recipient

POST /threads/:id/recipients

Create a thread recipient

Access rights

Permissions:

  • Thread recipients

Authentication mode:

Request

POST /threads/123/recipients HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

POST parameters

user_id int the user ID.

Example

{
    "user_id": 1234
}

Response

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

{
    "id": 123,
    "user": {
        ... // User resource
    }
}

Message

List thread messages

GET /threads/:id/messages

Retrieve all messages of the thread

Access rights

Permissions:

  • Thread recipients

Authentication mode:

Request

GET /threads/123/messages HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

Response

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

{
    "messages": [
        {
            "id": 1234,
            "sent_at": "2014-11-21T21:59:59Z",
            "sender_deleted_at": "2015-10-21T22:59:59Z",
            "body": "I love pizza",
            "sender": {
                ... // User resource
            },
            "attachments": [
              {
                  ... // Attachment resource
              }, ...
            ]
      }, ...
  ],
  "meta": {
      "limit": 20,
      "next": null
  }
}

Create thread message

POST /threads/:id/messages

Create a thread message

Access rights

Permissions:

  • Thread recipients

Authentication mode:

Request

POST /threads/123/messages HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

POST parameters

body string the message body.

Example

{
    "body": "I love pizza"
}

Response

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

{
    "id": 1234,
    "sent_at": "2014-11-21T21:59:59Z",
    "sender_deleted_at": "2015-10-21T22:59:59Z",
    "body": "I love pizza",
    "sender": {
      ... // User resource
    },
    "attachments": [
      {
          ... // Attachment resource
      }, ...
    ]
}

Update message

PATCH /messages/:id

Update the given message.

Access rights

Permissions:

  • Thread owner

Authentication mode:

Request

PATCH /messages/123 HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

PATCH parameters

body string the message body.

Example

{
    "body": "I love burger"
}

Response

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

{
    "id": 1234,
    "sender_id": 4321,
    "sent_at": "2014-11-21T21:59:59Z",
    "sender_deleted_at": "2015-10-21T22:59:59Z",
    "body": "I love pizza",
    "sender": {
      ... // User resource
    },
    "attachments": [
        {
            ... // Attachment resource
        }, ...
    ]
}

Attachment

Create message attachment

POST /messages/:id/attachments

Create a message attachment

Access rights

Permissions:

  • Message sender

Authentication mode:

Request

POST /messages/123/attachments HTTP/1.1
Host: discussions.ulule.com
Accept: application/json, text/javascript

POST parameters

file file the file (required)

Response

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

{
    "id": 1234,
    "file": "https://cloudfront.com/.../file.pdf"
}

Delete attachment

DELETE /attachments/:id

Delete attachment.

Access rights

Permissions:

  • Message sender

Authentication mode:

Request

DELETE /attachments/1 HTTP/1.1
Host: ulule.com
Accept: application/json, text/javascript

Path parameters

id required, the attachment ID

Response

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

Inspirations

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

We would like to thank their authors: