mirror of
https://github.com/pretix/pretix.git
synced 2025-12-06 21:42:49 +00:00
Compare commits
9 Commits
validate-d
...
v1.10.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae485a77d6 | ||
|
|
29e17d2284 | ||
|
|
6b95aca3f7 | ||
|
|
f227319f29 | ||
|
|
e63b85ccd6 | ||
|
|
bf3398e5f6 | ||
|
|
765d98464e | ||
|
|
66bdf9ab79 | ||
|
|
da830ef0a4 |
@@ -1,10 +1,3 @@
|
||||
doc/
|
||||
env/
|
||||
res/
|
||||
local/
|
||||
.git/
|
||||
pretixeu/
|
||||
src/data/
|
||||
src/pretix/static.dist/
|
||||
src/dist/
|
||||
|
||||
|
||||
25
.gitattributes
vendored
25
.gitattributes
vendored
@@ -1,17 +1,14 @@
|
||||
src/pretix/static/fontawesome/* linguist-vendored
|
||||
src/pretix/static/lightbox/* linguist-vendored
|
||||
src/pretix/static/typeahead/* linguist-vendored
|
||||
src/pretix/static/moment/* linguist-vendored
|
||||
src/pretix/static/datetimepicker/* linguist-vendored
|
||||
src/pretix/static/colorpicker/* linguist-vendored
|
||||
src/pretix/static/fileupload/* linguist-vendored
|
||||
src/pretix/static/vuejs/* linguist-vendored
|
||||
src/pretix/static/select2/* linguist-vendored
|
||||
src/pretix/static/charts/* linguist-vendored
|
||||
src/pretix/static/rrule/* linguist-vendored
|
||||
src/pretix/static/iframeresizer/* linguist-vendored
|
||||
src/pretix/static/pdfjs/* linguist-vendored
|
||||
src/pretix/static/fabric/* linguist-vendored
|
||||
src/static/fontawesome/* linguist-vendored
|
||||
src/static/lightbox/* linguist-vendored
|
||||
src/static/typeahead/* linguist-vendored
|
||||
src/static/moment/* linguist-vendored
|
||||
src/static/datetimepicker/* linguist-vendored
|
||||
src/static/colorpicker/* linguist-vendored
|
||||
src/static/fileupload/* linguist-vendored
|
||||
src/static/vuejs/* linguist-vendored
|
||||
src/static/charts/* linguist-vendored
|
||||
src/pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/fabric.* linguist-vendored
|
||||
src/pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/pdf.* linguist-vendored
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.eot binary
|
||||
|
||||
42
.github/workflows/docs.yml
vendored
42
.github/workflows/docs.yml
vendored
@@ -1,42 +0,0 @@
|
||||
name: Documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'src/pretix/locale/**'
|
||||
- 'src/pretix/static/**'
|
||||
- 'src/tests/**'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'src/pretix/locale/**'
|
||||
- 'src/pretix/static/**'
|
||||
- 'src/tests/**'
|
||||
|
||||
jobs:
|
||||
spelling:
|
||||
name: Spellcheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Install system packages
|
||||
run: sudo apt update && sudo apt install enchant hunspell aspell-en
|
||||
- name: Install Dependencies
|
||||
run: pip3 install --no-use-pep517 -Ur doc/requirements.txt
|
||||
- name: Spellcheck docs
|
||||
run: make spelling
|
||||
working-directory: ./doc
|
||||
- name:
|
||||
run: '[ ! -s _build/spelling/output.txt ]'
|
||||
working-directory: ./doc
|
||||
62
.github/workflows/strings.yml
vendored
62
.github/workflows/strings.yml
vendored
@@ -1,62 +0,0 @@
|
||||
name: Strings
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- 'doc/**'
|
||||
- 'src/pretix/locale/**'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- 'doc/**'
|
||||
- 'src/pretix/locale/**'
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
runs-on: ubuntu-latest
|
||||
name: Check gettext syntax
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Install system packages
|
||||
run: sudo apt update && sudo apt install gettext
|
||||
- name: Install Dependencies
|
||||
run: pip3 install --no-use-pep517 -Ur src/requirements.txt
|
||||
- name: Compile messages
|
||||
run: python manage.py compilemessages
|
||||
working-directory: ./src
|
||||
- name: Compile jsi18n
|
||||
run: python manage.py compilejsi18n
|
||||
working-directory: ./src
|
||||
spelling:
|
||||
runs-on: ubuntu-latest
|
||||
name: Spellcheck
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Install system packages
|
||||
run: sudo apt update && sudo apt install enchant hunspell hunspell-de-de aspell-en aspell-de
|
||||
- name: Install Dependencies
|
||||
run: pip3 install --no-use-pep517 -Ur src/requirements/dev.txt
|
||||
- name: Spellcheck translations
|
||||
run: potypo
|
||||
working-directory: ./src
|
||||
55
.github/workflows/style.yml
vendored
55
.github/workflows/style.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: Code Style
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'src/pretix/locale/**'
|
||||
- 'src/pretix/static/**'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'src/pretix/locale/**'
|
||||
- 'src/pretix/static/**'
|
||||
|
||||
jobs:
|
||||
isort:
|
||||
name: isort
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Install Dependencies
|
||||
run: pip3 install --no-use-pep517 -Ur src/requirements/dev.txt
|
||||
- name: Run isort
|
||||
run: isort -c .
|
||||
working-directory: ./src
|
||||
flake:
|
||||
name: flake8
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Install Dependencies
|
||||
run: pip3 install -r src/requirements.txt --no-use-pep517 -Ur src/requirements/dev.txt
|
||||
- name: Run flake8
|
||||
run: flake8 .
|
||||
working-directory: ./src
|
||||
75
.github/workflows/tests.yml
vendored
75
.github/workflows/tests.yml
vendored
@@ -1,75 +0,0 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
- 'src/pretix/locale/**'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
- 'src/pretix/locale/**'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: Tests
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.6, 3.7, 3.8]
|
||||
database: [sqlite, postgres, mysql]
|
||||
exclude:
|
||||
- database: mysql
|
||||
python-version: 3.7
|
||||
- database: sqlite
|
||||
python-version: 3.7
|
||||
- database: mysql
|
||||
python-version: 3.6
|
||||
- database: sqlite
|
||||
python-version: 3.6
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: getong/mariadb-action@v1.1
|
||||
with:
|
||||
mariadb version: '10.4'
|
||||
mysql database: 'pretix'
|
||||
mysql root password: ''
|
||||
if: matrix.database == 'mysql'
|
||||
- uses: harmon758/postgresql-action@v1
|
||||
with:
|
||||
postgresql version: '11'
|
||||
postgresql db: 'pretix'
|
||||
postgresql user: 'postgres'
|
||||
postgresql password: 'postgres'
|
||||
if: matrix.database == 'postgres'
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Install system dependencies
|
||||
run: sudo apt update && sudo apt install gettext mysql-client
|
||||
- name: Install Python dependencies
|
||||
run: pip3 install -r src/requirements.txt --no-use-pep517 -Ur src/requirements/dev.txt mysqlclient psycopg2-binary
|
||||
- name: Run checks
|
||||
run: python manage.py check
|
||||
working-directory: ./src
|
||||
- name: Compile
|
||||
working-directory: ./src
|
||||
run: make all compress
|
||||
- name: Run tests
|
||||
working-directory: ./src
|
||||
run: PRETIX_CONFIG_FILE=tests/travis_${{ matrix.database }}.cfg py.test -n 3 -p no:sugar --cov=./ --cov-report=xml --reruns 3 tests --maxfail=100
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: src/coverage.xml
|
||||
fail_ci_if_error: true
|
||||
if: matrix.database == 'postgres' && matrix.python-version == '3.8'
|
||||
@@ -5,11 +5,7 @@ tests:
|
||||
- virtualenv env
|
||||
- source env/bin/activate
|
||||
- pip install -U pip wheel setuptools
|
||||
- XDG_CACHE_HOME=/cache pip3 install -r src/requirements.txt --no-use-pep517 -Ur src/requirements/dev.txt
|
||||
- cd src
|
||||
- python manage.py check
|
||||
- make all compress
|
||||
- py.test --reruns 3 -n 3 tests
|
||||
- XDG_CACHE_HOME=/cache bash .travis.sh tests
|
||||
tags:
|
||||
- python3
|
||||
except:
|
||||
@@ -20,17 +16,11 @@ pypi:
|
||||
- cp /keys/.pypirc ~/.pypirc
|
||||
- virtualenv env
|
||||
- source env/bin/activate
|
||||
- pip install -U pip wheel setuptools check-manifest twine
|
||||
- XDG_CACHE_HOME=/cache pip3 install -Ur src/requirements.txt -r src/requirements/dev.txt
|
||||
- pip install -U pip wheel setuptools
|
||||
- XDG_CACHE_HOME=/cache pip3 install -Ur src/requirements.txt -r src/requirements/dev.txt -r src/requirements/py34.txt
|
||||
- cd src
|
||||
- python setup.py sdist
|
||||
- pip install dist/pretix-*.tar.gz
|
||||
- python -m pretix migrate
|
||||
- python -m pretix check
|
||||
- check-manifest
|
||||
- python setup.py sdist bdist_wheel
|
||||
- twine check dist/*
|
||||
- twine upload dist/*
|
||||
- python setup.py sdist upload
|
||||
- python setup.py bdist_wheel upload
|
||||
tags:
|
||||
- python3
|
||||
only:
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
-r src/requirements/py34.txt
|
||||
-r doc/requirements.txt
|
||||
|
||||
56
.travis.sh
Executable file
56
.travis.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
set -x
|
||||
|
||||
echo "Executing job $1"
|
||||
|
||||
if [ "$PRETIX_CONFIG_FILE" == "tests/travis_mysql.cfg" ]; then
|
||||
mysql -u root -e 'CREATE DATABASE pretix DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;'
|
||||
pip3 install -Ur src/requirements/mysql.txt
|
||||
fi
|
||||
|
||||
if [ "$PRETIX_CONFIG_FILE" == "tests/travis_postgres.cfg" ]; then
|
||||
psql -c 'create database travis_ci_test;' -U postgres
|
||||
pip3 install -Ur src/requirements/postgres.txt
|
||||
fi
|
||||
|
||||
if [ "$1" == "style" ]; then
|
||||
XDG_CACHE_HOME=/cache pip3 install -Ur src/requirements.txt -r src/requirements/dev.txt -r src/requirements/py34.txt
|
||||
cd src
|
||||
flake8 .
|
||||
isort -c -rc -df .
|
||||
fi
|
||||
if [ "$1" == "doctests" ]; then
|
||||
XDG_CACHE_HOME=/cache pip3 install -Ur doc/requirements.txt -r src/requirements/py34.txt
|
||||
cd doc
|
||||
make doctest
|
||||
fi
|
||||
if [ "$1" == "tests" ]; then
|
||||
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt -r src/requirements/py34.txt
|
||||
cd src
|
||||
python manage.py check
|
||||
make all compress
|
||||
py.test --rerun 5 tests
|
||||
fi
|
||||
if [ "$1" == "tests-cov" ]; then
|
||||
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt -r src/requirements/py34.txt
|
||||
cd src
|
||||
python manage.py check
|
||||
make all compress
|
||||
coverage run -m py.test --rerun 5 tests && codecov
|
||||
fi
|
||||
if [ "$1" == "plugins" ]; then
|
||||
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt -r src/requirements/py34.txt
|
||||
cd src
|
||||
python setup.py develop
|
||||
make all compress
|
||||
|
||||
pushd ~
|
||||
git clone --depth 1 https://github.com/pretix/pretix-cartshare.git
|
||||
cd pretix-cartshare
|
||||
python setup.py develop
|
||||
make
|
||||
py.test --rerun 5 tests
|
||||
popd
|
||||
|
||||
fi
|
||||
40
.travis.yml
Normal file
40
.travis.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
language: python
|
||||
sudo: false
|
||||
install:
|
||||
- pip install -U pip wheel setuptools==28.6.1
|
||||
script:
|
||||
- bash .travis.sh $JOB
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/pip
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
matrix:
|
||||
include:
|
||||
- python: 3.6
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_sqlite.cfg
|
||||
- python: 3.6
|
||||
env: JOB=tests-cov
|
||||
- python: 3.6
|
||||
env: JOB=style
|
||||
- python: 3.4
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_sqlite.cfg
|
||||
- python: 3.5
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_sqlite.cfg
|
||||
- python: 3.4
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_mysql.cfg
|
||||
- python: 3.5
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_mysql.cfg
|
||||
- python: 3.6
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_mysql.cfg
|
||||
- python: 3.4
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||
- python: 3.5
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||
- python: 3.6
|
||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||
- python: 3.6
|
||||
env: JOB=plugins
|
||||
addons:
|
||||
postgresql: "9.4"
|
||||
@@ -3,7 +3,7 @@ Contributing to pretix
|
||||
|
||||
Hey there and welcome to pretix!
|
||||
|
||||
We've got a contributors guide in [our documentation](https://docs.pretix.eu/en/latest/development/contribution/)
|
||||
We've got an contributors guide in [our documentation](https://docs.pretix.eu/en/latest/development/contribution/)
|
||||
together with notes on the [development setup](https://docs.pretix.eu/en/latest/development/setup.html).
|
||||
|
||||
Please note that we have a [Code of Conduct](https://docs.pretix.eu/en/latest/development/contribution/codeofconduct.html)
|
||||
|
||||
55
Dockerfile
55
Dockerfile
@@ -1,26 +1,10 @@
|
||||
FROM python:3.8
|
||||
FROM python:3.6
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
default-libmysqlclient-dev \
|
||||
gettext \
|
||||
git \
|
||||
libffi-dev \
|
||||
libjpeg-dev \
|
||||
libmemcached-dev \
|
||||
libpq-dev \
|
||||
libssl-dev \
|
||||
libxml2-dev \
|
||||
libxslt1-dev \
|
||||
locales \
|
||||
nginx \
|
||||
python-dev \
|
||||
python-virtualenv \
|
||||
python3-dev \
|
||||
sudo \
|
||||
supervisor \
|
||||
zlib1g-dev && \
|
||||
apt-get install -y git libxml2-dev libxslt1-dev python-dev python-virtualenv locales \
|
||||
libffi-dev build-essential python3-dev zlib1g-dev libssl-dev gettext libpq-dev \
|
||||
libmysqlclient-dev libmemcached-dev libjpeg-dev supervisor nginx sudo \
|
||||
--no-install-recommends && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
dpkg-reconfigure locales && \
|
||||
@@ -29,42 +13,25 @@ RUN apt-get update && \
|
||||
mkdir /etc/pretix && \
|
||||
mkdir /data && \
|
||||
useradd -ms /bin/bash -d /pretix -u 15371 pretixuser && \
|
||||
echo 'pretixuser ALL=(ALL) NOPASSWD:SETENV: /usr/bin/supervisord' >> /etc/sudoers && \
|
||||
mkdir /static && \
|
||||
mkdir /etc/supervisord
|
||||
echo 'pretixuser ALL=(ALL) NOPASSWD: /usr/bin/supervisord' >> /etc/sudoers && \
|
||||
mkdir /static
|
||||
|
||||
ENV LC_ALL=C.UTF-8 \
|
||||
DJANGO_SETTINGS_MODULE=production_settings
|
||||
|
||||
# To copy only the requirements files needed to install from PIP
|
||||
COPY src/requirements /pretix/src/requirements
|
||||
COPY src/requirements.txt /pretix/src
|
||||
RUN pip3 install -U \
|
||||
pip \
|
||||
setuptools \
|
||||
wheel && \
|
||||
cd /pretix/src && \
|
||||
pip3 install \
|
||||
-r requirements.txt \
|
||||
-r requirements/memcached.txt \
|
||||
-r requirements/mysql.txt \
|
||||
gunicorn django-extensions ipython && \
|
||||
rm -rf ~/.cache/pip
|
||||
|
||||
COPY deployment/docker/pretix.bash /usr/local/bin/pretix
|
||||
COPY deployment/docker/supervisord /etc/supervisord
|
||||
COPY deployment/docker/supervisord.all.conf /etc/supervisord.all.conf
|
||||
COPY deployment/docker/supervisord.web.conf /etc/supervisord.web.conf
|
||||
COPY deployment/docker/supervisord.conf /etc/supervisord.conf
|
||||
COPY deployment/docker/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY deployment/docker/production_settings.py /pretix/src/production_settings.py
|
||||
COPY src /pretix/src
|
||||
|
||||
RUN cd /pretix/src && pip3 install .
|
||||
|
||||
RUN chmod +x /usr/local/bin/pretix && \
|
||||
rm /etc/nginx/sites-enabled/default && \
|
||||
pip3 install -U pip wheel setuptools && \
|
||||
cd /pretix/src && \
|
||||
rm -f pretix.cfg && \
|
||||
pip3 install -r requirements.txt -r requirements/mysql.txt -r requirements/postgres.txt \
|
||||
-r requirements/memcached.txt -r requirements/redis.txt gunicorn && \
|
||||
mkdir -p data && \
|
||||
chown -R pretixuser:pretixuser /pretix /data data && \
|
||||
sudo -u pretixuser make production
|
||||
|
||||
27
README.rst
27
README.rst
@@ -4,10 +4,11 @@ pretix
|
||||
.. image:: https://img.shields.io/pypi/v/pretix.svg
|
||||
:target: https://pypi.python.org/pypi/pretix
|
||||
|
||||
.. image:: https://github.com/pretix/pretix/workflows/Documentation/badge.svg
|
||||
.. image:: https://readthedocs.org/projects/pretix/badge/?version=latest
|
||||
:target: https://docs.pretix.eu/en/latest/
|
||||
|
||||
.. image:: https://github.com/pretix/pretix/workflows/Tests/badge.svg
|
||||
.. image:: https://travis-ci.org/pretix/pretix.svg?branch=master
|
||||
:target: https://travis-ci.org/pretix/pretix
|
||||
|
||||
.. image:: https://codecov.io/gh/pretix/pretix/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/pretix/pretix
|
||||
@@ -19,8 +20,9 @@ Reinventing ticket presales, one ticket at a time.
|
||||
Project status & release cycle
|
||||
------------------------------
|
||||
|
||||
While there is always a lot to do and improve on, pretix by now has been in use for thousands of events
|
||||
conferences that sold millions of tickets combined. We therefore think of pretix as being stable and ready to use.
|
||||
While there is always a lot to do and improve on, pretix by now has been in use for more than a dozen
|
||||
conferences that sold over ten thousand tickets combined without major problems. We therefore think of
|
||||
pretix as being stable and ready to use.
|
||||
|
||||
If you want to use or extend pretix, we strongly recommend to follow our `blog`_. We will announce all
|
||||
releases there. You can always find the latest stable version on PyPI or in the ``release/X.Y`` branch of
|
||||
@@ -29,22 +31,15 @@ the sense that it does not break your data, but its APIs might change without p
|
||||
|
||||
To get started using pretix on your own server, look at the `installation guide`_ in our documentation.
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
This project is 100 percent free and open source software. You are welcome to ask questions in the GitHub
|
||||
repository. Private support via email or phone is only offered to customers of our pretix Hosted or pretix
|
||||
Enterprise offerings. If you are interested in commercial support, hosting services or supporting this project
|
||||
financially, please go to `pretix.eu`_ or contact us at support@pretix.eu.
|
||||
This project is 100 percent free and open source software. If you are interested in commercial support,
|
||||
hosting services or supporting this project financially, please go to `pretix.eu`_ or contact us at
|
||||
support@pretix.eu.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
If you want to contribute to pretix, please read the `developer documentation`_
|
||||
in our documentation. If you have any further questions, please do not hesitate to ask!
|
||||
|
||||
.. image:: https://translate.pretix.eu/widgets/pretix/-/pretix/multi-blue.svg
|
||||
:target: https://translate.pretix.eu/engage/pretix/
|
||||
|
||||
Code of Conduct
|
||||
---------------
|
||||
We have a `Code of Conduct`_ in place that applies to all project contributions,
|
||||
@@ -55,8 +50,8 @@ License
|
||||
The code in this repository is published under the terms of the Apache License.
|
||||
See the LICENSE file for the complete license text.
|
||||
|
||||
This project is maintained by Raphael Michel. See the AUTHORS file for a list of all
|
||||
the awesome folks who contributed to this project.
|
||||
This project is maintained by Raphael Michel <mail@raphaelmichel.de>. See the
|
||||
AUTHORS file for a list of all the awesome folks who contributed to this project.
|
||||
|
||||
.. _installation guide: https://docs.pretix.eu/en/latest/admin/installation/index.html
|
||||
.. _developer documentation: https://docs.pretix.eu/en/latest/development/index.html
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
user www-data www-data;
|
||||
worker_processes auto;
|
||||
worker_processes 1;
|
||||
pid /var/run/nginx.pid;
|
||||
daemon off;
|
||||
worker_rlimit_nofile 262144;
|
||||
|
||||
events {
|
||||
worker_connections 16384;
|
||||
multi_accept on;
|
||||
use epoll;
|
||||
worker_connections 768;
|
||||
}
|
||||
|
||||
http {
|
||||
@@ -42,7 +39,7 @@ http {
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
|
||||
server {
|
||||
listen 80 backlog=4096 default_server;
|
||||
listen 80 default_server;
|
||||
listen [::]:80 ipv6only=on default_server;
|
||||
server_name _;
|
||||
index index.php index.html;
|
||||
|
||||
@@ -3,10 +3,7 @@ cd /pretix/src
|
||||
export DJANGO_SETTINGS_MODULE=production_settings
|
||||
export DATA_DIR=/data/
|
||||
export HOME=/pretix
|
||||
|
||||
AUTOMIGRATE=${AUTOMIGRATE:-yes}
|
||||
NUM_WORKERS_DEFAULT=$((2 * $(nproc --all)))
|
||||
export NUM_WORKERS=${NUM_WORKERS:-$NUM_WORKERS_DEFAULT}
|
||||
NUM_WORKERS=10
|
||||
|
||||
if [ ! -d /data/logs ]; then
|
||||
mkdir /data/logs;
|
||||
@@ -19,16 +16,10 @@ if [ "$1" == "cron" ]; then
|
||||
exec python3 -m pretix runperiodic
|
||||
fi
|
||||
|
||||
if [ "$AUTOMIGRATE" != "skip" ]; then
|
||||
python3 -m pretix migrate --noinput
|
||||
fi
|
||||
python3 -m pretix migrate --noinput
|
||||
|
||||
if [ "$1" == "all" ]; then
|
||||
exec sudo -E /usr/bin/supervisord -n -c /etc/supervisord.all.conf
|
||||
fi
|
||||
|
||||
if [ "$1" == "web" ]; then
|
||||
exec sudo -E /usr/bin/supervisord -n -c /etc/supervisord.web.conf
|
||||
exec sudo /usr/bin/supervisord -n -c /etc/supervisord.conf
|
||||
fi
|
||||
|
||||
if [ "$1" == "webworker" ]; then
|
||||
@@ -42,12 +33,17 @@ if [ "$1" == "webworker" ]; then
|
||||
fi
|
||||
|
||||
if [ "$1" == "taskworker" ]; then
|
||||
shift
|
||||
exec celery -A pretix.celery_app worker -l info "$@"
|
||||
export C_FORCE_ROOT=True
|
||||
exec celery -A pretix.celery_app worker -l info
|
||||
fi
|
||||
|
||||
if [ "$1" == "shell" ]; then
|
||||
exec python3 -m pretix shell
|
||||
fi
|
||||
|
||||
if [ "$1" == "upgrade" ]; then
|
||||
exec python3 -m pretix updatestyles
|
||||
fi
|
||||
|
||||
exec python3 -m pretix "$@"
|
||||
echo "Specify argument: all|cron|webworker|taskworker|shell|upgrade"
|
||||
exit 1
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
[include]
|
||||
files = /etc/supervisord/*.conf
|
||||
44
deployment/docker/supervisord.conf
Normal file
44
deployment/docker/supervisord.conf
Normal file
@@ -0,0 +1,44 @@
|
||||
[unix_http_server]
|
||||
file=/tmp/supervisor.sock
|
||||
|
||||
[supervisord]
|
||||
logfile=/tmp/supervisord.log
|
||||
logfile_maxbytes=50MB
|
||||
logfile_backups=10
|
||||
loglevel=info
|
||||
pidfile=/tmp/supervisord.pid
|
||||
nodaemon=false
|
||||
minfds=1024
|
||||
minprocs=200
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///tmp/supervisor.sock
|
||||
|
||||
[program:pretixweb]
|
||||
command=/usr/local/bin/pretix webworker
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=5
|
||||
user=pretixuser
|
||||
environment=HOME=/pretix
|
||||
|
||||
[program:pretixtask]
|
||||
command=/usr/local/bin/pretix taskworker
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=5
|
||||
user=pretixuser
|
||||
|
||||
[program:nginx]
|
||||
command=/usr/sbin/nginx
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
stdout_events_enabled=true
|
||||
stderr_events_enabled=true
|
||||
|
||||
[include]
|
||||
files = /etc/supervisord-*.conf
|
||||
@@ -1,2 +0,0 @@
|
||||
[include]
|
||||
files = /etc/supervisord/base.conf /etc/supervisord/nginx.conf /etc/supervisord/pretixweb.conf
|
||||
@@ -1,18 +0,0 @@
|
||||
[unix_http_server]
|
||||
file=/tmp/supervisor.sock
|
||||
|
||||
[supervisord]
|
||||
logfile=/tmp/supervisord.log
|
||||
logfile_maxbytes=50MB
|
||||
logfile_backups=10
|
||||
loglevel=info
|
||||
pidfile=/tmp/supervisord.pid
|
||||
nodaemon=false
|
||||
minfds=1024
|
||||
minprocs=200
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///tmp/supervisor.sock
|
||||
@@ -1,7 +0,0 @@
|
||||
[program:nginx]
|
||||
command=/usr/sbin/nginx
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
stdout_events_enabled=true
|
||||
stderr_events_enabled=true
|
||||
@@ -1,6 +0,0 @@
|
||||
[program:pretixtask]
|
||||
command=/usr/local/bin/pretix taskworker
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=5
|
||||
user=pretixuser
|
||||
@@ -1,7 +0,0 @@
|
||||
[program:pretixweb]
|
||||
command=/usr/local/bin/pretix webworker
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=5
|
||||
user=pretixuser
|
||||
environment=HOME=/pretix
|
||||
@@ -175,9 +175,3 @@ pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
|
||||
spelling:
|
||||
$(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) $(BUILDDIR)/spelling
|
||||
@echo
|
||||
@echo "Spelling check finished, look at the results in " \
|
||||
"$(BUILDDIR)/spelling/output.txt."
|
||||
|
||||
@@ -6099,6 +6099,3 @@ img.screenshot, a.screenshot img {
|
||||
.versionchanged p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.rst-content td > .line-block {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
.. _`config`:
|
||||
|
||||
.. spelling:: Galera
|
||||
|
||||
Configuration file
|
||||
==================
|
||||
|
||||
@@ -12,7 +10,7 @@ at the following locations. It will try to read the file from the specified path
|
||||
the following order. The file that is found *last* will override the settings from
|
||||
the files found before.
|
||||
|
||||
1. ``PRETIX_CONFIG_FILE`` environment variable
|
||||
1. ``PREFIX_CONFIG_FILE`` environment variable
|
||||
2. ``/etc/pretix/pretix.cfg``
|
||||
3. ``~/.pretix.cfg``
|
||||
4. ``pretix.cfg`` in the current working directory
|
||||
@@ -23,14 +21,6 @@ The config file may contain the following sections (all settings are optional an
|
||||
default values). We suggest that you start from the examples given in one of the
|
||||
installation tutorials.
|
||||
|
||||
.. note::
|
||||
|
||||
The configuration file is the recommended way to configure pretix. However, you can
|
||||
also set them through environment variables. In this case, the syntax is
|
||||
``PRETIX_SECTION_CONFIG``. For example, to configure the setting ``password_reset``
|
||||
from the ``[pretix]`` section, set ``PRETIX_PRETIX_PASSWORD_RESET=off`` in your
|
||||
environment.
|
||||
|
||||
pretix settings
|
||||
---------------
|
||||
|
||||
@@ -55,19 +45,12 @@ Example::
|
||||
|
||||
``datadir``
|
||||
The local path to a data directory that will be used for storing user uploads and similar
|
||||
data. Defaults to the value of the environment variable ``DATA_DIR`` or ``data``.
|
||||
data. Defaults to thea value of the environment variable ``DATA_DIR`` or ``data``.
|
||||
|
||||
``plugins_default``
|
||||
A comma-separated list of plugins that are enabled by default for all new events.
|
||||
Defaults to ``pretix.plugins.sendmail,pretix.plugins.statistics``.
|
||||
|
||||
``plugins_exclude``
|
||||
A comma-separated list of plugins that are not available even though they are installed.
|
||||
Defaults to an empty string.
|
||||
|
||||
``auth_backends``
|
||||
A comma-separated list of available auth backends. Defaults to ``pretix.base.auth.NativeAuthBackend``.
|
||||
|
||||
``cookie_domain``
|
||||
The cookie domain to be set. Defaults to ``None``.
|
||||
|
||||
@@ -85,34 +68,6 @@ Example::
|
||||
that are used to print tax amounts in the customer currency on invoices for some currencies. Set to ``off`` to
|
||||
disable this feature. Defaults to ``on``.
|
||||
|
||||
``audit_comments``
|
||||
Enables or disables nagging staff users for leaving comments on their sessions for auditability.
|
||||
Defaults to ``off``.
|
||||
|
||||
``obligatory_2fa``
|
||||
Enables or disables obligatory usage of Two-Factor Authentication for users of the pretix backend.
|
||||
Defaults to ``False``
|
||||
|
||||
``trust_x_forwarded_for``
|
||||
Specifies whether the ``X-Forwarded-For`` header can be trusted. Only set to ``on`` if you have a reverse
|
||||
proxy that actively removes and re-adds the header to make sure the correct client IP is the first value.
|
||||
Defaults to ``off``.
|
||||
|
||||
``trust_x_forwarded_proto``
|
||||
Specifies whether the ``X-Forwarded-Proto`` header can be trusted. Only set to ``on`` if you have a reverse
|
||||
proxy that actively removes and re-adds the header to make sure the correct value is set.
|
||||
Defaults to ``off``.
|
||||
|
||||
``csp_log``
|
||||
Log violations of the Content Security Policy (CSP). Defaults to ``on``.
|
||||
|
||||
``csp_additional_header``
|
||||
Specifies a CSP header that will be **merged** with pretix's default header. For example, if you set this
|
||||
to ``script-src https://mycdn.com``, pretix will add ``https://mycdn.com`` as an **additional** allowed source
|
||||
to all CSP headers. Empty by default.
|
||||
|
||||
``loglevel``
|
||||
Set console and file log level (``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` or ``CRITICAL``). Defaults to ``INFO``.
|
||||
|
||||
Locale settings
|
||||
---------------
|
||||
@@ -160,27 +115,6 @@ Example::
|
||||
Indicates if the database backend is a MySQL/MariaDB Galera cluster and
|
||||
turns on some optimizations/special case handlers. Default: ``False``
|
||||
|
||||
.. _`config-replica`:
|
||||
|
||||
Database replica settings
|
||||
-------------------------
|
||||
|
||||
If you use a replicated database setup, pretix expects that the default database connection always points to the primary database node.
|
||||
Routing read queries to a replica on database layer is **strongly** discouraged since this can lead to inaccurate such as more tickets
|
||||
being sold than are actually available.
|
||||
|
||||
However, pretix can still make use of a database replica to keep some expensive queries with that can tolerate some latency from your
|
||||
primary database, such as backend search queries. The ``replica`` configuration section can have the same settings as the ``database``
|
||||
section (except for the ``backend`` setting) and will default back to the ``database`` settings for all values that are not given. This
|
||||
way, you just need to specify the settings that are different for the replica.
|
||||
|
||||
Example::
|
||||
|
||||
[replica]
|
||||
host=192.168.0.2
|
||||
|
||||
.. _`config-urls`:
|
||||
|
||||
URLs
|
||||
----
|
||||
|
||||
@@ -308,24 +242,6 @@ to speed up various operations::
|
||||
If redis is not configured, pretix will store sessions and locks in the database. If memcached
|
||||
is configured, memcached will be used for caching instead of redis.
|
||||
|
||||
Translations
|
||||
------------
|
||||
|
||||
pretix comes with a number of translations. Some of them are marked as "incubating", which means
|
||||
they can usually only be selected in development mode. If you want to use them nevertheless, you
|
||||
can activate them like this::
|
||||
|
||||
[languages]
|
||||
allow_incubating=pt-br,da
|
||||
|
||||
You can also tell pretix about additional paths where it will search for translations::
|
||||
|
||||
[languages]
|
||||
path=/path/to/my/translations
|
||||
|
||||
For a given language (e.g. ``pt-br``), pretix will then look in the
|
||||
specific sub-folder, e.g. ``/path/to/my/translations/pt_BR/LC_MESSAGES/django.po``.
|
||||
|
||||
Celery task queue
|
||||
-----------------
|
||||
|
||||
@@ -355,15 +271,6 @@ application. If you want to use sentry, you need to set a DSN in the configurati
|
||||
You will be given this value by your sentry installation.
|
||||
|
||||
|
||||
Caching
|
||||
-------
|
||||
|
||||
You can adjust some caching settings to control how much storage pretix uses::
|
||||
|
||||
[cache]
|
||||
tickets=48 ; Number of hours tickets (PDF, passbook, …) are cached
|
||||
|
||||
|
||||
Secret length
|
||||
-------------
|
||||
|
||||
@@ -378,13 +285,5 @@ various places like order codes, secrets in the ticket QR codes, etc. Example::
|
||||
; Voucher code needs to be < 255 characters, default is 16
|
||||
voucher_code=16
|
||||
|
||||
External tools
|
||||
--------------
|
||||
|
||||
pretix can make use of some external tools if they are installed. Currently, they are all optional. Example::
|
||||
|
||||
[tools]
|
||||
pdftk=/usr/bin/pdftk
|
||||
|
||||
.. _Python documentation: https://docs.python.org/3/library/configparser.html?highlight=configparser#supported-ini-file-structure
|
||||
.. _Celery documentation: http://docs.celeryproject.org/en/latest/userguide/configuration.html
|
||||
.. _Celery documentation: http://docs.celeryproject.org/en/latest/configuration.html
|
||||
|
||||
@@ -11,5 +11,3 @@ This documentation is for everyone who wants to install pretix on a server.
|
||||
installation/index
|
||||
config
|
||||
maintainance
|
||||
scaling
|
||||
indexes
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
Additional database indices
|
||||
===========================
|
||||
|
||||
If you have a large pretix database, some features such as search for orders or events might turn pretty slow.
|
||||
For PostgreSQL, we have compiled a list of additional database indexes that you can add to speed things up.
|
||||
Just like any index, they in turn make write operations insignificantly slower and cause the database to use
|
||||
more disk space.
|
||||
|
||||
The indexes aren't automatically created by pretix since Django does not allow us to do so only on PostgreSQL
|
||||
(and they won't work on other databases). Also, they're really not necessary if you're not having tens of
|
||||
thousands of records in your database.
|
||||
|
||||
However, this also means they won't automatically adapt if some of the referred fields change in future updates of pretix
|
||||
and you might need to re-check this page and change them manually.
|
||||
|
||||
Here is the currently recommended set of commands::
|
||||
|
||||
CREATE EXTENSION pg_trgm;
|
||||
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_event_slug
|
||||
ON pretixbase_event
|
||||
USING gin (upper("slug") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_event_name
|
||||
ON pretixbase_event
|
||||
USING gin (upper("name") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_order_code
|
||||
ON pretixbase_order
|
||||
USING gin (upper("code") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_voucher_code
|
||||
ON pretixbase_voucher
|
||||
USING gin (upper("code") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_invoice_nu1
|
||||
ON "pretixbase_invoice" (UPPER("invoice_no"));
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_invoice_nu2
|
||||
ON "pretixbase_invoice" (UPPER("full_invoice_no"));
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_organizer_name
|
||||
ON pretixbase_organizer
|
||||
USING gin (upper("name") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_organizer_slug
|
||||
ON pretixbase_organizer
|
||||
USING gin (upper("slug") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_order_email
|
||||
ON pretixbase_order
|
||||
USING gin (upper("email") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_order_comment
|
||||
ON pretixbase_order
|
||||
USING gin (upper("comment") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_orderpos_name
|
||||
ON pretixbase_orderposition
|
||||
USING gin (upper("attendee_name_cached") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_orderpos_scret
|
||||
ON pretixbase_orderposition
|
||||
USING gin (upper("secret") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_orderpos_email
|
||||
ON pretixbase_orderposition
|
||||
USING gin (upper("attendee_email") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_ia_name
|
||||
ON pretixbase_invoiceaddress
|
||||
USING gin (upper("name_cached") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_ia_company
|
||||
ON pretixbase_invoiceaddress
|
||||
USING gin (upper("company") gin_trgm_ops);
|
||||
|
||||
|
||||
Also, if you use our ``pretix-shipping`` plugin::
|
||||
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_sa_name
|
||||
ON pretix_shipping_shippingaddress
|
||||
USING gin (upper("name") gin_trgm_ops);
|
||||
CREATE INDEX CONCURRENTLY pretix_addidx_sa_company
|
||||
ON pretix_shipping_shippingaddress
|
||||
USING gin (upper("company") gin_trgm_ops);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
.. highlight:: none
|
||||
|
||||
Installing a development version
|
||||
================================
|
||||
|
||||
If you want to use a feature of pretix that is not yet contained in the last monthly release, you can also
|
||||
install a development version with pretix.
|
||||
|
||||
.. warning:: When in production, we strongly recommend only installing released versions. Development versions might
|
||||
be broken, incompatible to plugins, or in rare cases incompatible to upgrade later on.
|
||||
|
||||
|
||||
Manual installation
|
||||
-------------------
|
||||
|
||||
You can use ``pip`` to update pretix directly to the development branch. Then, upgrade as usual::
|
||||
|
||||
$ source /var/pretix/venv/bin/activate
|
||||
(venv)$ pip3 install -U "git+https://github.com/pretix/pretix.git#egg=pretix&subdirectory=src"
|
||||
(venv)$ python -m pretix migrate
|
||||
(venv)$ python -m pretix rebuild
|
||||
(venv)$ python -m pretix updatestyles
|
||||
# systemctl restart pretix-web pretix-worker
|
||||
|
||||
Docker installation
|
||||
-------------------
|
||||
|
||||
To use the latest development version with Docker, first pull it from Docker Hub::
|
||||
|
||||
$ docker pull pretix/standalone:latest
|
||||
|
||||
|
||||
Then change your ``/etc/systemd/system/pretix.service`` file to use the ``:latest`` tag instead of ``:stable`` as well
|
||||
and upgrade as usual::
|
||||
|
||||
$ systemctl restart pretix.service
|
||||
$ docker exec -it pretix.service pretix upgrade
|
||||
@@ -26,7 +26,7 @@ installation guides):
|
||||
* `Docker`_
|
||||
* A SMTP server to send out mails, e.g. `Postfix`_ on your machine or some third-party server you have credentials for
|
||||
* A HTTP reverse proxy, e.g. `nginx`_ or Apache to allow HTTPS connections
|
||||
* A `PostgreSQL`_ 9.5+, `MySQL`_ 5.7+, or MariaDB 10.2.7+ database server
|
||||
* A `MySQL`_ or `PostgreSQL`_ database server
|
||||
* A `redis`_ server
|
||||
|
||||
We also recommend that you use a firewall, although this is not a pretix-specific recommendation. If you're new to
|
||||
@@ -36,9 +36,6 @@ Linux and firewalls, we recommend that you start with `ufw`_.
|
||||
SSL certificates can be obtained for free these days. We also *do not* provide support for HTTP-only
|
||||
installations except for evaluation purposes.
|
||||
|
||||
.. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or
|
||||
**MariaDB 10.2.7 or newer**.
|
||||
|
||||
On this guide
|
||||
-------------
|
||||
|
||||
@@ -58,29 +55,16 @@ Database
|
||||
--------
|
||||
|
||||
Next, we need a database and a database user. We can create these with any kind of database managing tool or directly on
|
||||
our database's shell. For PostgreSQL, we would do::
|
||||
our database's shell, e.g. for MySQL::
|
||||
|
||||
# sudo -u postgres createuser -P pretix
|
||||
# sudo -u postgres createdb -O pretix pretix
|
||||
$ mysql -u root -p
|
||||
mysql> CREATE DATABASE pretix DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
|
||||
mysql> GRANT ALL PRIVILEGES ON pretix.* TO pretix@'localhost' IDENTIFIED BY '*********';
|
||||
mysql> FLUSH PRIVILEGES;
|
||||
|
||||
Make sure that your database listens on the network. If PostgreSQL on the same same host as docker, but not inside a docker container, we recommend that you just listen on the Docker interface by changing the following line in ``/etc/postgresql/<version>/main/postgresql.conf``::
|
||||
|
||||
listen_addresses = 'localhost,172.17.0.1'
|
||||
|
||||
You also need to add a new line to ``/etc/postgresql/<version>/main/pg_hba.conf`` to allow network connections to this user and database::
|
||||
|
||||
host pretix pretix 172.17.0.1/16 md5
|
||||
|
||||
Restart PostgreSQL after you changed these files::
|
||||
|
||||
# systemctl restart postgresql
|
||||
|
||||
If you have a firewall running, you should also make sure that port 5432 is reachable from the ``172.17.0.1/16`` subnet.
|
||||
|
||||
For MySQL, you can either also use network-based connections or mount the ``/var/run/mysqld/mysqld.sock`` socket into the docker container.
|
||||
When using MySQL, make sure you set the character set of the database to ``utf8mb4``, e.g. like this::
|
||||
|
||||
mysql > CREATE DATABASE pretix DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
|
||||
Replace the asterisks with a password of your own. For MySQL, we will use a unix domain socket to connect to the
|
||||
database. For PostgreSQL, be sure to configure the interface binding and your firewall so that the docker container
|
||||
can reach PostgreSQL.
|
||||
|
||||
Redis
|
||||
-----
|
||||
@@ -125,20 +109,15 @@ Fill the configuration file ``/etc/pretix/pretix.cfg`` with the following conten
|
||||
; DO NOT change the following value, it has to be set to the location of the
|
||||
; directory *inside* the docker container
|
||||
datadir=/data
|
||||
trust_x_forwarded_for=on
|
||||
trust_x_forwarded_proto=on
|
||||
|
||||
[database]
|
||||
; Replace postgresql with mysql for MySQL
|
||||
backend=postgresql
|
||||
; Replace mysql with postgresql_psycopg2 for PostgreSQL
|
||||
backend=mysql
|
||||
name=pretix
|
||||
user=pretix
|
||||
; Replace with the password you chose above
|
||||
password=*********
|
||||
; In most docker setups, 172.17.0.1 is the address of the docker host. Adjust
|
||||
; this to wherever your database is running, e.g. the name of a linked container
|
||||
; or of a mounted MySQL socket.
|
||||
host=172.17.0.1
|
||||
; Replace with host IP address for PostgreSQL
|
||||
host=/var/run/mysqld/mysqld.sock
|
||||
|
||||
[mail]
|
||||
; See config file documentation for more options
|
||||
@@ -182,16 +161,14 @@ named ``/etc/systemd/system/pretix.service`` with the following content::
|
||||
-v /var/pretix-data:/data \
|
||||
-v /etc/pretix:/etc/pretix \
|
||||
-v /var/run/redis:/var/run/redis \
|
||||
--sysctl net.core.somaxconn=4096 \
|
||||
-v /var/run/mysqld:/var/run/mysqld \
|
||||
pretix/standalone:stable all
|
||||
ExecStop=/usr/bin/docker stop %n
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
When using MySQL and socket mounting, you'll need the additional flag ``-v /var/run/mysqld:/var/run/mysqld`` in the command.
|
||||
|
||||
You can now run the following commands
|
||||
You can leave the MySQL socket volume out if you're using PostgreSQL. You can now run the following commands
|
||||
to enable and start the service::
|
||||
|
||||
# systemctl daemon-reload
|
||||
@@ -279,40 +256,20 @@ choice)::
|
||||
|
||||
Then, go to that directory and build the image::
|
||||
|
||||
$ docker build . -t mypretix
|
||||
$ docker build -t mypretix
|
||||
|
||||
You can now use that image ``mypretix`` instead of ``pretix/standalone`` in your service file (see above). Be sure
|
||||
to re-build your custom image after you pulled ``pretix/standalone`` if you want to perform an update.
|
||||
|
||||
Scaling up
|
||||
----------
|
||||
|
||||
If you need to scale to multiple machines, please first read our :ref:`scaling guide <scaling>`.
|
||||
|
||||
If you run the official docker container on multiple machines, it is recommended to set the environment
|
||||
variable ``AUTOMIGRATE=skip`` on all containers and run ``docker exec -it pretix.service pretix migrate``
|
||||
on one machine after each upgrade manually, otherwise multiple containers might try to upgrade the
|
||||
database schema at the same time.
|
||||
|
||||
To run only the ``pretix-web`` component of pretix as well as a nginx server serving static files, you
|
||||
can invoke the container with ``docker run … pretix/standalone:stable web`` (instead of ``all``). You
|
||||
can adjust the number of ``gunicorn`` processes with the ``NUM_WORKERS`` environment variable (defaults to
|
||||
two times the number of CPUs detected).
|
||||
|
||||
To run only ``pretix-worker``, you can run ``docker run … pretix/standalone:stable taskworker``. You can
|
||||
also pass arguments to limit the worker to specific queues or to change the number of concurrent task
|
||||
workers, e.g. ``docker run … taskworker -Q notifications --concurrency 32``.
|
||||
|
||||
|
||||
.. _Docker: https://docs.docker.com/engine/installation/linux/debian/
|
||||
.. _Postfix: https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-16-04
|
||||
.. _nginx: https://botleg.com/stories/https-with-lets-encrypt-and-nginx/
|
||||
.. _Let's Encrypt: https://letsencrypt.org/
|
||||
.. _pretix.eu: https://pretix.eu/
|
||||
.. _MySQL: https://dev.mysql.com/doc/refman/5.7/en/linux-installation-apt-repo.html
|
||||
.. _PostgreSQL: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-20-04
|
||||
.. _redis: https://blog.programster.org/debian-8-install-redis-server/
|
||||
.. _PostgreSQL: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-9-4-on-debian-8
|
||||
.. _redis: http://blog.programster.org/debian-8-install-redis-server/
|
||||
.. _ufw: https://en.wikipedia.org/wiki/Uncomplicated_Firewall
|
||||
.. _redis website: https://redis.io/topics/security
|
||||
.. _redis website: http://redis.io/topics/security
|
||||
.. _redis in docker: https://hub.docker.com/r/_/redis/
|
||||
.. _strong encryption settings: https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
.. highlight:: none
|
||||
|
||||
Installing pretix Enterprise plugins
|
||||
====================================
|
||||
|
||||
If you want to use a feature of pretix that is part of our commercial offering pretix Enterprise, you need to follow
|
||||
some extra steps. Installation works similar to normal pretix plugins, but involves a few extra steps.
|
||||
|
||||
Buying the license
|
||||
------------------
|
||||
|
||||
To obtain a license, please get in touch at sales@pretix.eu. Please let us know how many tickets you roughly intend
|
||||
to sell per year and how many servers you want to use the plugin on. We recommend having a look at our `price list`_
|
||||
first.
|
||||
|
||||
|
||||
Manual installation
|
||||
-------------------
|
||||
|
||||
First, generate an SSH key for the system user that you install pretix as. In our tutorial, that would be the user
|
||||
``pretix``. Choose an empty passphrase::
|
||||
|
||||
# su pretix
|
||||
$ ssh-keygen
|
||||
Generating public/private rsa key pair.
|
||||
Enter file in which to save the key (/var/pretix/.ssh/id_rsa):
|
||||
Enter passphrase (empty for no passphrase):
|
||||
Enter same passphrase again:
|
||||
Your identification has been saved in /var/pretix/.ssh/id_rsa.
|
||||
Your public key has been saved in /var/pretix/.ssh/id_rsa.pub.
|
||||
|
||||
Next, send the content of the *public* key to your sales representative at pretix::
|
||||
|
||||
$ cat /var/pretix/.ssh/id_rsa.pub
|
||||
ssh-rsa AAAAB3N...744HZawHlD pretix@foo
|
||||
|
||||
After we configured your key in our system, you can install the plugin directly using ``pip`` from the URL we told
|
||||
you, for example::
|
||||
|
||||
$ source /var/pretix/venv/bin/activate
|
||||
(venv)$ pip3 install -U "git+ssh://git@code.rami.io:10022/pretix/pretix-slack.git@stable#egg=pretix-slack"
|
||||
(venv)$ python -m pretix migrate
|
||||
(venv)$ python -m pretix rebuild
|
||||
# systemctl restart pretix-web pretix-worker
|
||||
|
||||
Docker installation
|
||||
-------------------
|
||||
|
||||
To install a plugin, you need to build your own docker image. To do so, create a new directory to work in. As a first
|
||||
step, generate a new SSH key in that directory to use for authentication with us::
|
||||
|
||||
$ cd /home/me/mypretixdocker
|
||||
$ ssh-keygen -N "" -f id_pretix_enterprise
|
||||
|
||||
Next, send the content of the *public* key to your sales representative at pretix::
|
||||
|
||||
$ cat id_pretix_enterprise.pub
|
||||
ssh-rsa AAAAB3N...744HZawHlD pretix@foo
|
||||
|
||||
After we configured your key in our system, you can add a ``Dockerfile`` in your directory that includes the newly
|
||||
generated key and installs the plugin from the URL we told you::
|
||||
|
||||
FROM pretix/standalone:stable
|
||||
USER root
|
||||
COPY id_pretix_enterprise /root/.ssh/id_rsa
|
||||
COPY id_pretix_enterprise.pub /root/.ssh/id_rsa.pub
|
||||
RUN chmod -R 0600 /root/.ssh && \
|
||||
mkdir -p /etc/ssh && \
|
||||
ssh-keyscan -t rsa -p 10022 code.rami.io >> /root/.ssh/known_hosts && \
|
||||
echo StrictHostKeyChecking=no >> /root/.ssh/config && \
|
||||
DJANGO_SETTINGS_MODULE=pretix.settings pip3 install -U "git+ssh://git@code.rami.io:10022/pretix/pretix-slack.git@stable#egg=pretix-slack" && \
|
||||
cd /pretix/src && \
|
||||
sudo -u pretixuser make production
|
||||
USER pretixuser
|
||||
|
||||
Then, build the image for docker::
|
||||
|
||||
$ docker build -t mypretix
|
||||
|
||||
You can now use that image ``mypretix`` instead of ``pretix/standalone:stable`` in your ``/etc/systemd/system/pretix.service``
|
||||
service file. Be sure to re-build your custom image after you pulled ``pretix/standalone`` if you want to perform an
|
||||
update to a new version of pretix.
|
||||
|
||||
.. _price list: https://pretix.eu/about/en/pricing
|
||||
@@ -1,7 +1,5 @@
|
||||
.. highlight:: ini
|
||||
|
||||
.. spelling:: SQL
|
||||
|
||||
General remarks
|
||||
===============
|
||||
|
||||
@@ -21,9 +19,6 @@ To use pretix, you will need the following things:
|
||||
|
||||
.. warning:: Do not ever use SQLite in production. It will break.
|
||||
|
||||
.. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or
|
||||
**MariaDB 10.2.7 or newer**.
|
||||
|
||||
* A **reverse proxy**. pretix needs to deliver some static content to your users (e.g. CSS, images, ...). While pretix
|
||||
is capable of doing this, having this handled by a proper web server like **nginx** or **Apache** will be much
|
||||
faster. Also, you need a proxying web server in front to provide SSL encryption.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
.. _`installation`:
|
||||
|
||||
Installation guide
|
||||
==================
|
||||
|
||||
@@ -12,5 +10,3 @@ for your needs.
|
||||
general
|
||||
docker_smallscale
|
||||
manual_smallscale
|
||||
dev_version
|
||||
enterprise
|
||||
|
||||
@@ -12,7 +12,7 @@ solution with many things readily set-up, look at :ref:`dockersmallscale`.
|
||||
get it right. If you're not feeling comfortable managing a Linux server, check out our hosting and service
|
||||
offers at `pretix.eu`_.
|
||||
|
||||
We tested this guide on the Linux distribution **Debian 10.0** but it should work very similar on other
|
||||
We tested this guide on the Linux distribution **Debian 8.0** but it should work very similar on other
|
||||
modern distributions, especially on all systemd-based ones.
|
||||
|
||||
Requirements
|
||||
@@ -23,7 +23,7 @@ installation guides):
|
||||
|
||||
* A SMTP server to send out mails, e.g. `Postfix`_ on your machine or some third-party server you have credentials for
|
||||
* A HTTP reverse proxy, e.g. `nginx`_ or Apache to allow HTTPS connections
|
||||
* A `PostgreSQL`_ 9.5+, `MySQL`_ 5.7+, or MariaDB 10.2.7+ database server
|
||||
* A `MySQL`_ or `PostgreSQL`_ database server
|
||||
* A `redis`_ server
|
||||
|
||||
We also recommend that you use a firewall, although this is not a pretix-specific recommendation. If you're new to
|
||||
@@ -33,9 +33,6 @@ Linux and firewalls, we recommend that you start with `ufw`_.
|
||||
SSL certificates can be obtained for free these days. We also *do not* provide support for HTTP-only
|
||||
installations except for evaluation purposes.
|
||||
|
||||
.. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or
|
||||
**MariaDB 10.2.7 or newer**.
|
||||
|
||||
Unix user
|
||||
---------
|
||||
|
||||
@@ -50,23 +47,21 @@ Database
|
||||
--------
|
||||
|
||||
Having the database server installed, we still need a database and a database user. We can create these with any kind
|
||||
of database managing tool or directly on our database's shell. For PostgreSQL, we would do::
|
||||
of database managing tool or directly on our database's shell, e.g. for MySQL::
|
||||
|
||||
# sudo -u postgres createuser pretix
|
||||
# sudo -u postgres createdb -O pretix pretix
|
||||
|
||||
When using MySQL, make sure you set the character set of the database to ``utf8mb4``, e.g. like this::
|
||||
|
||||
mysql > CREATE DATABASE pretix DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
|
||||
$ mysql -u root -p
|
||||
mysql> CREATE DATABASE pretix DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
|
||||
mysql> GRANT ALL PRIVILEGES ON pretix.* TO pretix@'localhost' IDENTIFIED BY '*********';
|
||||
mysql> FLUSH PRIVILEGES;
|
||||
|
||||
Package dependencies
|
||||
--------------------
|
||||
|
||||
To build and run pretix, you will need the following debian packages::
|
||||
|
||||
# apt-get install git build-essential python-dev python3-venv python3 python3-pip \
|
||||
# apt-get install git build-essential python-dev python-virtualenv python3 python3-pip \
|
||||
python3-dev libxml2-dev libxslt1-dev libffi-dev zlib1g-dev libssl-dev \
|
||||
gettext libpq-dev libmariadbclient-dev libjpeg-dev libopenjp2-7-dev
|
||||
gettext libpq-dev libmysqlclient-dev libjpeg-dev
|
||||
|
||||
Config file
|
||||
-----------
|
||||
@@ -85,22 +80,15 @@ Fill the configuration file ``/etc/pretix/pretix.cfg`` with the following conten
|
||||
url=https://pretix.mydomain.com
|
||||
currency=EUR
|
||||
datadir=/var/pretix/data
|
||||
trust_x_forwarded_for=on
|
||||
trust_x_forwarded_proto=on
|
||||
|
||||
[database]
|
||||
; For MySQL, replace with "mysql"
|
||||
backend=postgresql
|
||||
; Replace mysql with postgresql_psycopg2 for PostgreSQL
|
||||
backend=mysql
|
||||
name=pretix
|
||||
user=pretix
|
||||
; For MySQL, enter the user password. For PostgreSQL on the same host,
|
||||
; we don't need one because we can use peer authentification if our
|
||||
; PostgreSQL user matches our unix user.
|
||||
password=
|
||||
; For MySQL, use local socket, e.g. /var/run/mysqld/mysqld.sock
|
||||
; For a remote host, supply an IP address
|
||||
; For local postgres authentication, you can leave it empty
|
||||
host=
|
||||
password=*********
|
||||
; Replace with host IP address for PostgreSQL
|
||||
host=/var/run/mysqld/mysqld.sock
|
||||
|
||||
[mail]
|
||||
; See config file documentation for more options
|
||||
@@ -124,16 +112,17 @@ Now we will install pretix itself. The following steps are to be executed as the
|
||||
actually install pretix, we will create a virtual environment to isolate the python packages from your global
|
||||
python installation::
|
||||
|
||||
$ python3 -m venv /var/pretix/venv
|
||||
$ virtualenv -p python3 /var/pretix/venv
|
||||
$ source /var/pretix/venv/bin/activate
|
||||
(venv)$ pip3 install -U pip setuptools wheel
|
||||
|
||||
We now install pretix, its direct dependencies and gunicorn. Replace ``postgres`` with ``mysql`` in the following
|
||||
command if you're running MySQL::
|
||||
We now install pretix, its direct dependencies and gunicorn. Replace ``mysql`` with ``postgres`` in the following
|
||||
command if you're running PostgreSQL::
|
||||
|
||||
(venv)$ pip3 install "pretix[postgres]" gunicorn
|
||||
(venv)$ pip3 install "pretix[mysql]" gunicorn
|
||||
|
||||
Note that you need Python 3.6 or newer. You can find out your Python version using ``python -V``.
|
||||
If you are running Python 3.4, you also need to ``pip3 install typing``. This is not required on 3.5 or newer.
|
||||
You can find out your Python version using ``python -V``.
|
||||
|
||||
We also need to create a data directory::
|
||||
|
||||
@@ -277,10 +266,10 @@ Updates
|
||||
.. warning:: While we try hard not to break things, **please perform a backup before every upgrade**.
|
||||
|
||||
To upgrade to a new pretix release, pull the latest code changes and run the following commands (again, replace
|
||||
``postgres`` with ``mysql`` if necessary)::
|
||||
``mysql`` with ``postgres`` if necessary)::
|
||||
|
||||
$ source /var/pretix/venv/bin/activate
|
||||
(venv)$ pip3 install -U pretix[postgres] gunicorn
|
||||
(venv)$ pip3 install -U pretix[mysql] gunicorn
|
||||
(venv)$ python -m pretix migrate
|
||||
(venv)$ python -m pretix rebuild
|
||||
(venv)$ python -m pretix updatestyles
|
||||
@@ -308,7 +297,7 @@ example::
|
||||
.. _Let's Encrypt: https://letsencrypt.org/
|
||||
.. _pretix.eu: https://pretix.eu/
|
||||
.. _MySQL: https://dev.mysql.com/doc/refman/5.7/en/linux-installation-apt-repo.html
|
||||
.. _PostgreSQL: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-20-04
|
||||
.. _redis: https://blog.programster.org/debian-8-install-redis-server/
|
||||
.. _PostgreSQL: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-9-4-on-debian-8
|
||||
.. _redis: http://blog.programster.org/debian-8-install-redis-server/
|
||||
.. _ufw: https://en.wikipedia.org/wiki/Uncomplicated_Firewall
|
||||
.. _strong encryption settings: https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
||||
|
||||
@@ -92,8 +92,7 @@ pretix_task_duration_seconds
|
||||
|
||||
pretix_model_instances
|
||||
Gauge. Measures number of instances of a certain model within the database, labeled with
|
||||
the ``model`` name. Starting with pretix 3.11, these numbers might only be approximate for
|
||||
most tables when running on PostgreSQL to mitigate performance impact.
|
||||
the ``model`` name.
|
||||
|
||||
.. _metric types: https://prometheus.io/docs/concepts/metric_types/
|
||||
.. _Prometheus: https://prometheus.io/
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
.. _`scaling`:
|
||||
|
||||
Scaling guide
|
||||
=============
|
||||
|
||||
Our :ref:`installation guide <installation>` only covers "small-scale" setups, by which we mostly mean
|
||||
setups that run on a **single (virtual) machine** and do not encounter large traffic peaks.
|
||||
|
||||
We do not offer an installation guide for larger-scale setups of pretix, mostly because we believe that
|
||||
there is no one-size-fits-all solution for this and the desired setup highly depends on your use case,
|
||||
the platform you run pretix on, and your technical capabilities. We do not recommend trying set up pretix
|
||||
in a multi-server environment if you do not already have experience with managing server clusters.
|
||||
|
||||
This document is intended to give you a general idea on what issues you will encounter when you scale up
|
||||
and what you should think of.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you require more help on this, we're happy to help. Our pretix Enterprise support team has built
|
||||
and helped building, scaling and load-testing pretix installations at any scale and we're looking
|
||||
forward to work with you on fine-tuning your system. If you intend to sell **more than a thousand
|
||||
tickets in a very short amount of time**, we highly recommend reaching out and at least talking this
|
||||
through. Just get in touch at sales@pretix.eu!
|
||||
|
||||
Scaling reasons
|
||||
---------------
|
||||
|
||||
There's mainly two reasons to scale up a pretix installation beyond a single server:
|
||||
|
||||
* **Availability:** Distributing pretix over multiple servers can allow you to survive failure of one or more single machines, leading to a higher uptime and reliability of your system.
|
||||
|
||||
* **Traffic and throughput:** Distributing pretix over multiple servers can allow you to process more web requests and ticket sales at the same time.
|
||||
|
||||
You are very unlikely to require scaling for other reasons, such as having too much data in your database.
|
||||
|
||||
Components
|
||||
----------
|
||||
|
||||
A pretix installation usually consists of the following components which run performance-relevant processes:
|
||||
|
||||
* ``pretix-web`` is the Django-based web application that serves all user interaction.
|
||||
|
||||
* ``pretix-worker`` is a Celery-based application that processes tasks that should be run asynchronously outside of the web application process.
|
||||
|
||||
* A **SQL database** keeps all the important data and processes the actual transactions. We recommend using PostgreSQL, but MySQL/MariaDB works as well.
|
||||
|
||||
* A **web server** that terminates TLS and HTTP connections and forwards them to ``pretix-web``. In some cases, e.g. when serving static files, the web servers might return a response directly. We recommend using ``nginx``.
|
||||
|
||||
* A **redis** server responsible for the communication between ``pretix-web`` and ``pretix-worker``, as well as for caching.
|
||||
|
||||
* A directory of **media files** such as user-uploaded files or generated files (tickets, invoices, …) that are created and used by ``pretix-web``, ``pretix-worker`` and the web server.
|
||||
|
||||
In the following, we will discuss the scaling behavior of every component individually. In general, you can run all of the components
|
||||
on the same server, but you can just as well distribute every component to its own server, or even use multiple servers for some single
|
||||
components.
|
||||
|
||||
.. warning::
|
||||
|
||||
When setting up your system, don't forget about security. In a multi-server environment,
|
||||
you need to take special care to ensure that no unauthorized access to your database
|
||||
is possible through the network and that it's not easy to wiretap your connections. We
|
||||
recommend a rigorous use of firewalls and encryption on all communications. You can
|
||||
ensure this either on an application level (such as using the TLS support in your
|
||||
database) or on a network level with a VPN solution.
|
||||
|
||||
Web server
|
||||
""""""""""
|
||||
|
||||
Your web server is at the very front of your installation. It will need to absorb all of the traffic, and it should be able to
|
||||
at least show a decent error message, even when everything else fails. Luckily, web servers are really fast these days, so this
|
||||
can be achieved without too much work.
|
||||
|
||||
We recommend reading up on tuning your web server for high concurrency. For nginx, this means thinking about the number of worker
|
||||
processes and the number of connections each worker process accepts. Double-check that TLS session caching works, because TLS
|
||||
handshakes can get really expensive.
|
||||
|
||||
During a traffic peak, your web server will be able to make us of more CPU resources, while memory usage will stay comparatively low,
|
||||
so if you invest in more hardware here, invest in more and faster CPU cores.
|
||||
|
||||
Make sure that pretix' static files (such as CSS and JavaScript assets) as well as user-uploaded media files (event logos, etc)
|
||||
are served directly by your web server and your web server caches them in-memory (nginx does it by default) and sets useful
|
||||
headers for client-side caching. As an additional performance improvement, you can turn of access logging for these types of files.
|
||||
If you want, you can even farm out serving static files to a different web server entirely and :ref:`configure pretix to reference
|
||||
them from a different URL <config-urls>`.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you expect *really high traffic* for your very popular event, you might want to do some rate limiting on this layer, or,
|
||||
if you want to ensure a fair and robust first-come-first-served experience and prefer letting users wait over showing them
|
||||
errors, consider a queuing solution. We're happy to provide you with such systems, just get in touch at sales@pretix.eu.
|
||||
|
||||
pretix-web
|
||||
""""""""""
|
||||
|
||||
The ``pretix-web`` process does not carry any internal state can be easily started on as many machines as you like, and you can
|
||||
use the load balancing features of your frontend web server to redirect to all of them.
|
||||
|
||||
You can adjust the number of processes in the ``gunicorn`` command line, and we recommend choosing roughly two times the number
|
||||
of CPU cores available. Under load, the memory consumption of ``pretix-web`` will stay comparatively constant, while the CPU usage
|
||||
will increase a lot. Therefore, if you can add more or faster CPU cores, you will be able to serve more users.
|
||||
|
||||
pretix-worker
|
||||
"""""""""""""
|
||||
|
||||
The ``pretix-worker`` process performs all operations that are not directly executed in the request-response-cycle of ``pretix-web``.
|
||||
Just like ``pretix-web`` you can easily start up as many instances as you want on different machines to share the work. As long as they
|
||||
all talk to the same redis server, they will all receive tasks from ``pretix-web``, work on them and post their result back.
|
||||
You can configure the number of threads that run tasks in parallel through the ``--concurrency`` command line option of ``celery``.
|
||||
|
||||
Just like ``pretix-web``, this process is mostly heavy on CPU, disk IO and network IO, although memory peaks can occur e.g. during the
|
||||
generation of large PDF files, so we recommend having some reserves here.
|
||||
|
||||
``pretix-worker`` performs a variety of tasks which are of different importance.
|
||||
Some of them are mission-critical and need to be run quickly even during high load (such as
|
||||
creating a cart or an order), others are irrelevant and can easily run later (such as
|
||||
distributing tickets on the waiting list). You can fine-tune the capacity you assign to each
|
||||
of these tasks by running ``pretix-worker`` processes that only work on a specific **queue**.
|
||||
For example, you could have three servers dedicated only to process order creations and one
|
||||
server dedicated only to sending emails. This allows you to set priorities and also protects
|
||||
you from e.g. a slow email server lowering your ticket throughput.
|
||||
|
||||
You can do so by specifying one or more queues on the ``celery`` command line of this process, such as ``celery -A pretix.celery_app worker -Q notifications,mail``. Currently,
|
||||
the following queues exist:
|
||||
|
||||
* ``checkout`` -- This queue handles everything related to carts and orders and thereby everything required to process a sale. This includes adding and deleting items from carts as well as creating and canceling orders.
|
||||
|
||||
* ``mail`` -- This queue handles sending of outgoing emails.
|
||||
|
||||
* ``notifications`` -- This queue handles the processing of any outgoing notifications, such as email notifications to admin users (except for the actual sending) or API notifications to registered webhooks.
|
||||
|
||||
* ``background`` -- This queue handles tasks that are expected to take long or have no human waiting for their result immediately, such as refreshing caches, re-generating CSS files, assigning tickets on the waiting list or parsing bank data files.
|
||||
|
||||
* ``default`` -- This queue handles everything else with "medium" or unassigned priority, most prominently the generation of files for tickets, invoices, badges, admin exports, etc.
|
||||
|
||||
Media files
|
||||
"""""""""""
|
||||
|
||||
Both ``pretix-web``, ``pretix-worker`` and in some cases your webserver need to work with
|
||||
media files. Media files are all files generated *at runtime* by the software. This can
|
||||
include files uploaded by the event organizers, such as the event logo, files uploaded by
|
||||
ticket buyers (if you use such features) or files generated by the software, such as
|
||||
ticket files, invoice PDFs, data exports or customized CSS files.
|
||||
|
||||
Those files are by default stored to the ``media/`` sub-folder of the data directory given
|
||||
in the ``pretix.cfg`` configuration file. Inside that ``media/`` folder, you will find a
|
||||
``pub/`` folder containing the subset of files that should be publicly accessible through
|
||||
the web server. Everything else only needs to be accessible by ``pretix-web`` and
|
||||
``pretix-worker`` themselves.
|
||||
|
||||
If you distribute ``pretix-web`` or ``pretix-worker`` across more than one machine, you
|
||||
**must** make sure that they all have access to a shared storage to read and write these
|
||||
files, otherwise you **will** run into errors with the user interface.
|
||||
|
||||
The easiest solution for this is probably to store them on a NFS server that you mount
|
||||
on each of the other servers.
|
||||
|
||||
Since we use Django's file storage mechanism internally, you can in theory also use a object-storage solution like Amazon S3, Ceph, or Minio to store these files, although we currently do not expose this through pretix' configuration file and this would require you to ship your own variant of ``pretix/settings.py`` and reference it through the ``DJANGO_SETTINGS_MODULE`` environment variable.
|
||||
|
||||
At pretix.eu, we use a custom-built `object storage cluster`_.
|
||||
|
||||
SQL database
|
||||
""""""""""""
|
||||
|
||||
One of the most critical parts of the whole setup is the SQL database -- and certainly the
|
||||
hardest to scale. Tuning relational databases is an art form, and while there's lots of
|
||||
material on it on the internet, there's not a single recipe that you can apply to every case.
|
||||
|
||||
As a general rule of thumb, the more resources you can give your databases, the better.
|
||||
Most databases will happily use all CPU cores available, but only use memory up to an amount
|
||||
you configure, so make sure to set this memory usage as high as you can afford. Having more
|
||||
memory available allows your database to make more use of caching, which is usually good.
|
||||
|
||||
Scaling your database to multiple machines needs to be treated with great caution. It's a
|
||||
good to have a replica of your database for availability reasons. In case your primary
|
||||
database server fails, you can easily switch over to the replica and continue working.
|
||||
|
||||
However, using database replicas for performance gains is much more complicated. When using
|
||||
replicated database systems, you are always trading in consistency or availability to get
|
||||
additional performance and the consequences of this can be subtle and it is important
|
||||
that you have a deep understanding of the semantics of your replication mechanism.
|
||||
|
||||
.. warning::
|
||||
|
||||
Using an off-the-shelf database proxy solution that redirects read queries to your
|
||||
replicas and write queries to your primary database **will lead to very nasty bugs.**
|
||||
|
||||
As an example, if you buy a ticket, pretix first needs to calculate how many tickets
|
||||
are left to sell. If this calculation is done on a database replica that lags behind
|
||||
even for fractions of a second, the decision to allow selling the ticket will be made
|
||||
on out-of-data data and you can end up with more tickets sold than configured. Similarly,
|
||||
you could imagine situations leading to double payments etc.
|
||||
|
||||
If you do have a replica, you *can* tell pretix about it :ref:`in your configuration <config-replica>`.
|
||||
This way, pretix can offload complex read-only queries to the replica when it is safe to do so.
|
||||
As of pretix 2.7, this is mainly used for search queries in the backend and for rendering the
|
||||
product list and event lists in the frontend, but we plan on expanding this in the future.
|
||||
|
||||
Therefore, for now our clear recommendation is: Try to scale your database vertically and put
|
||||
it on the most powerful machine you have available.
|
||||
|
||||
redis
|
||||
"""""
|
||||
|
||||
While redis is a very important part that glues together some of the components, it isn't used
|
||||
heavily and can usually handle a fairly large pretix installation easily on a single modern
|
||||
CPU core.
|
||||
Having some memory available is good in case of e.g. lots of tasks queuing up during a traffic peak, but we wouldn't expect ever needing more than a gigabyte of it.
|
||||
|
||||
Feel free to set up a redis cluster for availability – but you won't need it for performance in a long time.
|
||||
|
||||
The limitations
|
||||
---------------
|
||||
|
||||
Up to a certain point, pretix scales really well. However, there are a few things that we consider
|
||||
even more important than scalability, and those are correctness and reliability. We want you to be
|
||||
able to trust that pretix will not sell more tickets than you intended or run into similar error
|
||||
cases.
|
||||
|
||||
Combined with pretix' flexibility and complexity, especially around vouchers and quotas, this creates
|
||||
some hard issues. In many cases, we need to fall back to event-global locking for some actions which
|
||||
are likely to run with high concurrency and cause harm.
|
||||
|
||||
For every event, only one of these locking actions can be run at the same time. Examples for this are
|
||||
adding products limited by a quota to a cart, adding items to a cart using a voucher or placing an order
|
||||
consisting of cart positions that don't have a valid reservation for much longer. In these cases, it is
|
||||
currently not realistically possible to exceed selling **approx. 500 orders per minute per event**, even
|
||||
if you add more hardware.
|
||||
If you have an unlimited number of tickets, we can apply fewer locking and we've reached **approx.
|
||||
1500 orders per minute per event** in benchmarks, although even more should be possible.
|
||||
|
||||
We're working to reduce the number of cases in which this is relevant and thereby improve the possible
|
||||
throughput. If you want to use pretix for an event with 10,000+ tickets that are likely to be sold out
|
||||
within minutes, please get in touch to discuss possible solutions. We'll work something out for you!
|
||||
|
||||
|
||||
.. _object storage cluster: https://behind.pretix.eu/2018/03/20/high-available-cdn/
|
||||
@@ -1,9 +0,0 @@
|
||||
Authentication
|
||||
==============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
tokenauth
|
||||
oauth
|
||||
deviceauth
|
||||
@@ -1,196 +0,0 @@
|
||||
.. _`rest-deviceauth`:
|
||||
|
||||
Device authentication
|
||||
=====================
|
||||
|
||||
Initializing a new device
|
||||
-------------------------
|
||||
|
||||
Users can create new devices in the "Device" section of their organizer settings. When creating
|
||||
a new device, users can specify a list of events the device is allowed to access. After a new
|
||||
device is created, users will be presented initialization instructions, consisting of an URL
|
||||
and an initialization token. They will also be shown as a QR code with the following contents::
|
||||
|
||||
{"handshake_version": 1, "url": "https://pretix.eu", "token": "kpp4jn8g2ynzonp6"}
|
||||
|
||||
Your application should be able to scan a QR code of this type, or allow to enter the URL and the
|
||||
initialization token manually. The handshake version is not used for manual initialization. When a
|
||||
QR code is scanned with a higher handshake version than you support, you should reject the request
|
||||
and prompt the user to update the client application.
|
||||
|
||||
After your application received the token, you need to call the initialization endpoint to obtain
|
||||
a proper API token. At this point, you need to identify the name and version of your application,
|
||||
as well as the type of underlying hardware. Example:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/initialize HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"token": "kpp4jn8g2ynzonp6",
|
||||
"hardware_brand": "Samsung",
|
||||
"hardware_model": "Galaxy S",
|
||||
"software_brand": "pretixdroid",
|
||||
"software_version": "4.0.0"
|
||||
}
|
||||
|
||||
Every initialization token can only be used once. On success, you will receive a response containing
|
||||
information on your device as well as your API token:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"organizer": "foo",
|
||||
"device_id": 5,
|
||||
"unique_serial": "HHZ9LW9JWP390VFZ",
|
||||
"api_token": "1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd",
|
||||
"name": "Bar",
|
||||
"gate": {
|
||||
"id": 3,
|
||||
"name": "South entrance"
|
||||
}
|
||||
}
|
||||
|
||||
Please make sure that you store this ``api_token`` value. We also recommend storing your device ID, your assigned
|
||||
``unique_serial``, and the ``organizer`` you have access to, but that's up to you. ``gate`` might be ``null``.
|
||||
|
||||
In case of an error, the response will look like this:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 400 Bad Request
|
||||
Content-Type: application/json
|
||||
|
||||
{"token":["This initialization token has already been used."]}
|
||||
|
||||
|
||||
Performing API requests
|
||||
-----------------------
|
||||
|
||||
You need to include the API token with every request to pretix' API in the ``Authorization`` header
|
||||
like the following:
|
||||
|
||||
.. sourcecode:: http
|
||||
:emphasize-lines: 3
|
||||
|
||||
GET /api/v1/organizers/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
Updating the software version
|
||||
-----------------------------
|
||||
|
||||
If your application is updated, we ask you to tell the server about the new version in use. You can do this at the
|
||||
following endpoint:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/update HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Content-Type: application/json
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
{
|
||||
"hardware_brand": "Samsung",
|
||||
"hardware_model": "Galaxy S",
|
||||
"software_brand": "pretixdroid",
|
||||
"software_version": "4.1.0"
|
||||
}
|
||||
|
||||
You will receive a response equivalent to the response of your initialization request.
|
||||
|
||||
Creating a new API key
|
||||
----------------------
|
||||
|
||||
If you think your API key might have leaked or just want to be extra cautious, the API allows you to create a new key.
|
||||
The old API key will be invalid immediately. A request for a new key looks like this:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/roll HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
The response will look like the response to the initialization request.
|
||||
|
||||
Removing a device
|
||||
-----------------
|
||||
|
||||
If you want implement a way to to deprovision a device in your software, you can call the ``revoke`` endpoint to
|
||||
invalidate your API key. There is no way to reverse this operation.
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/revoke HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
This can also be done by the user through the web interface.
|
||||
|
||||
Permissions & security profiles
|
||||
-------------------------------
|
||||
|
||||
Device authentication is currently hardcoded to grant the following permissions:
|
||||
|
||||
* View event meta data and products etc.
|
||||
* View orders
|
||||
* Change orders
|
||||
* Manage gift cards
|
||||
|
||||
Devices cannot change events or products and cannot access vouchers.
|
||||
|
||||
Additionally, when creating a device through the user interface or API, a user can specify a "security profile" for
|
||||
the device. These include an allow list of specific API calls that may be made by the device. pretix ships with security
|
||||
policies for official pretix apps like pretixSCAN and pretixPOS.
|
||||
|
||||
Removing a device
|
||||
-----------------
|
||||
|
||||
If you want implement a way to to deprovision a device in your software, you can call the ``revoke`` endpoint to
|
||||
invalidate your API key. There is no way to reverse this operation.
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/device/revoke HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
This can also be done by the user through the web interface.
|
||||
|
||||
Event selection
|
||||
---------------
|
||||
|
||||
In most cases, your application should allow the user to select the event and check-in list they work with manually
|
||||
from a list. However, in some cases it is required to automatically configure the device for the correct event, for
|
||||
example in a kiosk-like situation where nobody is operating the device. In this case, the app can query the server
|
||||
for a suggestion which event should be used. You can also submit the configuration that is currently in use via
|
||||
query parameters:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/device/eventselection?current_event=democon¤t_subevent=42¤t_checkinlist=542 HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Device 1kcsh572fonm3hawalrncam4l1gktr2rzx25a22l8g9hx108o9oi0rztpcvwnfnd
|
||||
|
||||
You can get three response codes:
|
||||
|
||||
* ``304`` The server things you already selected a good event
|
||||
* ``404`` The server has not found a suggestion for you
|
||||
* ``200`` The server suggests a new event (body see below)
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"event": "democon",
|
||||
"subevent": 23,
|
||||
"checkinlist": 5
|
||||
}
|
||||
|
||||
@@ -6,42 +6,43 @@ with pretix' REST API, such as authentication, pagination and similar definition
|
||||
|
||||
.. _`rest-auth`:
|
||||
|
||||
Obtaining an API token
|
||||
----------------------
|
||||
|
||||
To authenticate your API requests, you need to obtain an API token. You can create a
|
||||
token in the pretix web interface on the level of organizer teams. Create a new team
|
||||
or choose an existing team that has the level of permissions the token should have and
|
||||
create a new token using the form below the list of team members:
|
||||
|
||||
.. image:: img/token_form.png
|
||||
:class: screenshot
|
||||
|
||||
You can enter a description for the token to distinguish from other tokens later on.
|
||||
Once you click "Add", you will be provided with an API token in the success message.
|
||||
Copy this token, as you won't be able to retrieve it again.
|
||||
|
||||
.. image:: img/token_success.png
|
||||
:class: screenshot
|
||||
|
||||
Authentication
|
||||
--------------
|
||||
|
||||
To access the API, you need to present valid authentication credentials. pretix currently
|
||||
supports the following authorization schemes:
|
||||
You need to include the API token with every request to pretix' API in the ``Authorization`` header
|
||||
like the following:
|
||||
|
||||
* :ref:`rest-tokenauth`: This is the simplest way and recommended for server-side applications
|
||||
that interact with pretix without user interaction.
|
||||
* :ref:`rest-oauth`: This is the recommended way to use if you write a third-party application
|
||||
that users can connect with their pretix account. It provides the best user experience, but
|
||||
requires user interaction and slightly more implementation effort.
|
||||
* :ref:`rest-deviceauth`: This is the recommended way if you build apps or hardware devices that can
|
||||
connect to pretix, e.g. for processing check-ins or to sell tickets offline. It provides a way
|
||||
to uniquely identify devices and allows for a quick configuration flow inside your software.
|
||||
* Authentication using browser sessions: This is used by the pretix web interface and it is *not*
|
||||
officially supported for use by third-party applications. It might change or be removed at any
|
||||
time without prior notice. If you use it, you need to comply with Django's `CSRF policies`_.
|
||||
.. sourcecode:: http
|
||||
:emphasize-lines: 3
|
||||
|
||||
Permissions
|
||||
-----------
|
||||
GET /api/v1/organizers/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Token e1l6gq2ye72thbwkacj7jbri7a7tvxe614ojv8ybureain92ocub46t5gab5966k
|
||||
|
||||
The API follows pretix team based permissions model. Each organizer can have several teams
|
||||
each with it's own set of permissions. Each team can have any number of API keys attached.
|
||||
|
||||
To access a given endpoint the team the API key belongs to needs to have the corresponding
|
||||
permission for the organizer/event being accessed.
|
||||
|
||||
Possible permissions are:
|
||||
|
||||
* Can create events
|
||||
* Can change event settings
|
||||
* Can change product settings
|
||||
* Can view orders
|
||||
* Can change orders
|
||||
* Can view vouchers
|
||||
* Can change vouchers
|
||||
.. note:: The API currently also supports authentication via browser sessions, i.e. the
|
||||
same way that you authenticate with pretix when using the browser interface.
|
||||
Using this type of authentication is *not* officially supported for use by
|
||||
third-party clients and might change or be removed at any time. We plan on
|
||||
adding OAuth2 support in the future for user-level authentication. If you want
|
||||
to use session authentication, be sure to comply with Django's `CSRF policies`_.
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
@@ -89,41 +90,6 @@ respective page.
|
||||
The field ``results`` contains a list of objects representing the first results. For most
|
||||
objects, every page contains 50 results.
|
||||
|
||||
Conditional fetching
|
||||
--------------------
|
||||
|
||||
If you pull object lists from pretix' APIs regularly, we ask you to implement conditional fetching
|
||||
to avoid unnecessary data traffic. This is not supported on all resources and we currently implement
|
||||
two different mechanisms for different resources, which is necessary because we can only obtain best
|
||||
efficiency for resources that do not support deletion operations.
|
||||
|
||||
Object-level conditional fetching
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :ref:`rest-orders` resource list contains an HTTP header called ``X-Page-Generated`` containing the
|
||||
current time on the server in ISO 8601 format. On your next request, you can pass this header
|
||||
(as is, without any modifications necessary) as the ``modified_since`` query parameter and you will receive
|
||||
a list containing only objects that have changed in the time since your last request.
|
||||
|
||||
List-level conditional fetching
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If modification checks are not possible with this granularity, you can instead check for the full list.
|
||||
In this case, the list of objects may contain a regular HTTP header ``Last-Modified`` with the date of the
|
||||
last modification to any item of that resource. You can then pass this date back in your next request in the
|
||||
``If-Modified-Since`` header. If the any object has changed in the meantime, you will receive back a full list
|
||||
(if something it missing, this means the object has been deleted). If nothing happened, we'll send back a
|
||||
``304 Not Modified`` return code.
|
||||
|
||||
This is currently implemented on the following resources:
|
||||
|
||||
* :ref:`rest-categories`
|
||||
* :ref:`rest-items`
|
||||
* :ref:`rest-questions`
|
||||
* :ref:`rest-quotas`
|
||||
* :ref:`rest-subevents`
|
||||
* :ref:`rest-taxrules`
|
||||
|
||||
Errors
|
||||
------
|
||||
|
||||
@@ -148,7 +114,6 @@ Field specific input errors include the name of the offending fields as keys in
|
||||
|
||||
{"amount": ["A valid integer is required."], "description": ["This field may not be blank."]}
|
||||
|
||||
If you see errors of type ``429 Too Many Requests``, you should read our documentation on :ref:`rest-ratelimit`.
|
||||
|
||||
Data types
|
||||
----------
|
||||
@@ -170,19 +135,6 @@ Date String in ISO 8601 format ``2017-12-27``
|
||||
Multi-lingual string Object of strings ``{"en": "red", "de": "rot", "de_Informal": "rot"}``
|
||||
Money String with decimal number ``"23.42"``
|
||||
Currency String with ISO 4217 code ``"EUR"``, ``"USD"``
|
||||
Relative datetime *either* String in ISO 8601 ``"2017-12-27T10:00:00.596934Z"``,
|
||||
format *or* specification of ``"RELDATE/3/12:00:00/presale_start/"``
|
||||
a relative datetime,
|
||||
constructed from a number of
|
||||
days before the base point,
|
||||
a time of day, and the base
|
||||
point.
|
||||
Relative date *either* String in ISO 8601 ``"2017-12-27"``,
|
||||
format *or* specification of ``"RELDATE/3/-/presale_start/"``
|
||||
a relative date,
|
||||
constructed from a number of
|
||||
days before the base point
|
||||
and the base point.
|
||||
===================== ============================ ===================================
|
||||
|
||||
Query parameters
|
||||
@@ -194,37 +146,4 @@ as the string values ``true`` and ``false``.
|
||||
If the ``ordering`` parameter is documented for a resource, you can use it to sort the result set by one of the allowed
|
||||
fields. Prepend a ``-`` to the field name to reverse the sort order.
|
||||
|
||||
|
||||
Idempotency
|
||||
-----------
|
||||
|
||||
Our API supports an idempotency mechanism to make sure you can safely retry operations without accidentally performing
|
||||
them twice. This is useful if an API call experiences interruptions in transit, e.g. due to a network failure, and you
|
||||
do not know if it completed successfully.
|
||||
|
||||
To perform an idempotent request, add a ``X-Idempotency-Key`` header with a random string value (we recommend a version
|
||||
4 UUID) to your request. If we see a second request with the same ``X-Idempotency-Key`` and the same ``Authorization``
|
||||
and ``Cookie`` headers, we will not perform the action for a second time but return the exact same response instead.
|
||||
|
||||
Please note that this also goes for most error responses. For example, if we returned you a ``403 Permission Denied``
|
||||
error and you retry with the same ``X-Idempotency-Key``, you will get the same error again, even if you were granted
|
||||
permission in the meantime! This includes internal server errors on our side that might have been fixed in the meantime.
|
||||
|
||||
There are only three exceptions to the rule:
|
||||
|
||||
* Responses with status code ``409 Conflict`` are not cached. If you send the request again, it will be executed as a
|
||||
new request, since these responses are intended to be retried.
|
||||
|
||||
* Rate-limited responses with status code ``429 Too Many Requests`` are not cached and you can safely retry them.
|
||||
|
||||
* Responses with status code ``503 Service Unavailable`` are not cached and you can safely retry them.
|
||||
|
||||
If you send a request with an ``X-Idempotency-Key`` header that we have seen before but that has not yet received a
|
||||
response, you will receive a response with status code ``409 Conflict`` and are asked to retry after five seconds.
|
||||
|
||||
We store idempotency keys for 24 hours, so you should never retry a request after a longer time period.
|
||||
|
||||
All ``POST``, ``PUT``, ``PATCH``, or ``DELETE`` api calls support idempotency keys. Adding an idempotency key to a
|
||||
``GET``, ``HEAD``, or ``OPTIONS`` request has no effect.
|
||||
|
||||
.. _CSRF policies: https://docs.djangoproject.com/en/1.11/ref/csrf/#ajax
|
||||
.. _CSRF policies: https://docs.djangoproject.com/en/1.11/ref/csrf/#ajax
|
||||
@@ -1,132 +0,0 @@
|
||||
Creating an external checkout process
|
||||
=====================================
|
||||
|
||||
Occasionally, we get asked whether it is possible to just use pretix' powerful backend as a ticketing engine but use
|
||||
a fully-customized checkout process that only communicates via the API. This is possible, but with a few limitations.
|
||||
If you go down this route, you will miss out on many of pretix features and safeguards, as well as the added flexibility
|
||||
by most of pretix' plugins. We strongly recommend to talk this through with us before you decide this is the way to go.
|
||||
|
||||
However, this is really useful if you need to tightly integrate pretix into existing web applications that e.g. control
|
||||
the pricing of your products in a way that cannot be mapped to pretix' product structures.
|
||||
|
||||
Creating orders
|
||||
---------------
|
||||
|
||||
After letting your user select the products to buy in your application, you should create a new order object inside
|
||||
pretix. Below, you can see an example of such an order, but most fields are optional and there are some more features
|
||||
supported. Read :ref:`rest-orders-create` to learn more about this endpoint.
|
||||
|
||||
Please note that this endpoint assumes trustworthy input for the most part. By default, the endpoint checks that
|
||||
you do not exceed any quotas, do not sell any seats twice, or do not use any redeemed vouchers. However, it will not
|
||||
complain about violation of any other availability constraints, such as violation of time frames or minimum/maximum
|
||||
amounts of either your product or event. Bundled products will not be added in automatically and fees will not be
|
||||
calculated automatically.
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/democon/events/3vjrh/orders/ HTTP/1.1
|
||||
Host: test.pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Authorization: …
|
||||
|
||||
{
|
||||
"email": "dummy@example.org",
|
||||
"locale": "en",
|
||||
"sales_channel": "web",
|
||||
"payment_provider": "banktransfer",
|
||||
"invoice_address": {
|
||||
"is_business": false,
|
||||
"company": "Sample company",
|
||||
"name_parts": {"full_name": "John Doe"},
|
||||
"street": "Sesam Street 12",
|
||||
"zipcode": "12345",
|
||||
"city": "Sample City",
|
||||
"country": "US",
|
||||
"state": "NY",
|
||||
"internal_reference": "",
|
||||
"vat_id": ""
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"item": 21,
|
||||
"variation": null,
|
||||
"attendee_name_parts": {
|
||||
"full_name": "Peter"
|
||||
},
|
||||
"answers": [
|
||||
{
|
||||
"question": 1,
|
||||
"answer": "23",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"subevent": null
|
||||
}
|
||||
],
|
||||
"fees": []
|
||||
}
|
||||
|
||||
You will be returned a full order object that you can inspect, store, or use to build emails or confirmation pages for
|
||||
the user. If you don't want to do that yourself, it will also contain the URL to our confirmation page in the ``url``
|
||||
attribute. If you pass the ``"send_mail": true`` option, pretix will also send order confirmations for you.
|
||||
|
||||
Handling payments yourself
|
||||
--------------------------
|
||||
|
||||
If you want to handle payments in your application, you can either just create the orders with status "paid" or you can
|
||||
create them in "pending" state (the default) and later confirm the payment. We strongly advise to use the payment
|
||||
provider ``"manual"`` in this case to avoid interference with payment code with pretix.
|
||||
|
||||
However, it is often unfeasible to implement the payment process yourself, and it also requires you to give up a
|
||||
lot of pretix functionality, such as automatic refunds. Therefore, it is also possible to utilize pretix' native
|
||||
payment process even in this case:
|
||||
|
||||
Using pretix payment providers
|
||||
------------------------------
|
||||
|
||||
If you passed a ``payment_provider`` during order creation above, pretix will have created a payment object with state
|
||||
``created`` that you can see in the returned order object. This payment object will have an attribute ``payment_url``
|
||||
that you can use to let the user pay. For example, you could link or redirect to this page.
|
||||
|
||||
If you want the user to return to your application after the payment is complete, you can pass a query parameter
|
||||
``return_url``. To prepare your event for this, open your event in the pretix backend and go to "Settings", then
|
||||
"Plugins". Enable the plugin "Redirection from order page". Then, go to the new page "Settings", then "Redirection".
|
||||
Enter the base URL of your web application. This will allow you to redirect to pages under this base URL later on.
|
||||
For example, if you want users to be redirected to ``https://example.org/order/return?tx_id=1234``, you could now
|
||||
either enter ``https://example.org`` or ``https://example.org/order/``.
|
||||
|
||||
The user will be redirected back to your page instead of pretix' order confirmation page after the payment,
|
||||
**regardless of whether it was successful or not**. Make sure you use our API to check if the payment actually
|
||||
worked! Your final URL could look like this::
|
||||
|
||||
https://test.pretix.eu/democon/3vjrh/order/NSLEZ/ujbrnsjzbq4dzhck/pay/123/?return_url=https%3A%2F%2Fexample.org%2Forder%2Freturn%3Ftx_id%3D1234
|
||||
|
||||
You can also embed this page in an ``<iframe>`` instead. Note, however, that this causes problems with some payment
|
||||
methods such as PayPal which do not allow being opened in an iframe. pretix can partly work around these issues by
|
||||
opening a new window, but will only to so if you also append an ``iframe=1`` parameter to the URL::
|
||||
|
||||
https://test.pretix.eu/democon/3vjrh/order/NSLEZ/ujbrnsjzbq4dzhck/pay/123/?return_url=https%3A%2F%2Fexample.org%2Forder%2Freturn%3Ftx_id%3D1234&iframe=1
|
||||
|
||||
If you did **not** pass a payment method since you want us to ask the user which payment method they want to use, you
|
||||
need to construct the URL from the ``url`` attribute of the order and the sub-path ``pay/change```. For example, you
|
||||
would end up with the following URL::
|
||||
|
||||
https://test.pretix.eu/democon/3vjrh/order/NSLEZ/ujbrnsjzbq4dzhck/pay/change
|
||||
|
||||
Of course, you can also use the ``iframe`` and ``return_url`` parameters here.
|
||||
|
||||
Optional: Cart reservations
|
||||
---------------------------
|
||||
|
||||
Creating orders is an atomic operation: The order is either created as a whole or not at all. However, pretix'
|
||||
built-in checkout automatically reserves tickets in a user's cart for a configurable amount of time to ensure users
|
||||
will actually get their tickets once they started entering all their details. If you want a similar behavior in your
|
||||
application, you need to create :ref:`rest-carts` through the API.
|
||||
|
||||
When creating your order, you can pass a ``consume_carts`` parameter with the cart ID(s) of your user. This way, the
|
||||
quota reserved by the cart will be credited towards the order and the carts will be destroyed if (and only if) the
|
||||
order creation succeeds.
|
||||
|
||||
Cart creation is currently even more limited than the order creation endpoints, as cart creation currently does not
|
||||
support vouchers or automatic price calculation. If you require these features, please get in touch with us.
|
||||
@@ -1,11 +0,0 @@
|
||||
.. _`rest-api-guides`:
|
||||
|
||||
API Usage Guides
|
||||
================
|
||||
|
||||
This part of the documentation contains how-to guides on some special use cases of our API.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
custom_checkout
|
||||
@@ -7,12 +7,11 @@ This part of the documentation contains information about the REST-style API
|
||||
exposed by pretix since version 1.5 that can be used by third-party programs
|
||||
to interact with pretix and its data structures.
|
||||
|
||||
Currently, the API provides mostly read-only capabilities, but it will be extended
|
||||
in functionality over time.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
fundamentals
|
||||
auth
|
||||
resources/index
|
||||
ratelimit
|
||||
webhooks
|
||||
guides/index
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
.. _`rest-oauth`:
|
||||
|
||||
OAuth authentication / "Connect with pretix"
|
||||
============================================
|
||||
|
||||
In addition to static tokens, pretix supports `OAuth2`_-based authentication starting with
|
||||
pretix 1.16. This allows you to put a "Connect with pretix" button into your website or tool
|
||||
that allows the user to easily set up a connection between the two systems.
|
||||
|
||||
If you haven't worked with OAuth before, have a look at the `OAuth2 Simplified`_ tutorial.
|
||||
|
||||
Registering an application
|
||||
--------------------------
|
||||
|
||||
To use OAuth, you need to register your application with the pretix instance you want to connect to.
|
||||
In order to do this, log in to your pretix account and go to your user settings. Click on "Authorized applications"
|
||||
first and then on "Manage your own apps". From there, you can "Create a new application".
|
||||
|
||||
You should fill in a descriptive name of your application that allows users to recognize who you are. You also need to
|
||||
give a list of fully-qualified URLs that users will be redirected to after a successful authorization. After you pressed
|
||||
"Save", you will be presented with a client ID and a client secret. Please note them down and treat the client secret
|
||||
like a password; it should not become available to your users.
|
||||
|
||||
Obtaining an authorization grant
|
||||
--------------------------------
|
||||
|
||||
To authorize a new user, link or redirect them to the ``authorize`` endpoint, passing your client ID as a query
|
||||
parameter. Additionally, you can pass a scope (currently either ``read``, ``write``, ``read write`` or ``profile``)
|
||||
and an URL the user should be redirected to after successful or failed authorization. You also need to pass the
|
||||
``response_type`` parameter with a value of ``code``. Example::
|
||||
|
||||
https://pretix.eu/api/v1/oauth/authorize?client_id=lsLi0hNL0vk53mEdYjNJxHUn1PcO1R6wVg81dLNT&response_type=code&scope=read+write&redirect_uri=https://pretalx.com
|
||||
|
||||
To prevent CSRF attacks, you can also optionally pass a ``state`` parameter with a random string. Later, when
|
||||
redirecting back to your application, we will pass the same ``state`` parameter back to you, so you can compare if they
|
||||
match.
|
||||
|
||||
After the user granted or denied access, they will be redirected back either to the ``redirect_url`` you passed in the
|
||||
query or to the first redirect URL configured in your application settings.
|
||||
|
||||
On successful registration, we will append the query parameter ``code`` to the URL containing an authorization code.
|
||||
For example, we might redirect the user to this URL::
|
||||
|
||||
https://pretalx.com/?code=eYBBf8gmeD4E01HLoj0XflqO4Lg3Cw&state=e3KCh9mfx07qxU4bRpXk
|
||||
|
||||
You will need this ``code`` parameter to perform the next step.
|
||||
|
||||
On a failed registration, a query string like ``?error=access_denied`` will be appended to the redirection URL.
|
||||
|
||||
.. note:: By default, the user is asked to give permission on every call to this URL. If you **only** request the
|
||||
``profile`` scope, i.e. no access to organizer data, you can pass the ``approval_prompt=auto`` parameter
|
||||
to skip user interaction on subsequent calls.
|
||||
|
||||
Getting an access token
|
||||
-----------------------
|
||||
|
||||
Using the ``code`` value you obtained above and your client ID, you can now request an access token that actually gives
|
||||
access to the API. The ``token`` endpoint expects you to authenticate using `HTTP Basic authentication`_ using your client
|
||||
ID as a username and your client secret as a password. You are also required to again supply the same ``redirect_uri``
|
||||
parameter that you used for the authorization.
|
||||
|
||||
.. http:post:: /api/v1/oauth/token
|
||||
|
||||
Request a new access token
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/oauth/token HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Authorization: Basic bHNMaTBoTkwwdms1M21FZFlqTkp4SFVuMVBjTzFSNndWZzgxZExOVDplSmpzZVA0UjJMN0hMcjBiS0p1b3BmbnJtT2cyY3NDeTdYaFVVZ0FoalhUU0NhZHhRTjk3cVNvMkpPaXlWTFpQOEozaTVQd1FVdFIwNUNycG5ac2Z0bXJjdmNTbkZ1SkFmb2ZsUTdZUDRpSjZNTWFYTHIwQ0FpNlhIRFJjV1Awcg==
|
||||
|
||||
grant_type=authorization_code&code=eYBBf8gmeD4E01HLoj0XflqO4Lg3Cw&redirect_uri=https://pretalx.com
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"access_token": "i3ytqTSRWsKp16fqjekHXa4tdM4qNC",
|
||||
"expires_in": 86400,
|
||||
"token_type": "Bearer",
|
||||
"scope": "read write",
|
||||
"refresh_token": "XBK0r8z4A4TTeR9LyMUyU2AM5rqpXp"
|
||||
}
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
|
||||
As you can see, you receive two types of tokens: One "access token", and one "refresh token". The access token is valid
|
||||
for a day and can be used to actually access the API. The refresh token does not have an expiration date and can be used
|
||||
to obtain a new access_token after a day, so you should make sure to store the access token safely if you need long-term
|
||||
access.
|
||||
|
||||
Using the API with an access token
|
||||
----------------------------------
|
||||
|
||||
You can supply a valid access token as a ``Bearer``-type token in the ``Authorization`` header to get API access.
|
||||
|
||||
.. sourcecode:: http
|
||||
:emphasize-lines: 3
|
||||
|
||||
GET /api/v1/organizers/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Bearer i3ytqTSRWsKp16fqjekHXa4tdM4qNC
|
||||
|
||||
Refreshing an access token
|
||||
--------------------------
|
||||
|
||||
You can obtain a new access token using your refresh token any time. This can be done using the same ``token`` endpoint
|
||||
used to obtain the first access token above, but with a different set of parameters:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/oauth/token HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Authorization: Basic bHNMaTBoTkwwdms1M21FZFlqTkp4SFVuMVBjTzFSNndWZzgxZExOVDplSmpzZVA0UjJMN0hMcjBiS0p1b3BmbnJtT2cyY3NDeTdYaFVVZ0FoalhUU0NhZHhRTjk3cVNvMkpPaXlWTFpQOEozaTVQd1FVdFIwNUNycG5ac2Z0bXJjdmNTbkZ1SkFmb2ZsUTdZUDRpSjZNTWFYTHIwQ0FpNlhIRFJjV1Awcg==
|
||||
|
||||
grant_type=refresh_token&refresh_token=XBK0r8z4A4TTeR9LyMUyU2AM5rqpXp
|
||||
|
||||
The previous access token will instantly become invalid.
|
||||
|
||||
Revoking a token
|
||||
----------------
|
||||
|
||||
If you don't need a token any more or if you believe it may have been compromised, you can use the ``revoke_token``
|
||||
endpoint to revoke it.
|
||||
|
||||
.. http:get:: /api/v1/oauth/revoke_token
|
||||
|
||||
Revoke an access or refresh token. If you revoke an access token, you can still create a new one using the refresh token. If you
|
||||
revoke a refresh token, the connected access token will also be revoked.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/oauth/revoke_token HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Authorization: Basic bHNMaTBoTkwwdms1M21FZFlqTkp4SFVuMVBjTzFSNndWZzgxZExOVDplSmpzZVA0UjJMN0hMcjBiS0p1b3BmbnJtT2cyY3NDeTdYaFVVZ0FoalhUU0NhZHhRTjk3cVNvMkpPaXlWTFpQOEozaTVQd1FVdFIwNUNycG5ac2Z0bXJjdmNTbkZ1SkFmb2ZsUTdZUDRpSjZNTWFYTHIwQ0FpNlhIRFJjV1Awcg==
|
||||
|
||||
token=XBK0r8z4A4TTeR9LyMUyU2AM5rqpXp
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
If you want to revoke your client secret, you can generate a new one in the list of your managed applications in the
|
||||
pretix user interface.
|
||||
|
||||
Fetching the user profile
|
||||
-------------------------
|
||||
|
||||
If you need the user's meta data, you can fetch it here:
|
||||
|
||||
.. http:get:: /api/v1/me
|
||||
|
||||
Returns the profile of the authenticated user
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/me HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Authorization: Bearer i3ytqTSRWsKp16fqjekHXa4tdM4qNC
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "admin@localhost",
|
||||
"fullname": "John Doe",
|
||||
"locale": "de",
|
||||
"is_staff": false,
|
||||
"timezone": "Europe/Berlin"
|
||||
}
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
.. _OAuth2: https://en.wikipedia.org/wiki/OAuth
|
||||
.. _OAuth2 Simplified: https://aaronparecki.com/oauth-2-simplified/
|
||||
.. _HTTP Basic authentication: https://en.wikipedia.org/wiki/Basic_access_authentication
|
||||
@@ -1,31 +0,0 @@
|
||||
.. _`rest-ratelimit`:
|
||||
|
||||
Rate limiting
|
||||
=============
|
||||
|
||||
.. note:: This page only applies to the pretix Hosted service at pretix.eu. APIs of custom pretix installations do not
|
||||
enforce any rate limiting by default.
|
||||
|
||||
All authenticated requests to pretix' API are rate limited. If you exceed the limits, you will receive a response
|
||||
with HTTP status code ``429 Too Many Requests``. This response will have a ``Retry-After`` header, containing the number
|
||||
of seconds you are supposed to wait until you try again. We expect that all API clients respect this. If you continue
|
||||
to burst requests after a ``429`` status code, we might get in touch with you or, in extreme cases, disable your API
|
||||
access.
|
||||
|
||||
Currently, the following rate limits apply:
|
||||
|
||||
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== =================================================================================
|
||||
Authentication method Rate limit
|
||||
===================================== =================================================================================
|
||||
:ref:`rest-deviceauth` 360 requests per minute per device
|
||||
:ref:`rest-tokenauth` 360 requests per minute per organizer account
|
||||
:ref:`rest-oauth` 360 requests per minute per combination of accessed organizer and OAuth application
|
||||
Session authentication *Not an officially supported authentication method for external access*
|
||||
===================================== =================================================================================
|
||||
|
||||
If you require a higher rate limit, please get in touch at support@pretix.eu and tell us about your use case, we are
|
||||
sure we can work something out.
|
||||
@@ -1,131 +0,0 @@
|
||||
pretix Hosted billing invoices
|
||||
==============================
|
||||
|
||||
This endpoint allows you to access invoices you received for pretix Hosted. It only contains invoices created starting
|
||||
November 2017.
|
||||
|
||||
.. note:: Only available on pretix Hosted, not on self-hosted pretix instances.
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
invoice_number string Invoice number
|
||||
date_issued date Invoice date
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/billing_invoices/
|
||||
|
||||
Returns a list of all invoices to a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/billing_invoices/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"invoice_number": "R2019002",
|
||||
"date_issued": "2019-06-03"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``date_issued`` and
|
||||
its reverse, ``-date_issued``. Default: ``date_issued``.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/billing_invoices/(invoice_number)/
|
||||
|
||||
Returns information on one invoice, identified by its invoice number.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/billing_invoices/R2019002/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"invoice_number": "R2019002",
|
||||
"date_issued": "2019-06-03"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param invoice_number: The ``invoice_number`` field of the invoice to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/billing_invoices/(invoice_number)/download/
|
||||
|
||||
Download an invoice in PDF format.
|
||||
|
||||
.. warning:: After we created the invoices, they are placed in review with our accounting department. You will
|
||||
already see them in the API at this point, but you are not able to download them until they completed
|
||||
review and are sent to you via email. This usually takes a few hours. If you try to download them
|
||||
in this time frame, you will receive a status code :http:statuscode:`423`.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/billing_invoices/R2019002/download/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/pdf
|
||||
|
||||
...
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param invoice_number: The ``invoice_number`` field of the invoice to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 423: The file is not yet ready and will now be prepared. Retry the request after waiting for a few
|
||||
seconds.
|
||||
@@ -1,148 +0,0 @@
|
||||
pretix Hosted reseller API
|
||||
==========================
|
||||
|
||||
This API is only accessible to our `value-added reseller partners`_ on pretix Hosted.
|
||||
|
||||
.. note:: This API is only accessible with user-level permissions, not with API tokens. Therefore, you will need to
|
||||
create an :ref:`OAuth application <rest-oauth>` and obtain an OAuth access token for a user account that has
|
||||
permission to your reseller account.
|
||||
|
||||
Reseller account resource
|
||||
-------------------------
|
||||
|
||||
The resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Your reseller ID
|
||||
name string Internal name of your reseller account
|
||||
public_name string Public name of your reseller account
|
||||
public_url string Public URL of your company
|
||||
support_email string Your support email address
|
||||
support_phone string Your support phone number
|
||||
communication_language string Language code we use to communicate with you
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/var/
|
||||
|
||||
Returns a list of all reseller accounts you have access to.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/var/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "ticketshop.live Ltd & Co. KG",
|
||||
"public_name": "ticketshop.live",
|
||||
"public_url": "https://ticketshop.live",
|
||||
"support_email": "support@ticketshop.live",
|
||||
"support_phone": "+4962213217750",
|
||||
"communication_language": "de"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
.. http:get:: /api/v1/var/(id)/
|
||||
|
||||
Returns information on one reseller account, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/var/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "ticketshop.live Ltd & Co. KG",
|
||||
"public_name": "ticketshop.live",
|
||||
"public_url": "https://ticketshop.live",
|
||||
"support_email": "support@ticketshop.live",
|
||||
"support_phone": "+4962213217750",
|
||||
"communication_language": "de"
|
||||
}
|
||||
|
||||
:param id: The ``id`` field of the reseller account to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 404: The requested account does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/var/(id)/create_organizer/
|
||||
|
||||
Creates a new organizer account that will be associated with a given reseller account.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/var/1/create_organizer/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 123
|
||||
|
||||
{
|
||||
"name": "My new client",
|
||||
"slug": "New client"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "My new client",
|
||||
"slug": "New client"
|
||||
}
|
||||
|
||||
:param id: The ``id`` field of the reseller account to fetch
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: Invalid request body, usually the slug is invalid or already taken.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 404: The requested account does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. _value-added reseller partners: https://pretix.eu/about/en/var
|
||||
@@ -1,276 +0,0 @@
|
||||
.. _rest-carts:
|
||||
|
||||
Cart positions
|
||||
==============
|
||||
|
||||
The API provides limited access to the cart position data model. This API currently only allows creating and deleting
|
||||
cart positions to reserve quota.
|
||||
|
||||
Cart position resource
|
||||
----------------------
|
||||
|
||||
The cart position resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the cart position
|
||||
cart_id string Identifier of the cart this belongs to. Needs to end
|
||||
in "@api" for API-created positions.
|
||||
datetime datetime Time of creation
|
||||
expires datetime The cart position will expire at this time and no longer block quota
|
||||
item integer ID of the item
|
||||
variation integer ID of the variation (or ``null``)
|
||||
price money (string) Price of this position
|
||||
attendee_name string Specified attendee name for this position (or ``null``)
|
||||
attendee_name_parts object of strings Composition of attendee name (i.e. first name, last name, …)
|
||||
attendee_email string Specified attendee email address for this position (or ``null``)
|
||||
voucher integer Internal ID of the voucher used for this position (or ``null``)
|
||||
addon_to integer Internal ID of the position this position is an add-on for (or ``null``)
|
||||
subevent integer ID of the date inside an event series this position belongs to (or ``null``).
|
||||
answers list of objects Answers to user-defined questions
|
||||
├ question integer Internal ID of the answered question
|
||||
├ answer string Text representation of the answer
|
||||
├ question_identifier string The question's ``identifier`` field
|
||||
├ options list of integers Internal IDs of selected option(s)s (only for choice types)
|
||||
└ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
|
||||
seat objects The assigned seat. Can be ``null``.
|
||||
├ id integer Internal ID of the seat instance
|
||||
├ name string Human-readable seat name
|
||||
└ seat_guid string Identifier of the seat within the seating plan
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.17
|
||||
|
||||
This resource has been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
This ``seat`` attribute has been added.
|
||||
|
||||
|
||||
Cart position endpoints
|
||||
-----------------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/cartpositions/
|
||||
|
||||
Returns a list of API-created cart positions.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/cartpositions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
X-Page-Generated: 2017-12-01T10:00:00Z
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"cart_id": "XwokV8FojQviD9jhtDzKvHFdlLRNMhlfo3cNjGbuK6MUTQDT@api",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name": null,
|
||||
"attendee_name_parts": {},
|
||||
"attendee_email": null,
|
||||
"voucher": null,
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
"datetime": "2018-06-11T10:00:00Z",
|
||||
"expires": "2018-06-11T10:00:00Z",
|
||||
"includes_tax": true,
|
||||
"seat": null,
|
||||
"answers": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/cartpositions/(id)/
|
||||
|
||||
Returns information on one cart position, identified by its internal ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/cartpositions/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"cart_id": "XwokV8FojQviD9jhtDzKvHFdlLRNMhlfo3cNjGbuK6MUTQDT@api",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name": null,
|
||||
"attendee_name_parts": {},
|
||||
"attendee_email": null,
|
||||
"voucher": null,
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
"datetime": "2018-06-11T10:00:00Z",
|
||||
"expires": "2018-06-11T10:00:00Z",
|
||||
"includes_tax": true,
|
||||
"seat": null,
|
||||
"answers": []
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param id: The ``id`` field of the position to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested cart position does not exist.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/cartpositions/
|
||||
|
||||
Creates a new cart position.
|
||||
|
||||
.. warning:: This endpoint is considered **experimental**. It might change at any time without prior notice.
|
||||
|
||||
.. warning::
|
||||
|
||||
This endpoint is intended for advanced users. It is not designed to be used to build your own shop frontend.
|
||||
There is a lot that it does not or can not do, and you will need to be careful using it.
|
||||
It allows to bypass many of the restrictions imposed when creating a cart through the
|
||||
regular shop.
|
||||
|
||||
Specifically, this endpoint currently
|
||||
|
||||
* does not validate if products are only to be sold in a specific time frame
|
||||
|
||||
* does not validate if the event's ticket sales are already over or haven't started
|
||||
|
||||
* does not support add-on products at the moment
|
||||
|
||||
* does not check or calculate prices but believes any prices you send
|
||||
|
||||
* does not support the redemption of vouchers
|
||||
|
||||
* does not prevent you from buying items that can only be bought with a voucher
|
||||
|
||||
* does not support file upload questions
|
||||
|
||||
You can supply the following fields of the resource:
|
||||
|
||||
* ``cart_id`` (optional, needs to end in ``@api``)
|
||||
* ``item``
|
||||
* ``variation`` (optional)
|
||||
* ``price``
|
||||
* ``seat`` (The ``seat_guid`` attribute of a seat. Required when the specified ``item`` requires a seat, otherwise must be ``null``.)
|
||||
* ``attendee_name`` **or** ``attendee_name_parts`` (optional)
|
||||
* ``attendee_email`` (optional)
|
||||
* ``subevent`` (optional)
|
||||
* ``expires`` (optional)
|
||||
* ``includes_tax`` (optional)
|
||||
* ``sales_channel`` (optional)
|
||||
* ``answers``
|
||||
|
||||
* ``question``
|
||||
* ``answer``
|
||||
* ``options``
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/cartpositions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name_parts": {
|
||||
"given_name": "Peter",
|
||||
"family_name": "Miller"
|
||||
},
|
||||
"attendee_email": null,
|
||||
"answers": [
|
||||
{
|
||||
"question": 1,
|
||||
"answer": "23",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
(Full cart position resource, see above.)
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create a position for
|
||||
:param event: The ``slug`` field of the event to create a position for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The item could not be created due to invalid submitted data or lack of quota.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this
|
||||
order.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/cartpositions/(id)/
|
||||
|
||||
Deletes a cart position, identified by its internal ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/cartpositions/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param id: The ``id`` field of the position to delete
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested cart position does not exist.
|
||||
@@ -1,5 +1,3 @@
|
||||
.. _`rest-categories`:
|
||||
|
||||
Item categories
|
||||
===============
|
||||
|
||||
@@ -16,23 +14,14 @@ Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the category
|
||||
name multi-lingual string The category's visible name
|
||||
internal_name string An optional name that is only used in the backend
|
||||
description multi-lingual string A public description (might include markdown, can
|
||||
be ``null``)
|
||||
position integer An integer, used for sorting the categories
|
||||
is_addon boolean If ``true``, items within this category are not on sale
|
||||
is_addon boolean If ``True``, items within this category are not on sale
|
||||
on their own but the category provides a source for
|
||||
defining add-ons for other products.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.14
|
||||
|
||||
The operations POST, PATCH, PUT and DELETE have been added.
|
||||
|
||||
.. versionchanged:: 1.16
|
||||
|
||||
The field ``internal_name`` has been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
@@ -65,7 +54,6 @@ Endpoints
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": false
|
||||
@@ -107,7 +95,6 @@ Endpoints
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": false
|
||||
@@ -119,121 +106,3 @@ Endpoints
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/categories/
|
||||
|
||||
Creates a new category
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/categories/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": false
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": false
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create a category for
|
||||
:param event: The ``slug`` field of the event to create a category for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The category could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/categories/(id)/
|
||||
|
||||
Update a category. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/categories/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"is_addon": true
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Tickets"},
|
||||
"internal_name": "",
|
||||
"description": {"en": "Tickets are what you need to get in."},
|
||||
"position": 1,
|
||||
"is_addon": true
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the category to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The category could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/category/(id)/
|
||||
|
||||
Delete a category.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/categories/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the category to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
.. spelling:: checkin
|
||||
|
||||
Check-in lists
|
||||
==============
|
||||
|
||||
@@ -23,55 +21,20 @@ Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the check-in list
|
||||
name string The internal name of the check-in list
|
||||
all_products boolean If ``true``, the check-in lists contains tickets of all products in this event. The ``limit_products`` field is ignored in this case.
|
||||
all_products boolean If ``True``, the check-in lists contains tickets of all products in this event. The ``limit_products`` field is ignored in this case.
|
||||
limit_products list of integers List of item IDs to include in this list.
|
||||
subevent integer ID of the date inside an event series this list belongs to (or ``null``).
|
||||
position_count integer Number of tickets that match this list (read-only).
|
||||
checkin_count integer Number of check-ins performed on this list (read-only).
|
||||
include_pending boolean If ``true``, the check-in list also contains tickets from orders in pending state.
|
||||
auto_checkin_sales_channels list of strings All items on the check-in list will be automatically marked as checked-in when purchased through any of the listed sales channels.
|
||||
allow_multiple_entries boolean If ``true``, subsequent scans of a ticket on this list should not show a warning but instead be stored as an additional check-in.
|
||||
allow_entry_after_exit boolean If ``true``, subsequent scans of a ticket on this list are valid if the last scan of the ticket was an exit scan.
|
||||
rules object Custom check-in logic. The contents of this field are currently not considered a stable API and modifications through the API are highly discouraged.
|
||||
exit_all_at datetime Automatically check out (i.e. perform an exit scan) at this point in time. After this happened, this property will automatically be set exactly one day into the future. Note that this field is considered "internal configuration" and if you pull the list with ``If-Modified-Since``, the daily change in this field will not trigger a response.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.10
|
||||
|
||||
This resource has been added.
|
||||
|
||||
.. versionchanged:: 1.11
|
||||
|
||||
The ``positions`` endpoints have been added.
|
||||
|
||||
.. versionchanged:: 1.13
|
||||
|
||||
The ``include_pending`` field has been added.
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
|
||||
The ``auto_checkin_sales_channels`` field has been added.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
|
||||
The ``subevent`` attribute may now be ``null`` inside event series. The ``allow_multiple_entries``,
|
||||
``allow_entry_after_exit``, and ``rules`` attributes have been added.
|
||||
|
||||
.. versionchanged:: 3.11
|
||||
|
||||
The ``subevent_match`` and ``exclude`` query parameters have been added.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
|
||||
The ``exit_all_at`` attribute has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The ``../status/`` detail endpoint has been added.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/
|
||||
|
||||
Returns a list of all check-in lists within a given event.
|
||||
@@ -104,23 +67,13 @@ Endpoints
|
||||
"position_count": 456,
|
||||
"all_products": true,
|
||||
"limit_products": [],
|
||||
"include_pending": false,
|
||||
"subevent": null,
|
||||
"allow_multiple_entries": false,
|
||||
"allow_entry_after_exit": true,
|
||||
"exit_all_at": null,
|
||||
"rules": {},
|
||||
"auto_checkin_sales_channels": [
|
||||
"pretixpos"
|
||||
]
|
||||
"subevent": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query integer subevent: Only return check-in lists of the sub-event with the given ID
|
||||
:query integer subevent_match: Only return check-in lists that are valid for the sub-event with the given ID (i.e. also lists valid for all subevents)
|
||||
:query string exclude: Exclude a field from the output, e.g. ``checkin_count``. Can be used as a performance optimization. Can be passed multiple times.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 200: no error
|
||||
@@ -154,82 +107,7 @@ Endpoints
|
||||
"position_count": 456,
|
||||
"all_products": true,
|
||||
"limit_products": [],
|
||||
"include_pending": false,
|
||||
"subevent": null,
|
||||
"allow_multiple_entries": false,
|
||||
"allow_entry_after_exit": true,
|
||||
"exit_all_at": null,
|
||||
"rules": {},
|
||||
"auto_checkin_sales_channels": [
|
||||
"pretixpos"
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param id: The ``id`` field of the check-in list to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(id)/status/
|
||||
|
||||
Returns detailed status information on a check-in list, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/status/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"checkin_count": 17,
|
||||
"position_count": 42,
|
||||
"inside_count": 12,
|
||||
"event": {
|
||||
"name": "Demo Conference"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"name": "T-Shirt",
|
||||
"id": 1,
|
||||
"checkin_count": 1,
|
||||
"admission": false,
|
||||
"position_count": 1,
|
||||
"variations": [
|
||||
{
|
||||
"value": "Red",
|
||||
"id": 1,
|
||||
"checkin_count": 1,
|
||||
"position_count": 12
|
||||
},
|
||||
{
|
||||
"value": "Blue",
|
||||
"id": 2,
|
||||
"checkin_count": 4,
|
||||
"position_count": 8
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Ticket",
|
||||
"id": 2,
|
||||
"checkin_count": 15,
|
||||
"admission": true,
|
||||
"position_count": 22,
|
||||
"variations": []
|
||||
}
|
||||
]
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
@@ -250,18 +128,13 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/checkinlists/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content: application/json
|
||||
|
||||
{
|
||||
"name": "VIP entry",
|
||||
"all_products": false,
|
||||
"limit_products": [1, 2],
|
||||
"subevent": null,
|
||||
"allow_multiple_entries": false,
|
||||
"allow_entry_after_exit": true,
|
||||
"auto_checkin_sales_channels": [
|
||||
"pretixpos"
|
||||
]
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
@@ -279,13 +152,7 @@ Endpoints
|
||||
"position_count": 0,
|
||||
"all_products": false,
|
||||
"limit_products": [1, 2],
|
||||
"include_pending": false,
|
||||
"subevent": null,
|
||||
"allow_multiple_entries": false,
|
||||
"allow_entry_after_exit": true,
|
||||
"auto_checkin_sales_channels": [
|
||||
"pretixpos"
|
||||
]
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a list for
|
||||
@@ -298,7 +165,7 @@ Endpoints
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(id)/
|
||||
|
||||
Update a check-in list. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
the resource, other fields will be resetted to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field and the ``checkin_count`` and ``position_count``
|
||||
@@ -333,13 +200,7 @@ Endpoints
|
||||
"position_count": 42,
|
||||
"all_products": false,
|
||||
"limit_products": [1, 2],
|
||||
"include_pending": false,
|
||||
"subevent": null,
|
||||
"allow_multiple_entries": false,
|
||||
"allow_entry_after_exit": true,
|
||||
"auto_checkin_sales_channels": [
|
||||
"pretixpos"
|
||||
]
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
@@ -352,7 +213,7 @@ Endpoints
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/checkinlist/(id)/
|
||||
|
||||
Delete a check-in list. Note that this also deletes the information on all check-ins performed via this list.
|
||||
Delete a check-in list. Note that this also deletes the information on all checkins performed via this list.
|
||||
|
||||
**Example request**:
|
||||
|
||||
@@ -375,370 +236,3 @@ Endpoints
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
|
||||
Order position endpoints
|
||||
------------------------
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The order positions endpoint has been extended by the filter queries ``item__in``, ``variation__in``,
|
||||
``order__status__in``, ``subevent__in``, ``addon_to__in``, and ``search``. The search for attendee names and order
|
||||
codes is now case-insensitive.
|
||||
|
||||
The ``.../redeem/`` endpoint has been added.
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
|
||||
The order positions endpoint has been extended by the filter queries ``voucher`` and ``voucher__code``.
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The resource now contains the new attributes ``require_attention`` and ``order__status`` and accepts the new
|
||||
``ignore_status`` filter. The ``attendee_name`` field is now "smart" (see below) and the redemption endpoint
|
||||
returns ``400`` instead of ``404`` on tickets which are known but not paid.
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
|
||||
The ``checkins`` dict now also contains a ``auto_checked_in`` value to indicate if the check-in has been performed
|
||||
automatically by the system.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(list)/positions/
|
||||
|
||||
Returns a list of all order positions within a given event. The result is the same as
|
||||
the :ref:`order-position-resource`, with the following differences:
|
||||
|
||||
* The ``checkins`` value will only include check-ins for the selected list.
|
||||
|
||||
* An additional boolean property ``require_attention`` will inform you whether either the order or the item
|
||||
have the ``checkin_attention`` flag set.
|
||||
|
||||
* If ``attendee_name`` is empty, it will automatically fall back to values from a parent product or from invoice
|
||||
addresses.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/positions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 23442,
|
||||
"order": "ABC12",
|
||||
"positionid": 1,
|
||||
"item": 1345,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name": "Peter",
|
||||
"attendee_name_parts": {
|
||||
"full_name": "Peter",
|
||||
},
|
||||
"attendee_email": null,
|
||||
"voucher": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": null,
|
||||
"tax_value": "0.00",
|
||||
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
"pseudonymization_id": "MQLJvANO3B",
|
||||
"seat": null,
|
||||
"checkins": [
|
||||
{
|
||||
"list": 1,
|
||||
"datetime": "2017-12-25T12:45:23Z",
|
||||
"auto_checked_in": true
|
||||
}
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"question": 12,
|
||||
"answer": "Foo",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"downloads": [
|
||||
{
|
||||
"output": "pdf",
|
||||
"url": "https://pretix.eu/api/v1/organizers/bigevents/events/sampleconf/orderpositions/23442/download/pdf/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string ignore_status: If set to ``true``, results will be returned regardless of the state of
|
||||
the order they belong to and you will need to do your own filtering by order status.
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``order__code``,
|
||||
``order__datetime``, ``positionid``, ``attendee_name``, ``last_checked_in`` and ``order__email``. Default:
|
||||
``attendee_name,positionid``
|
||||
:query string order: Only return positions of the order with the given order code
|
||||
:query string search: Fuzzy search matching the attendee name, order code, invoice address name as well as to the beginning of the secret.
|
||||
:query integer item: Only return positions with the purchased item matching the given ID.
|
||||
:query integer item__in: Only return positions with the purchased item matching one of the given comma-separated IDs.
|
||||
:query integer variation: Only return positions with the purchased item variation matching the given ID.
|
||||
:query integer variation__in: Only return positions with one of the purchased item variation matching the given
|
||||
comma-separated IDs.
|
||||
:query string attendee_name: Only return positions with the given value in the attendee_name field. Also, add-on
|
||||
products positions are shown if they refer to an attendee with the given name.
|
||||
:query string secret: Only return positions with the given ticket secret.
|
||||
:query string order__status: Only return positions with the given order status.
|
||||
:query string order__status__in: Only return positions with one the given comma-separated order status.
|
||||
:query boolean has_checkin: If set to ``true`` or ``false``, only return positions that have or have not been
|
||||
checked in already.
|
||||
:query integer subevent: Only return positions of the sub-event with the given ID
|
||||
:query integer subevent__in: Only return positions of one of the sub-events with the given comma-separated IDs
|
||||
:query integer addon_to: Only return positions that are add-ons to the position with the given ID.
|
||||
:query integer addon_to__in: Only return positions that are add-ons to one of the positions with the given
|
||||
comma-separated IDs.
|
||||
:query string voucher: Only return positions with a specific voucher.
|
||||
:query string voucher__code: Only return positions with a specific voucher code.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param list: The ID of the check-in list to look for
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested check-in list does not exist.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(list)/positions/(id)/
|
||||
|
||||
Returns information on one order position, identified by its internal ID.
|
||||
The result is the same as the :ref:`order-position-resource`, with the following differences:
|
||||
|
||||
* The ``checkins`` value will only include check-ins for the selected list.
|
||||
|
||||
* An additional boolean property ``require_attention`` will inform you whether either the order or the item
|
||||
have the ``checkin_attention`` flag set.
|
||||
|
||||
* If ``attendee_name`` is empty, it will automatically fall back to values from a parent product or from invoice
|
||||
addresses.
|
||||
|
||||
**Instead of an ID, you can also use the ``secret`` field as the lookup parameter.**
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/positions/23442/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 23442,
|
||||
"order": "ABC12",
|
||||
"positionid": 1,
|
||||
"item": 1345,
|
||||
"variation": null,
|
||||
"price": "23.00",
|
||||
"attendee_name": "Peter",
|
||||
"attendee_name_parts": {
|
||||
"full_name": "Peter",
|
||||
},
|
||||
"attendee_email": null,
|
||||
"voucher": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": null,
|
||||
"tax_value": "0.00",
|
||||
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
"pseudonymization_id": "MQLJvANO3B",
|
||||
"seat": null,
|
||||
"checkins": [
|
||||
{
|
||||
"list": 1,
|
||||
"datetime": "2017-12-25T12:45:23Z",
|
||||
"auto_checked_in": true
|
||||
}
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"question": 12,
|
||||
"answer": "Foo",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"downloads": [
|
||||
{
|
||||
"output": "pdf",
|
||||
"url": "https://pretix.eu/api/v1/organizers/bigevents/events/sampleconf/orderpositions/23442/download/pdf/"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param list: The ID of the check-in list to look for
|
||||
:param id: The ``id`` field of the order position to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested order position or check-in list does not exist.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(list)/positions/(id)/redeem/
|
||||
|
||||
Tries to redeem an order position, identified by its internal ID, i.e. checks the attendee in. This endpoint
|
||||
accepts a number of optional requests in the body.
|
||||
|
||||
**Instead of an ID, you can also use the ``secret`` field as the lookup parameter.**
|
||||
|
||||
:<json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
|
||||
you do not implement question handling in your user interface, you **must**
|
||||
set this to ``false``. In that case, questions will just be ignored. Defaults
|
||||
to ``true``.
|
||||
:<json boolean canceled_supported: When this parameter is set to ``true``, the response code ``canceled`` may be
|
||||
returned. Otherwise, canceled orders will return ``unpaid``.
|
||||
:<json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
|
||||
:<json boolean force: Specifies that the check-in should succeed regardless of previous check-ins or required
|
||||
questions that have not been filled. Defaults to ``false``.
|
||||
:<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
|
||||
:<json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
|
||||
Defaults to ``false`` and only works when ``include_pending`` is set on the check-in
|
||||
list.
|
||||
:<json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
|
||||
this request twice with the same nonce, the second request will also succeed but will always
|
||||
create only one check-in object even when the previous request was successful as well. This
|
||||
allows for a certain level of idempotency and enables you to re-try after a connection failure.
|
||||
:<json object answers: If questions are supported/required, you may/must supply a mapping of question IDs to their
|
||||
respective answers. The answers should always be strings. In case of (multiple-)choice-type
|
||||
answers, the string should contain the (comma-separated) IDs of the selected options.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/checkinlists/1/positions/234/redeem/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
{
|
||||
"force": false,
|
||||
"ignore_unpaid": false,
|
||||
"nonce": "Pvrk50vUzQd0DhdpNRL4I4OcXsvg70uA",
|
||||
"datetime": null,
|
||||
"questions_supported": true,
|
||||
"canceled_supported": true,
|
||||
"answers": {
|
||||
"4": "XS"
|
||||
}
|
||||
}
|
||||
|
||||
**Example successful response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": "ok",
|
||||
"position": {
|
||||
…
|
||||
}
|
||||
}
|
||||
|
||||
**Example response with required questions**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 400 Bad Request
|
||||
Content-Type: text/json
|
||||
|
||||
{
|
||||
"status": "incomplete",
|
||||
"position": {
|
||||
…
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"id": 1,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": true,
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 0,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 1,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 2,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
**Example error response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/json
|
||||
|
||||
{
|
||||
"status": "error",
|
||||
"reason": "unpaid",
|
||||
"position": {
|
||||
…
|
||||
}
|
||||
}
|
||||
|
||||
Possible error reasons:
|
||||
|
||||
* ``unpaid`` - Ticket is not paid for
|
||||
* ``canceled`` – Ticket is canceled or expired. This reason is only sent when your request sets
|
||||
``canceled_supported`` to ``true``, otherwise these orders return ``unpaid``.
|
||||
* ``already_redeemed`` - Ticket already has been redeemed
|
||||
* ``product`` - Tickets with this product may not be scanned at this device
|
||||
* ``rules`` - Check-in prevented by a user-defined rule
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param list: The ID of the check-in list to look for
|
||||
:param id: The ``id`` field of the order position to fetch
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: Invalid or incomplete request, see above
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested order position or check-in list does not exist.
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
.. spelling:: fullname
|
||||
|
||||
.. _`rest-devices`:
|
||||
|
||||
Devices
|
||||
=======
|
||||
|
||||
See also :ref:`rest-deviceauth`.
|
||||
|
||||
Device resource
|
||||
----------------
|
||||
|
||||
The device resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
device_id integer Internal ID of the device within this organizer
|
||||
unique_serial string Unique identifier of this device
|
||||
name string Device name
|
||||
all_events boolean Whether this device has access to all events
|
||||
limit_events list List of event slugs this device has access to
|
||||
hardware_brand string Device hardware manufacturer (read-only)
|
||||
hardware_model string Device hardware model (read-only)
|
||||
software_brand string Device software product (read-only)
|
||||
software_version string Device software version (read-only)
|
||||
created datetime Creation time
|
||||
initialized datetime Time of initialization (or ``null``)
|
||||
initialization_token string Token for initialization
|
||||
revoked boolean Whether this device no longer has access
|
||||
security_profile string The name of a supported security profile restricting API access
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Device endpoints
|
||||
----------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/devices/
|
||||
|
||||
Returns a list of all devices within a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/devices/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"device_id": 1,
|
||||
"unique_serial": "UOS3GNZ27O39V3QS",
|
||||
"initialization_token": "frkso3m2w58zuw70",
|
||||
"all_events": false,
|
||||
"limit_events": [
|
||||
"museum"
|
||||
],
|
||||
"revoked": false,
|
||||
"name": "Scanner",
|
||||
"created": "2020-09-18T14:17:40.971519Z",
|
||||
"initialized": "2020-09-18T14:17:44.190021Z",
|
||||
"security_profile": "full",
|
||||
"hardware_brand": "Zebra",
|
||||
"hardware_model": "TC25",
|
||||
"software_brand": "pretixSCAN",
|
||||
"software_version": "1.5.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/devices/(device_id)/
|
||||
|
||||
Returns information on one device, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/devices/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"device_id": 1,
|
||||
"unique_serial": "UOS3GNZ27O39V3QS",
|
||||
"initialization_token": "frkso3m2w58zuw70",
|
||||
"all_events": false,
|
||||
"limit_events": [
|
||||
"museum"
|
||||
],
|
||||
"revoked": false,
|
||||
"name": "Scanner",
|
||||
"created": "2020-09-18T14:17:40.971519Z",
|
||||
"initialized": "2020-09-18T14:17:44.190021Z",
|
||||
"security_profile": "full",
|
||||
"hardware_brand": "Zebra",
|
||||
"hardware_model": "TC25",
|
||||
"software_brand": "pretixSCAN",
|
||||
"software_version": "1.5.1"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param device_id: The ``device_id`` field of the device to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/devices/
|
||||
|
||||
Creates a new device
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/devices/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Scanner",
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"device_id": 1,
|
||||
"unique_serial": "UOS3GNZ27O39V3QS",
|
||||
"initialization_token": "frkso3m2w58zuw70",
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"revoked": false,
|
||||
"name": "Scanner",
|
||||
"created": "2020-09-18T14:17:40.971519Z",
|
||||
"security_profile": "full",
|
||||
"initialized": null
|
||||
"hardware_brand": null,
|
||||
"hardware_model": null,
|
||||
"software_brand": null,
|
||||
"software_version": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a device for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The device could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/devices/(device_id)/
|
||||
|
||||
Update a device.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/devices/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"name": "Foo"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Foo",
|
||||
...
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param device_id: The ``device_id`` field of the device to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The device could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
.. spelling::
|
||||
|
||||
geo
|
||||
lat
|
||||
lon
|
||||
|
||||
Events
|
||||
======
|
||||
|
||||
@@ -21,7 +15,6 @@ name multi-lingual string The event's ful
|
||||
slug string A short form of the name, used e.g. in URLs.
|
||||
live boolean If ``true``, the event ticket shop is publicly
|
||||
available.
|
||||
testmode boolean If ``true``, the ticket shop is in test mode.
|
||||
currency string The currency this event is handled in.
|
||||
date_from datetime The event's start date
|
||||
date_to datetime The event's end date (or ``null``)
|
||||
@@ -31,86 +24,22 @@ is_public boolean If ``true``, th
|
||||
presale_start datetime The date at which the ticket shop opens (or ``null``)
|
||||
presale_end datetime The date at which the ticket shop closes (or ``null``)
|
||||
location multi-lingual string The event location (or ``null``)
|
||||
geo_lat float Latitude of the location (or ``null``)
|
||||
geo_lon float Longitude of the location (or ``null``)
|
||||
has_subevents boolean ``true`` if the event series feature is active for this
|
||||
event. Cannot change after event is created.
|
||||
meta_data object Values set for organizer-specific meta data parameters.
|
||||
plugins list A list of package names of the enabled plugins for this
|
||||
event.
|
||||
seating_plan integer If reserved seating is in use, the ID of a seating
|
||||
plan. Otherwise ``null``.
|
||||
seat_category_mapping object An object mapping categories of the seating plan
|
||||
(strings) to items in the event (integers or ``null``).
|
||||
timezone string Event timezone name
|
||||
item_meta_properties object Item-specific meta data parameters and default values.
|
||||
valid_keys object Cryptographic keys for non-default signature schemes.
|
||||
For performance reason, value is omitted in lists and
|
||||
only contained in detail views. Value can be cached.
|
||||
sales_channels list A list of sales channels this event is available for
|
||||
sale on.
|
||||
has_subevents boolean ``True`` if the event series feature is active for this
|
||||
event
|
||||
meta_data dict Values set for organizer-specific meta data parameters.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The ``meta_data`` field has been added.
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The ``plugins`` field has been added.
|
||||
The operations POST, PATCH, PUT and DELETE have been added.
|
||||
|
||||
.. versionchanged:: 2.1
|
||||
|
||||
Filters have been added to the list of events.
|
||||
|
||||
.. versionchanged:: 2.5
|
||||
|
||||
The ``testmode`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2.8
|
||||
|
||||
When cloning events, the ``testmode`` attribute will now be cloned, too.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attributes ``seating_plan`` and ``seat_category_mapping`` have been added.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
|
||||
The attributes ``geo_lat`` and ``geo_lon`` have been added.
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
|
||||
The attribute ``timezone`` has been added.
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
|
||||
The attribute ``item_meta_properties`` has been added.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
|
||||
The attribute ``valid_keys`` has been added.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
|
||||
The attribute ``sales_channels`` has been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
|
||||
The events resource can now be filtered by meta data attributes.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/
|
||||
|
||||
Returns a list of all events within a given organizer the authenticated user/token has access to.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
@@ -136,7 +65,6 @@ Endpoints
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
@@ -145,44 +73,13 @@ Endpoints
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"has_subevents": false,
|
||||
"meta_data": {},
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"timezone": "Europe/Berlin",
|
||||
"item_meta_properties": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.banktransfer",
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal",
|
||||
"pretix.plugins.ticketoutputpdf"
|
||||
],
|
||||
"sales_channels": [
|
||||
"web",
|
||||
"pretixpos",
|
||||
"resellers"
|
||||
]
|
||||
"meta_data": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query page: The page number in case of a multi-page result set, default is 1
|
||||
:query is_public: If set to ``true``/``false``, only events with a matching value of ``is_public`` are returned.
|
||||
:query live: If set to ``true``/``false``, only events with a matching value of ``live`` are returned.
|
||||
:query has_subevents: If set to ``true``/``false``, only events with a matching value of ``has_subevents`` are returned.
|
||||
:query is_future: If set to ``true`` (``false``), only events that happen currently or in the future are (not) returned. Event series are never (always) returned.
|
||||
:query is_past: If set to ``true`` (``false``), only events that are over are (not) returned. Event series are never (always) returned.
|
||||
:query ends_after: If set to a date and time, only events that happen during of after the given time are returned. Event series are never returned.
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``date_from`` and
|
||||
``slug``. Keep in mind that ``date_from`` of event series does not really tell you anything.
|
||||
Default: ``slug``.
|
||||
:query array attr[meta_data_key]: By providing the key and value of a meta data attribute, the list of events will
|
||||
only contain the events matching the set criteria. Providing ``?attr[Format]=Seminar`` would return only those
|
||||
events having set their ``Format`` meta data to ``Seminar``, ``?attr[Format]=`` only those, that have no value
|
||||
set. Please note that this filter will respect default values set on organizer level.
|
||||
:query sales_channel: If set to a sales channel identifier, only events allowed to be sold on the specified sales channel are returned.
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
@@ -192,8 +89,6 @@ Endpoints
|
||||
|
||||
Returns information on one event, identified by its slug.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
@@ -214,7 +109,6 @@ Endpoints
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
@@ -223,30 +117,8 @@ Endpoints
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"has_subevents": false,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"meta_data": {},
|
||||
"timezone": "Europe/Berlin",
|
||||
"item_meta_properties": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.banktransfer",
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal",
|
||||
"pretix.plugins.ticketoutputpdf"
|
||||
],
|
||||
"valid_keys": {
|
||||
"pretix_sig1": [
|
||||
"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQTdBRDcvdkZBMzNFc1k0ejJQSHI3aVpQc1o4bjVkaDBhalA4Z3l6Tm1tSXM9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo="
|
||||
]
|
||||
},
|
||||
"sales_channels": [
|
||||
"web",
|
||||
"pretixpos",
|
||||
"resellers"
|
||||
]
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
@@ -254,422 +126,3 @@ Endpoints
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/
|
||||
|
||||
Creates a new event
|
||||
|
||||
Please note that events cannot be created as 'live' using this endpoint. Quotas and payment must be added to the
|
||||
event before sales can go live.
|
||||
|
||||
Permission required: "Can create events"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"has_subevents": false,
|
||||
"meta_data": {},
|
||||
"timezone": "Europe/Berlin",
|
||||
"item_meta_properties": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal"
|
||||
],
|
||||
"sales_channels": [
|
||||
"web",
|
||||
"pretixpos",
|
||||
"resellers"
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"has_subevents": false,
|
||||
"meta_data": {},
|
||||
"timezone": "Europe/Berlin",
|
||||
"item_meta_properties": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal"
|
||||
],
|
||||
"sales_channels": [
|
||||
"web",
|
||||
"pretixpos",
|
||||
"resellers"
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create.
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/clone/
|
||||
|
||||
Creates a new event with properties as set in the request body. The properties that are copied are: ``is_public``,
|
||||
``testmode``, ``has_subevents``, settings, plugin settings, items, variations, add-ons, quotas, categories, tax rules, questions.
|
||||
|
||||
If the ``plugins``, ``has_subevents`` and/or ``is_public`` fields are present in the post body this will determine their
|
||||
value. Otherwise their value will be copied from the existing event.
|
||||
|
||||
Please note that you can only copy from events under the same organizer.
|
||||
|
||||
Permission required: "Can create events"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/clone/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"has_subevents": false,
|
||||
"meta_data": {},
|
||||
"timezone": "Europe/Berlin",
|
||||
"item_meta_properties": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal"
|
||||
],
|
||||
"sales_channels": [
|
||||
"web",
|
||||
"pretixpos",
|
||||
"resellers"
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"has_subevents": false,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"meta_data": {},
|
||||
"timezone": "Europe/Berlin",
|
||||
"item_meta_properties": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal"
|
||||
],
|
||||
"sales_channels": [
|
||||
"web",
|
||||
"pretixpos",
|
||||
"resellers"
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create.
|
||||
:param event: The ``slug`` field of the event to copy settings and items from.
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/
|
||||
|
||||
Updates an event
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"plugins": [
|
||||
"pretix.plugins.banktransfer",
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal",
|
||||
"pretix.plugins.pretixdroid"
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
"slug": "sampleconf",
|
||||
"live": false,
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"is_public": false,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"has_subevents": false,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"meta_data": {},
|
||||
"timezone": "Europe/Berlin",
|
||||
"item_meta_properties": {},
|
||||
"plugins": [
|
||||
"pretix.plugins.banktransfer",
|
||||
"pretix.plugins.stripe",
|
||||
"pretix.plugins.paypal",
|
||||
"pretix.plugins.pretixdroid"
|
||||
],
|
||||
"sales_channels": [
|
||||
"web",
|
||||
"pretixpos",
|
||||
"resellers"
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to update
|
||||
:param event: The ``slug`` field of the event to update
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/
|
||||
|
||||
Delete an event. Note that events with orders cannot be deleted to ensure data integrity.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
Event settings
|
||||
--------------
|
||||
|
||||
pretix events have lots and lots of parameters of different types that are stored in a key-value store on our system.
|
||||
Since many of these settings depend on each other in complex ways, we can not give direct access to all of these
|
||||
settings through the API. However, we do expose many of the simple and useful flags through the API.
|
||||
|
||||
Please note that the available settings flags change between pretix versions and also between events, depending on the
|
||||
installed plugins, and we do not give a guarantee on backwards-compatibility like with other parts of the API.
|
||||
Therefore, we're also not including a list of the options here, but instead recommend to look at the endpoint output
|
||||
to see available options. The ``explain=true`` flag enables a verbose mode that provides you with human-readable
|
||||
information about the properties.
|
||||
|
||||
.. note:: Please note that this is not a complete representation of all event settings. You will find more settings
|
||||
in the web interface.
|
||||
|
||||
.. warning:: This API is intended for advanced users. Even though we take care to validate your input, you will be
|
||||
able to break your event using this API by creating situations of conflicting settings. Please take care.
|
||||
|
||||
.. versionchanged:: 3.6
|
||||
|
||||
Initial support for settings has been added to the API.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/settings/
|
||||
|
||||
Get current values of event settings.
|
||||
|
||||
Permission required: "Can change event settings" (Exception: with device auth, *some* settings can always be *read*.)
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/settings/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example standard response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"imprint_url": "https://pretix.eu",
|
||||
…
|
||||
}
|
||||
|
||||
**Example verbose response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"imprint_url":
|
||||
{
|
||||
"value": "https://pretix.eu",
|
||||
"label": "Imprint URL",
|
||||
"help_text": "This should point e.g. to a part of your website that has your contact details and legal information."
|
||||
}
|
||||
},
|
||||
…
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to access
|
||||
:param event: The ``slug`` field of the event to access
|
||||
:query explain: Set to ``true`` to enable verbose response mode
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/settings/
|
||||
|
||||
Updates event settings. Note that ``PUT`` is not allowed here, only ``PATCH``.
|
||||
|
||||
.. warning::
|
||||
|
||||
Settings can be stored at different levels in pretix. If a value is not set on event level, a default setting
|
||||
from a higher level (organizer, global) will be returned. If you explicitly set a setting on event level, it
|
||||
will no longer be inherited from the higher levels. Therefore, we recommend you to send only settings that you
|
||||
explicitly want to set on event level. To unset a settings, pass ``null``.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/settings/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"imprint_url": "https://example.org/imprint/"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"imprint_url": "https://example.org/imprint/",
|
||||
…
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to update
|
||||
:param event: The ``slug`` field of the event to update
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The event could not be updated due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
.. spelling:: checkin
|
||||
|
||||
Data exporters
|
||||
==============
|
||||
|
||||
pretix and it's plugins include a number of data exporters that allow you to bulk download various data from pretix in
|
||||
different formats. This page shows you how to use these exporters through the API.
|
||||
|
||||
.. versionchanged:: 3.13
|
||||
|
||||
This feature has been added to the API.
|
||||
|
||||
.. warning::
|
||||
|
||||
While we consider the methods listed on this page to be a stable API, the availability and specific input field
|
||||
requirements of individual exporters is **not considered a stable API**. Specific exporters and their input parameters
|
||||
may change at any time without warning.
|
||||
|
||||
Listing available exporters
|
||||
---------------------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/exporters/
|
||||
|
||||
Returns a list of all exporters available for a given event. You will receive a list of export methods as well as their
|
||||
supported input fields. Note that the exact type and validation requirements of the input fields are not given in the
|
||||
response, and you might need to look into the pretix web interface to figure out the exact input required.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/exporters/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"identifier": "orderlist",
|
||||
"verbose_name": "Order data",
|
||||
"input_parameters": [
|
||||
{
|
||||
"name": "_format",
|
||||
"required": true,
|
||||
"choices": [
|
||||
"xlsx",
|
||||
"orders:default",
|
||||
"orders:excel",
|
||||
"orders:semicolon",
|
||||
"positions:default",
|
||||
"positions:excel",
|
||||
"positions:semicolon",
|
||||
"fees:default",
|
||||
"fees:excel",
|
||||
"fees:semicolon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "paid_only",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/exporters/
|
||||
|
||||
Returns a list of all cross-event exporters available for a given organizer. You will receive a list of export methods as well as their
|
||||
supported input fields. Note that the exact type and validation requirements of the input fields are not given in the
|
||||
response, and you might need to look into the pretix web interface to figure out the exact input required.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/exporters/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"identifier": "orderlist",
|
||||
"verbose_name": "Order data",
|
||||
"input_parameters": [
|
||||
{
|
||||
"name": "events",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "_format",
|
||||
"required": true,
|
||||
"choices": [
|
||||
"xlsx",
|
||||
"orders:default",
|
||||
"orders:excel",
|
||||
"orders:semicolon",
|
||||
"positions:default",
|
||||
"positions:excel",
|
||||
"positions:semicolon",
|
||||
"fees:default",
|
||||
"fees:excel",
|
||||
"fees:semicolon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "paid_only",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
Running an export
|
||||
-----------------
|
||||
|
||||
Since exports often include large data sets, they might take longer than the duration of an HTTP request. Therefore,
|
||||
creating an export is a two-step process. First you need to start an export task with one of the following to API
|
||||
endpoints:
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/exporters/(identifier)/run/
|
||||
|
||||
Starts an export task. If your input parameters validate correctly, a ``202 Accepted`` status code is returned.
|
||||
The body points you to the download URL of the result.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/exporters/orderlist/run/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"_format": "xlsx"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"download": "https://pretix.eu/api/v1/organizers/bigevents/events/sampleconf/orderlist/download/29891ede-196f-4942-9e26-d055a36e98b8/3f279f13-c198-4137-b49b-9b360ce9fcce/"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param identifier: The ``identifier`` field of the exporter to run
|
||||
:statuscode 202: no error
|
||||
:statuscode 400: Invalid input options
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/exporters/(identifier)/run/
|
||||
|
||||
The endpoint for organizer-level exports works just like event-level exports (see above).
|
||||
|
||||
|
||||
Downloading the result
|
||||
----------------------
|
||||
|
||||
When starting an export, you receive a ``url`` for downloading the result. Running a ``GET`` request on that result will
|
||||
yield one of the following status codes:
|
||||
|
||||
* ``200 OK`` – The export succeeded. The body will be your resulting file. Might be large!
|
||||
* ``409 Conflict`` – Your export is still running. The body will be JSON with the structure ``{"status": "running", "percentage": 40}``. ``percentage`` can be ``null`` if it is not known and ``status`` can be ``waiting`` before the task is actually being processed. Please retry, but wait at least one second before you do.
|
||||
* ``410 Gone`` – Running the export has failed permanently. The body will be JSON with the structure ``{"status": "failed", "message": "Error message"}``
|
||||
* ``404 Not Found`` – The export does not exist / is expired.
|
||||
|
||||
.. warning::
|
||||
|
||||
Running exports puts a lot of stress on the system, we kindly ask you not to run more than two exports at the same time.
|
||||
|
||||
@@ -1,313 +0,0 @@
|
||||
.. _`rest-giftcards`:
|
||||
|
||||
Gift cards
|
||||
==========
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The gift card resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the gift card
|
||||
secret string Gift card code (can not be modified later)
|
||||
value money (string) Current gift card value
|
||||
currency string Currency of the value (can not be modified later)
|
||||
testmode boolean Whether this is a test gift card
|
||||
expires datetime Expiry date (or ``null``)
|
||||
conditions string Special terms and conditions for this card (or ``null``)
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
The gift card transaction resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the gift card transaction
|
||||
datetime datetime Creation date of the transaction
|
||||
value money (string) Transaction amount
|
||||
event string Event slug, if the gift card was used in the web shop (or ``null``)
|
||||
order string Order code, if the gift card was used in the web shop (or ``null``)
|
||||
text string Custom text of the transaction (or ``null``)
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
The transaction list endpoint was added.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/giftcards/
|
||||
|
||||
Returns a list of all gift cards issued by a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/giftcards/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"secret": "HLBYVELFRC77NCQY",
|
||||
"currency": "EUR",
|
||||
"testmode": false,
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"value": "13.37"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string secret: Only show gift cards with the given secret.
|
||||
:query boolean testmode: Filter for gift cards that are (not) in test mode.
|
||||
:query boolean include_accepted: Also show gift cards issued by other organizers that are accepted by this organizer.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/giftcards/(id)/
|
||||
|
||||
Returns information on one gift card, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/giftcards/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"secret": "HLBYVELFRC77NCQY",
|
||||
"currency": "EUR",
|
||||
"testmode": false,
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"value": "13.37"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param id: The ``id`` field of the gift card to fetch
|
||||
:query boolean include_accepted: Also show gift cards issued by other organizers that are accepted by this organizer.
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/giftcards/
|
||||
|
||||
Creates a new gift card
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/giftcards/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"secret": "HLBYVELFRC77NCQY",
|
||||
"currency": "EUR",
|
||||
"value": "13.37"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"secret": "HLBYVELFRC77NCQY",
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"value": "13.37"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a gift card for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The gift card could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/giftcards/(id)/
|
||||
|
||||
Update a gift card. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id``, ``secret``, ``testmode``, and ``currency`` fields. Be
|
||||
careful when modifying the ``value`` field to avoid race conditions. We recommend to use the ``transact`` method
|
||||
described below.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/giftcards/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"value": "14.00"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"secret": "HLBYVELFRC77NCQY",
|
||||
"testmode": false,
|
||||
"currency": "EUR",
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"value": "14.00"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the gift card to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The gift card could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/giftcards/(id)/transact/
|
||||
|
||||
Atomically change the value of a gift card. A positive amount will increase the value of the gift card,
|
||||
a negative amount will decrease it.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/giftcards/1/transact/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 79
|
||||
|
||||
{
|
||||
"value": "2.00",
|
||||
"text": "Optional value explaining the transaction"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"secret": "HLBYVELFRC77NCQY",
|
||||
"currency": "EUR",
|
||||
"testmode": false,
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"value": "15.37"
|
||||
}
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
This endpoint now returns status code ``409`` if the transaction would lead to a negative gift card value.
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the gift card to modify
|
||||
:query boolean include_accepted: Also show gift cards issued by other organizers that are accepted by this organizer.
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The gift card could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
||||
:statuscode 409: There is not sufficient credit on the gift card.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/giftcards/(id)/transactions/
|
||||
|
||||
List all transactions of a gift card.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/giftcards/1/transactions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 82,
|
||||
"datetime": "2020-06-22T15:41:42.800534Z",
|
||||
"value": "50.00",
|
||||
"event": "democon",
|
||||
"order": "FXQYW",
|
||||
"text": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to view
|
||||
:param id: The ``id`` field of the gift card to view
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
@@ -10,23 +10,10 @@ Resources and endpoints
|
||||
taxrules
|
||||
categories
|
||||
items
|
||||
item_variations
|
||||
item_bundles
|
||||
item_add-ons
|
||||
questions
|
||||
question_options
|
||||
quotas
|
||||
orders
|
||||
invoices
|
||||
vouchers
|
||||
checkinlists
|
||||
waitinglist
|
||||
giftcards
|
||||
carts
|
||||
teams
|
||||
devices
|
||||
webhooks
|
||||
seatingplans
|
||||
exporters
|
||||
billing_invoices
|
||||
billing_var
|
||||
|
||||
@@ -13,7 +13,7 @@ Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
number string Invoice number (with prefix)
|
||||
order string Order code of the order this invoice belongs to
|
||||
is_cancellation boolean ``true``, if this invoice is the cancellation of a
|
||||
is_cancellation boolean ``True``, if this invoice is the cancellation of a
|
||||
different invoice.
|
||||
invoice_from string Sender address
|
||||
invoice_to string Receiver address
|
||||
@@ -28,7 +28,6 @@ payment_provider_text string Text to be prin
|
||||
payment information
|
||||
footer_text string Text to be printed in the page footer area
|
||||
lines list of objects The actual invoice contents
|
||||
├ position integer Number of the line within an invoice.
|
||||
├ description string Text representing the invoice line (e.g. product name)
|
||||
├ gross_value money (string) Price including taxes
|
||||
├ tax_value money (string) Tax amount included
|
||||
@@ -64,11 +63,6 @@ internal_reference string Customer's refe
|
||||
The attribute ``internal_reference`` has been added.
|
||||
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
|
||||
The attribute ``lines.number`` has been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
@@ -113,7 +107,6 @@ Endpoints
|
||||
"footer_text": "Big Events LLC - Registration No. 123456 - VAT ID: EU0987654321",
|
||||
"lines": [
|
||||
{
|
||||
"position": 1,
|
||||
"description": "Budget Ticket",
|
||||
"gross_value": "23.00",
|
||||
"tax_value": "0.00",
|
||||
@@ -178,7 +171,6 @@ Endpoints
|
||||
"footer_text": "Big Events LLC - Registration No. 123456 - VAT ID: EU0987654321",
|
||||
"lines": [
|
||||
{
|
||||
"position": 1,
|
||||
"description": "Budget Ticket",
|
||||
"gross_value": "23.00",
|
||||
"tax_value": "0.00",
|
||||
@@ -229,61 +221,5 @@ Endpoints
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 409: The file is not yet ready and will now be prepared. Retry the request after waiting for a few
|
||||
:statuscode 409: The file is not yet ready and will now be prepared. Retry the request after waiting vor a few
|
||||
seconds.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/invoices/(invoice_no)/reissue/
|
||||
|
||||
Cancels the invoice and creates a new one.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/00001/reissue/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
Content-Type: application/pdf
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param invoice_no: The ``invoice_no`` field of the invoice to reissue
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The invoice has already been canceled
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/invoices/(invoice_no)/regenerate/
|
||||
|
||||
Re-generates the invoice from order data.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/00001/regenerate/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
Content-Type: application/pdf
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param invoice_no: The ``invoice_no`` field of the invoice to regenerate
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The invoice has already been canceled
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
Item add-ons
|
||||
============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
With add-ons, you can specify products that can be bought as an addition to this specific product. For example, if you
|
||||
host a conference with a base conference ticket and a number of workshops, you could define the workshops as add-ons to
|
||||
the conference ticket. With this configuration, the workshops cannot be bought on their own but only in combination with
|
||||
a conference ticket. You can here specify categories of products that can be used as add-ons to this product. You can
|
||||
also specify the minimum and maximum number of add-ons of the given category that can or need to be chosen. The user can
|
||||
buy every add-on from the category at most once. If an add-on product has multiple variations, only one of them can be
|
||||
bought.
|
||||
The add-ons resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the add-on
|
||||
addon_category integer Internal ID of the item category the add-on can be
|
||||
chosen from.
|
||||
min_count integer The minimal number of add-ons that need to be chosen.
|
||||
max_count integer The maximal number of add-ons that can be chosen.
|
||||
position integer An integer, used for sorting
|
||||
multi_allowed boolean Adding the same item multiple times is allowed
|
||||
price_included boolean Adding this add-on to the item is free
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
This resource has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/addons/
|
||||
|
||||
Returns a list of all add-ons for a given item.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/11/addons/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 3,
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 0,
|
||||
"multi_allowed": false,
|
||||
"price_included": true
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"addon_category": 2,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"multi_allowed": false,
|
||||
"price_included": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/item does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/addons/(id)/
|
||||
|
||||
Returns information on one add-on, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/1/addons/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"multi_allowed": false,
|
||||
"price_included": true
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:param id: The ``id`` field of the add-on to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/bigevents/events/sampleconf/items/1/addons/
|
||||
|
||||
Creates a new add-on
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/(organizer)/events/(event)/items/(item)/addons/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"multi_allowed": false,
|
||||
"price_included": true
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"multi_allowed": false,
|
||||
"price_included": true
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a add-on for
|
||||
:param event: The ``slug`` field of the event to create a add-on for
|
||||
:param item: The ``id`` field of the item to create a add-on for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The add-on could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/addon/(id)/
|
||||
|
||||
Update an add-on. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/items/1/addons/3/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"min_count": 0,
|
||||
"max_count": 10
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"addon_category": 1,
|
||||
"min_count": 0,
|
||||
"max_count": 10,
|
||||
"position": 1,
|
||||
"multi_allowed": false,
|
||||
"price_included": true
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param item: The ``id`` field of the item to modify
|
||||
:param id: The ``id`` field of the add-on to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The add-on could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/items/(id)/addons/(id)/
|
||||
|
||||
Delete an add-on.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/addons/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the item to modify
|
||||
:param id: The ``id`` field of the add-on to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
@@ -1,242 +0,0 @@
|
||||
Item bundles
|
||||
============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
With bundles, you can specify products that are included within other products. There are two premier use cases of this:
|
||||
|
||||
* Package discounts. For example, you could offer a discounted package that includes three tickets but can only be
|
||||
bought as a whole. With a bundle including three times the usual product, the package will automatically pull three
|
||||
sub-items into the cart, making sure of correct quota calculation and issuance of the correct number of tickets.
|
||||
|
||||
* Tax splitting. For example, if your conference ticket includes a part that is subject to different taxation and that
|
||||
you need to put on the invoice separately. When you putting a "designated price" on a bundled sub-item, pretix will
|
||||
use that price to show a split taxation.
|
||||
|
||||
The bundles resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the bundling configuration
|
||||
bundled_item integer Internal ID of the item that is included.
|
||||
bundled_variation integer Internal ID of the variation of the item (or ``null``).
|
||||
count integer Number of items included
|
||||
designated_price money (string) Designated price of the bundled product. This will be
|
||||
used to split the price of the base item e.g. for mixed
|
||||
taxation. This is not added to the price.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
|
||||
This resource has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/bundles/
|
||||
|
||||
Returns a list of all bundles for a given item.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/11/bundles/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 1,
|
||||
"designated_price": "0.00"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/item does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/bundles/(id)/
|
||||
|
||||
Returns information on one bundle configuration, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/1/bundles/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:param id: The ``id`` field of the bundle to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/bigevents/events/sampleconf/items/1/bundles/
|
||||
|
||||
Creates a new bundle configuration
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/(organizer)/events/(event)/items/(item)/bundles/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a bundle-configuration for
|
||||
:param event: The ``slug`` field of the event to create a bundle configuration for
|
||||
:param item: The ``id`` field of the item to create a bundle configuration for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The bundle could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/bundles/(id)/
|
||||
|
||||
Update a bundle configuration. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all
|
||||
fields of the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields
|
||||
that you want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/items/1/bundles/3/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"count": 2
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"bundled_item": 3,
|
||||
"bundled_variation": null,
|
||||
"count": 2,
|
||||
"designated_price": "1.50"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param item: The ``id`` field of the item to modify
|
||||
:param id: The ``id`` field of the bundle to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The bundle configuration could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/items/(id)/bundles/(id)/
|
||||
|
||||
Delete a bundle configuration.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/bundles/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the item to modify
|
||||
:param id: The ``id`` field of the bundle to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
@@ -1,268 +0,0 @@
|
||||
Item variations
|
||||
===============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Variations of items can be use for products (items) that are available in different sizes, colors or other variations
|
||||
of the same product.
|
||||
The variations resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the variation
|
||||
default_price money (string) The price set directly for this variation or ``null``
|
||||
price money (string) The price used for this variation. This is either the
|
||||
same as ``default_price`` if that value is set or equal
|
||||
to the item's ``default_price`` (read-only).
|
||||
original_price money (string) An original price, shown for comparison, not used
|
||||
for price calculations (or ``null``).
|
||||
active boolean If ``false``, this variation will not be sold or shown.
|
||||
description multi-lingual string A public description of the variation. May contain
|
||||
Markdown syntax or can be ``null``.
|
||||
position integer An integer, used for sorting
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The attribute ``original_price`` has been added.
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
This resource has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/variations/
|
||||
|
||||
Returns a list of all variations for a given item.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/11/variations/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"value": {
|
||||
"en": "S"
|
||||
},
|
||||
"active": true,
|
||||
"description": {
|
||||
"en": "Test2"
|
||||
},
|
||||
"position": 0,
|
||||
"default_price": "223.00",
|
||||
"price": 223.0,
|
||||
"original_price": null,
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"value": {
|
||||
"en": "L"
|
||||
},
|
||||
"active": true,
|
||||
"description": {},
|
||||
"position": 1,
|
||||
"default_price": null,
|
||||
"price": 15.0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query boolean active: If set to ``true`` or ``false``, only items with this value for the field ``active`` will be
|
||||
returned.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/item does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/variations/(id)/
|
||||
|
||||
Returns information on one variation, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"value": {
|
||||
"en": "Student"
|
||||
},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param item: The ``id`` field of the item to fetch
|
||||
:param id: The ``id`` field of the variation to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/variations/
|
||||
|
||||
Creates a new variation
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a variation for
|
||||
:param event: The ``slug`` field of the event to create a variation for
|
||||
:param item: The ``id`` field of the item to create a variation for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The variation could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/variations/(id)/
|
||||
|
||||
Update a variation. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` and the ``price`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"active": false,
|
||||
"position": 1
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": false,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the item to modify
|
||||
:param id: The ``id`` field of the variation to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The variation could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/items/(id)/variations/(id)/
|
||||
|
||||
Delete a variation.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the item to modify
|
||||
:param id: The ``id`` field of the variation to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
@@ -1,5 +1,3 @@
|
||||
.. _rest-items:
|
||||
|
||||
Items
|
||||
=====
|
||||
|
||||
@@ -16,43 +14,35 @@ Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the item
|
||||
name multi-lingual string The item's visible name
|
||||
internal_name string An optional name that is only used in the backend
|
||||
default_price money (string) The item price that is applied if the price is not
|
||||
overwritten by variations or other options.
|
||||
category integer The ID of the category this item belongs to
|
||||
(or ``null``).
|
||||
active boolean If ``false``, the item is hidden from all public lists
|
||||
active boolean If ``False``, the item is hidden from all public lists
|
||||
and will not be sold.
|
||||
description multi-lingual string A public description of the item. May contain Markdown
|
||||
syntax or can be ``null``.
|
||||
free_price boolean If ``true``, customers can change the price at which
|
||||
free_price boolean If ``True``, customers can change the price at which
|
||||
they buy the product (however, the price can't be set
|
||||
lower than the price defined by ``default_price`` or
|
||||
otherwise).
|
||||
tax_rate decimal (string) The VAT rate to be applied for this item (read-only,
|
||||
set through ``tax_rule``).
|
||||
tax_rate decimal (string) The VAT rate to be applied for this item.
|
||||
tax_rule integer The internal ID of the applied tax rule (or ``null``).
|
||||
admission boolean ``true`` for items that grant admission to the event
|
||||
(such as primary tickets) and ``false`` for others
|
||||
admission boolean ``True`` for items that grant admission to the event
|
||||
(such as primary tickets) and ``False`` for others
|
||||
(such as add-ons or merchandise).
|
||||
position integer An integer, used for sorting
|
||||
picture string A product picture to be displayed in the shop
|
||||
(read-only, can be ``null``).
|
||||
sales_channels list of strings Sales channels this product is available on, such as
|
||||
``"web"`` or ``"resellers"``. Defaults to ``["web"]``.
|
||||
available_from datetime The first date time at which this item can be bought
|
||||
(or ``null``).
|
||||
available_until datetime The last date time at which this item can be bought
|
||||
(or ``null``).
|
||||
hidden_if_available integer The internal ID of a quota object, or ``null``. If
|
||||
set, this item won't be shown publicly as long as this
|
||||
quota is available.
|
||||
require_voucher boolean If ``true``, this item can only be bought using a
|
||||
require_voucher boolean If ``True``, this item can only be bought using a
|
||||
voucher that is specifically assigned to this item.
|
||||
hide_without_voucher boolean If ``true``, this item is only shown during the voucher
|
||||
hide_without_voucher boolean If ``True``, this item is only shown during the voucher
|
||||
redemption process, but not in the normal shop
|
||||
frontend.
|
||||
allow_cancel boolean If ``false``, customers cannot cancel orders containing
|
||||
allow_cancel boolean If ``False``, customers cannot cancel orders containing
|
||||
this item.
|
||||
min_per_order integer This product can only be bought if it is included at
|
||||
least this many times in the order (or ``null`` for no
|
||||
@@ -60,120 +50,35 @@ min_per_order integer This product ca
|
||||
max_per_order integer This product can only be bought if it is included at
|
||||
most this many times in the order (or ``null`` for no
|
||||
limitation).
|
||||
checkin_attention boolean If ``true``, the check-in app should show a warning
|
||||
checkin_attention boolean If ``True``, the check-in app should show a warning
|
||||
that this ticket requires special attention if such
|
||||
a product is being scanned.
|
||||
original_price money (string) An original price, shown for comparison, not used
|
||||
for price calculations (or ``null``).
|
||||
require_approval boolean If ``true``, orders with this product will need to be
|
||||
approved by the event organizer before they can be
|
||||
paid.
|
||||
require_bundling boolean If ``true``, this item is only available as part of bundles.
|
||||
generate_tickets boolean If ``false``, tickets are never generated for this
|
||||
product, regardless of other settings. If ``true``,
|
||||
tickets are generated even if this is a
|
||||
non-admission or add-on product, regardless of event
|
||||
settings. If this is ``null``, regular ticketing
|
||||
rules apply.
|
||||
allow_waitinglist boolean If ``false``, no waiting list will be shown for this
|
||||
product when it is sold out.
|
||||
issue_giftcard boolean If ``true``, buying this product will yield a gift card.
|
||||
show_quota_left boolean Publicly show how many tickets are still available.
|
||||
If this is ``null``, the event default is used.
|
||||
has_variations boolean Shows whether or not this item has variations.
|
||||
has_variations boolean Shows whether or not this item has variations
|
||||
(read-only).
|
||||
variations list of objects A list with one object for each variation of this item.
|
||||
Can be empty. Only writable during creation,
|
||||
use separate endpoint to modify this later.
|
||||
Can be empty.
|
||||
├ id integer Internal ID of the variation
|
||||
├ value multi-lingual string The "name" of the variation
|
||||
├ default_price money (string) The price set directly for this variation or ``null``
|
||||
├ price money (string) The price used for this variation. This is either the
|
||||
same as ``default_price`` if that value is set or equal
|
||||
to the item's ``default_price``.
|
||||
├ original_price money (string) An original price, shown for comparison, not used
|
||||
for price calculations (or ``null``).
|
||||
├ active boolean If ``false``, this variation will not be sold or shown.
|
||||
├ active boolean If ``False``, this variation will not be sold or shown.
|
||||
├ description multi-lingual string A public description of the variation. May contain
|
||||
Markdown syntax or can be ``null``.
|
||||
└ position integer An integer, used for sorting
|
||||
addons list of objects Definition of add-ons that can be chosen for this item.
|
||||
Only writable during creation,
|
||||
use separate endpoint to modify this later.
|
||||
addons list of objects Definition of add-ons that can be chosen for this item
|
||||
├ addon_category integer Internal ID of the item category the add-on can be
|
||||
chosen from.
|
||||
├ min_count integer The minimal number of add-ons that need to be chosen.
|
||||
├ max_count integer The maximal number of add-ons that can be chosen.
|
||||
├ position integer An integer, used for sorting
|
||||
├ multi_allowed boolean Adding the same item multiple times is allowed
|
||||
└ price_included boolean Adding this add-on to the item is free
|
||||
bundles list of objects Definition of bundles that are included in this item.
|
||||
Only writable during creation,
|
||||
use separate endpoint to modify this later.
|
||||
├ bundled_item integer Internal ID of the item that is included.
|
||||
├ bundled_variation integer Internal ID of the variation of the item (or ``null``).
|
||||
├ count integer Number of items included
|
||||
└ designated_price money (string) Designated price of the bundled product. This will be
|
||||
used to split the price of the base item e.g. for mixed
|
||||
taxation. This is not added to the price.
|
||||
meta_data object Values set for event-specific meta data parameters.
|
||||
├ max_count integer The maxima number of add-ons that can be chosen.
|
||||
└ position integer An integer, used for sorting
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The attribute ``original_price`` has been added for ``variations``.
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The attribute ``tax_rule`` has been added. ``tax_rate`` is kept for compatibility. The attribute
|
||||
``checkin_attention`` has been added.
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
The attribute ``price_included`` has been added to ``addons``.
|
||||
|
||||
.. versionchanged:: 1.16
|
||||
|
||||
The ``internal_name`` and ``original_price`` fields have been added.
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
|
||||
The field ``require_approval`` has been added.
|
||||
|
||||
.. versionchanged:: 2.3
|
||||
|
||||
The ``sales_channels`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2.4
|
||||
|
||||
The ``generate_tickets`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
|
||||
The ``bundles`` and ``require_bundling`` attributes have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The ``show_quota_left``, ``allow_waitinglist``, and ``hidden_if_available`` attributes have been added.
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
|
||||
The attribute ``meta_data`` has been added.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
|
||||
The attribute ``multi_allowed`` has been added to ``addons``.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Please note that an item either always has variations or never has. Once created with variations the item can never
|
||||
change to an item without and vice versa. To create an item with variations ensure that you POST an item with at least
|
||||
one variation.
|
||||
|
||||
Also note that ``variations``, ``bundles``, and ``addons`` are only supported on ``POST``. To update/delete variations,
|
||||
bundles, and add-ons please use the dedicated nested endpoints. By design this endpoint does not support ``PATCH`` and ``PUT``
|
||||
with nested ``variations``, ``bundles`` and/or ``addons``.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
@@ -206,10 +111,7 @@ Endpoints
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Standard ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "23.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
@@ -217,13 +119,10 @@ Endpoints
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"issue_giftcard": false,
|
||||
"meta_data": {},
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
@@ -231,17 +130,11 @@ Endpoints
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": false,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
@@ -250,14 +143,12 @@ Endpoints
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
"addons": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -302,10 +193,7 @@ Endpoints
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Standard ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "23.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
@@ -313,31 +201,22 @@ Endpoints
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"issue_giftcard": false,
|
||||
"meta_data": {},
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": false,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
@@ -346,14 +225,12 @@ Endpoints
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
"addons": []
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
@@ -362,268 +239,3 @@ Endpoints
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/items/
|
||||
|
||||
Creates a new item
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/items/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Standard ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "23.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"issue_giftcard": false,
|
||||
"meta_data": {},
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Standard ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "23.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"issue_giftcard": false,
|
||||
"meta_data": {},
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": true,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create an item for
|
||||
:param event: The ``slug`` field of the event to create an item for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The item could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/items/(id)/
|
||||
|
||||
Update an item. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``has_variations``, ``variations`` and the ``addon`` field. If
|
||||
you need to update/delete variations or add-ons please use the nested dedicated endpoints.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/items/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"name": {"en": "Ticket"},
|
||||
"default_price": "25.00"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "Ticket"},
|
||||
"internal_name": "",
|
||||
"sales_channels": ["web"],
|
||||
"default_price": "25.00",
|
||||
"original_price": null,
|
||||
"category": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
"issue_giftcard": false,
|
||||
"meta_data": {},
|
||||
"position": 0,
|
||||
"picture": null,
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"generate_tickets": null,
|
||||
"allow_waitinglist": true,
|
||||
"show_quota_left": null,
|
||||
"allow_cancel": true,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": true,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"value": {"en": "Regular"},
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"active": true,
|
||||
"description": null,
|
||||
"position": 1
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"bundles": []
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the item to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The item could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/items/(id)/
|
||||
|
||||
Delete an item.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the item to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,8 +56,6 @@ Endpoints
|
||||
}
|
||||
|
||||
:query page: The page number in case of a multi-page result set, default is 1
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``slug`` and
|
||||
``name``. Default: ``slug``.
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
@@ -90,120 +88,3 @@ Endpoints
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
|
||||
Organizer settings
|
||||
------------------
|
||||
|
||||
pretix organizers and events have lots and lots of parameters of different types that are stored in a key-value store on our system.
|
||||
Since many of these settings depend on each other in complex ways, we can not give direct access to all of these
|
||||
settings through the API. However, we do expose many of the simple and useful flags through the API.
|
||||
|
||||
Please note that the available settings flags change between pretix versions, and we do not give a guarantee on backwards-compatibility like with other parts of the API.
|
||||
Therefore, we're also not including a list of the options here, but instead recommend to look at the endpoint output
|
||||
to see available options. The ``explain=true`` flag enables a verbose mode that provides you with human-readable
|
||||
information about the properties.
|
||||
|
||||
.. note:: Please note that this is not a complete representation of all organizer settings. You will find more settings
|
||||
in the web interface.
|
||||
|
||||
.. warning:: This API is intended for advanced users. Even though we take care to validate your input, you will be
|
||||
able to break your shops using this API by creating situations of conflicting settings. Please take care.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
|
||||
Initial support for settings has been added to the API.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/settings/
|
||||
|
||||
Get current values of organizer settings.
|
||||
|
||||
Permission required: "Can change organizer settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/settings/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example standard response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"event_list_type": "calendar",
|
||||
…
|
||||
}
|
||||
|
||||
**Example verbose response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"event_list_type":
|
||||
{
|
||||
"value": "calendar",
|
||||
"label": "Default overview style",
|
||||
"help_text": "If your event series has more than 50 dates in the future, only the month or week calendar can be used."
|
||||
}
|
||||
},
|
||||
…
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to access
|
||||
:query explain: Set to ``true`` to enable verbose response mode
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/settings/
|
||||
|
||||
Updates organizer settings. Note that ``PUT`` is not allowed here, only ``PATCH``.
|
||||
|
||||
.. warning::
|
||||
|
||||
Settings can be stored at different levels in pretix. If a value is not set on organizer level, a default setting
|
||||
from a higher level (global) will be returned. If you explicitly set a setting on organizer level, it
|
||||
will no longer be inherited from the higher levels. Therefore, we recommend you to send only settings that you
|
||||
explicitly want to set on organizer level. To unset a settings, pass ``null``.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/settings/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"event_list_type": "calendar"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"event_list_type": "calendar",
|
||||
…
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to update
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The organizer could not be updated due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
Question options
|
||||
================
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Questions of type "choice" or "multiple choice" can have different options attached.
|
||||
The options resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the option
|
||||
position integer An integer, used for sorting
|
||||
identifier string An arbitrary string that can be used for matching with
|
||||
other sources.
|
||||
answer multi-lingual string The displayed value of this option
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
This resource has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/
|
||||
|
||||
Returns a list of all options for a given question.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/questions/11/options/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 2,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 3,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query boolean active: If set to ``true`` or ``false``, only questions with this value for the field ``active`` will be
|
||||
returned.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param question: The ``id`` field of the question to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/question does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/(id)/
|
||||
|
||||
Returns information on one option, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param question: The ``id`` field of the question to fetch
|
||||
:param id: The ``id`` field of the option to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/
|
||||
|
||||
Creates a new option
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/question to create a option for
|
||||
:param event: The ``slug`` field of the event to create a option for
|
||||
:param question: The ``id`` field of the question to create a option for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The option could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/(id)/
|
||||
|
||||
Update an option. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"position": 3
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the question to modify
|
||||
:param id: The ``id`` field of the option to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The option could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/questions/(id)/options/(id)/
|
||||
|
||||
Delete an option.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the question to modify
|
||||
:param id: The ``id`` field of the option to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
@@ -1,10 +1,3 @@
|
||||
.. spelling::
|
||||
|
||||
checkin
|
||||
datetime
|
||||
|
||||
.. _rest-questions:
|
||||
|
||||
Questions
|
||||
=========
|
||||
|
||||
@@ -21,7 +14,6 @@ Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the question
|
||||
question multi-lingual string The field label shown to the customer
|
||||
help_text multi-lingual string The help text shown to the customer
|
||||
type string The expected type of answer. Valid options:
|
||||
|
||||
* ``N`` – number
|
||||
@@ -31,88 +23,19 @@ type string The expected ty
|
||||
* ``C`` – choice from a list
|
||||
* ``M`` – multiple choice from a list
|
||||
* ``F`` – file upload
|
||||
* ``D`` – date
|
||||
* ``H`` – time
|
||||
* ``W`` – date and time
|
||||
* ``CC`` – country code (ISO 3666-1 alpha-2)
|
||||
* ``TEL`` – telephone number
|
||||
required boolean If ``true``, the question needs to be filled out.
|
||||
required boolean If ``True``, the question needs to be filled out.
|
||||
position integer An integer, used for sorting
|
||||
items list of integers List of item IDs this question is assigned to.
|
||||
identifier string An arbitrary string that can be used for matching with
|
||||
other sources.
|
||||
ask_during_checkin boolean If ``true``, this question will not be asked while
|
||||
buying the ticket, but will show up when redeeming
|
||||
the ticket instead.
|
||||
hidden boolean If ``true``, the question will only be shown in the
|
||||
backend.
|
||||
print_on_invoice boolean If ``true``, the question will only be shown on
|
||||
invoices.
|
||||
options list of objects In case of question type ``C`` or ``M``, this lists the
|
||||
available objects. Only writable during creation,
|
||||
use separate endpoint to modify this later.
|
||||
available objects.
|
||||
├ id integer Internal ID of the option
|
||||
├ position integer An integer, used for sorting
|
||||
├ identifier string An arbitrary string that can be used for matching with
|
||||
other sources.
|
||||
└ answer multi-lingual string The displayed value of this option
|
||||
valid_number_min string Minimum value for number questions (optional)
|
||||
valid_number_max string Maximum value for number questions (optional)
|
||||
valid_date_min date Minimum value for date questions (optional)
|
||||
valid_date_max date Maximum value for date questions (optional)
|
||||
valid_datetime_min datetime Minimum value for date and time questions (optional)
|
||||
valid_datetime_max datetime Maximum value for date and time questions (optional)
|
||||
dependency_question integer Internal ID of a different question. The current
|
||||
question will only be shown if the question given in
|
||||
this attribute is set to the value given in
|
||||
``dependency_value``. This cannot be combined with
|
||||
``ask_during_checkin``.
|
||||
dependency_values list of strings If ``dependency_question`` is set to a boolean
|
||||
question, this should be ``["True"]`` or ``["False"]``.
|
||||
Otherwise, it should be a list of ``identifier`` values
|
||||
of question options.
|
||||
dependency_value string An old version of ``dependency_values`` that only allows
|
||||
for one value. **Deprecated.**
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
|
||||
The values ``D``, ``H``, and ``W`` for the field ``type`` are now allowed and the ``ask_during_checkin`` field has
|
||||
been added.
|
||||
|
||||
.. versionchanged:: 1.14
|
||||
|
||||
Write methods have been added. The attribute ``identifier`` has been added to both the resource itself and the
|
||||
options resource. The ``position`` attribute has been added to the options resource.
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The attribute ``hidden`` and the question type ``CC`` have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attribute ``dependency_values`` has been added.
|
||||
|
||||
.. versionchanged:: 3.1
|
||||
|
||||
The attribute ``print_on_invoice`` has been added.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
The attribute ``help_text`` has been added.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
|
||||
The attributes ``valid_*`` have been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The questions endpoint has been extended by the filter queries ``ask_during_checkin``, ``requred``, and
|
||||
``identifier``.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questions/
|
||||
|
||||
Returns a list of all questions within a given event.
|
||||
@@ -141,41 +64,21 @@ Endpoints
|
||||
{
|
||||
"id": 1,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"help_text": {"en": "Choose your preferred t-shirt-size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"print_on_invoice": false,
|
||||
"valid_number_min": null,
|
||||
"valid_number_max": null,
|
||||
"valid_date_min": null,
|
||||
"valid_date_max": null,
|
||||
"valid_datetime_min": null,
|
||||
"valid_datetime_max": null,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 0,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 1,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 2,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
@@ -186,9 +89,6 @@ Endpoints
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id`` and ``position``.
|
||||
Default: ``position``
|
||||
:query string identifier: Only return questions with the given identifier string
|
||||
:query boolean ask_during_checkin: Only return questions that are or are not to be asked during check-in
|
||||
:query boolean required: Only return questions that are or are not required to fill in
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 200: no error
|
||||
@@ -218,41 +118,21 @@ Endpoints
|
||||
{
|
||||
"id": 1,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"help_text": {"en": "Choose your preferred t-shirt-size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"print_on_invoice": false,
|
||||
"valid_number_min": null,
|
||||
"valid_number_max": null,
|
||||
"valid_date_min": null,
|
||||
"valid_date_max": null,
|
||||
"valid_datetime_min": null,
|
||||
"valid_datetime_max": null,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 2,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 3,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
@@ -264,208 +144,3 @@ Endpoints
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/questions/
|
||||
|
||||
Creates a new question
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/questions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"help_text": {"en": "Choose your preferred t-shirt-size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"print_on_invoice": false,
|
||||
"dependency_question": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"help_text": {"en": "Choose your preferred t-shirt-size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 1,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"print_on_invoice": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"valid_number_min": null,
|
||||
"valid_number_max": null,
|
||||
"valid_date_min": null,
|
||||
"valid_date_max": null,
|
||||
"valid_datetime_min": null,
|
||||
"valid_datetime_max": null,
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 2,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 3,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create an item for
|
||||
:param event: The ``slug`` field of the event to create an item for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The item could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/questions/(id)/
|
||||
|
||||
Update a question. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``options`` field. If
|
||||
you need to update/delete options please use the nested dedicated endpoints.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/items/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"position": 2
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"question": {"en": "T-Shirt size"},
|
||||
"help_text": {"en": "Choose your preferred t-shirt-size"},
|
||||
"type": "C",
|
||||
"required": false,
|
||||
"items": [1, 2],
|
||||
"position": 2,
|
||||
"identifier": "WY3TP9SL",
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"print_on_invoice": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"valid_number_min": null,
|
||||
"valid_number_max": null,
|
||||
"valid_date_min": null,
|
||||
"valid_date_max": null,
|
||||
"valid_datetime_min": null,
|
||||
"valid_datetime_max": null,
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 2,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 3,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the question to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The item could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/questions/(id)/
|
||||
|
||||
Delete a question.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the item to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
.. _rest-quotas:
|
||||
|
||||
Quotas
|
||||
======
|
||||
|
||||
@@ -20,28 +18,12 @@ size integer The size of the
|
||||
items list of integers List of item IDs this quota acts on.
|
||||
variations list of integers List of item variation IDs this quota acts on.
|
||||
subevent integer ID of the date inside an event series this quota belongs to (or ``null``).
|
||||
close_when_sold_out boolean If ``true``, the quota will "close" as soon as it is
|
||||
sold out once. Even if tickets become available again,
|
||||
they will not be sold unless the quota is set to open
|
||||
again.
|
||||
closed boolean Whether the quota is currently closed (see above
|
||||
field).
|
||||
release_after_exit boolean Whether the quota regains capacity as soon as some tickets
|
||||
have been scanned at an exit.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.10
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attributes ``close_when_sold_out`` and ``closed`` have been added.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
|
||||
The attribute ``release_after_exit`` has been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
@@ -77,9 +59,7 @@ Endpoints
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
"subevent": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -120,9 +100,7 @@ Endpoints
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
@@ -143,23 +121,21 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/quotas/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content: application/json
|
||||
|
||||
{
|
||||
"name": "Ticket Quota",
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
@@ -169,9 +145,7 @@ Endpoints
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a quota for
|
||||
@@ -184,7 +158,7 @@ Endpoints
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/quotas/(id)/
|
||||
|
||||
Update a quota. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
the resource, other fields will be resetted to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field.
|
||||
@@ -224,9 +198,7 @@ Endpoints
|
||||
1,
|
||||
2
|
||||
],
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
@@ -289,7 +261,6 @@ Endpoints
|
||||
"total_size": 1000,
|
||||
"pending_orders": 25,
|
||||
"paid_orders": 423,
|
||||
"exited_orders": 0,
|
||||
"cart_positions": 7,
|
||||
"blocking_vouchers": 126,
|
||||
"waiting_list": 0
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
.. _`rest-seatingplans`:
|
||||
|
||||
Seating plans
|
||||
=============
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The seating plan resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the plan
|
||||
name string Human-readable name of the plan
|
||||
layout object JSON representation of the seating plan. These
|
||||
representations follow a JSON schema that currently
|
||||
still evolves. The version in use can be found `here`_.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
This endpoint has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/seatingplans/
|
||||
|
||||
Returns a list of all seating plans within a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/seatingplans/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Main plan",
|
||||
"layout": { … }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/seatingplans/(id)/
|
||||
|
||||
Returns information on one plan, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/seatingplans/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Main plan",
|
||||
"layout": { … }
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param id: The ``id`` field of the seating plan to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/seatingplans/
|
||||
|
||||
Creates a new seating plan
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/seatingplans/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Main plan",
|
||||
"layout": { … }
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Main plan",
|
||||
"layout": { … }
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a seating plan for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The seating plan could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/seatingplans/(id)/
|
||||
|
||||
Update a plan. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field. **You can not change a plan while it is in use for
|
||||
any events.**
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/seatingplans/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"name": "Old plan"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Old plan",
|
||||
"layout": { … }
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the plan to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The plan could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource **or** the plan is currently in use.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/seatingplans/(id)/
|
||||
|
||||
Delete a plan. You can not delete plans which are currently in use by any events.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/seatingplans/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the plan to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to delete this resource **or** the plan is currently in use.
|
||||
|
||||
|
||||
.. _here: https://github.com/pretix/pretix/blob/master/src/pretix/static/seating/seating-plan.schema.json
|
||||
@@ -1,11 +1,3 @@
|
||||
.. spelling::
|
||||
|
||||
geo
|
||||
lat
|
||||
lon
|
||||
|
||||
.. _rest-subevents:
|
||||
|
||||
Event series dates / Sub-events
|
||||
===============================
|
||||
|
||||
@@ -23,75 +15,33 @@ Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the sub-event
|
||||
name multi-lingual string The sub-event's full name
|
||||
event string The slug of the parent event
|
||||
active boolean If ``true``, the sub-event ticket shop is publicly
|
||||
available.
|
||||
is_public boolean If ``true``, the sub-event ticket shop is publicly
|
||||
shown in lists.
|
||||
date_from datetime The sub-event's start date
|
||||
date_to datetime The sub-event's end date (or ``null``)
|
||||
date_admission datetime The sub-event's admission date (or ``null``)
|
||||
presale_start datetime The sub-date at which the ticket shop opens (or ``null``)
|
||||
presale_end datetime The sub-date at which the ticket shop closes (or ``null``)
|
||||
location multi-lingual string The sub-event location (or ``null``)
|
||||
geo_lat float Latitude of the location (or ``null``)
|
||||
geo_lon float Longitude of the location (or ``null``)
|
||||
item_price_overrides list of objects List of items for which this sub-event overrides the
|
||||
default price
|
||||
├ item integer The internal item ID
|
||||
├ disabled boolean If ``true``, item should not be available for this sub-event
|
||||
└ price money (string) The price or ``null`` for the default price
|
||||
variation_price_overrides list of objects List of variations for which this sub-event overrides
|
||||
the default price
|
||||
├ variation integer The internal variation ID
|
||||
├ disabled boolean If ``true``, variation should not be available for this sub-event
|
||||
└ price money (string) The price or ``null`` for the default price
|
||||
meta_data object Values set for organizer-specific meta data parameters.
|
||||
seating_plan integer If reserved seating is in use, the ID of a seating
|
||||
plan. Otherwise ``null``.
|
||||
seat_category_mapping object An object mapping categories of the seating plan
|
||||
(strings) to items in the event (integers or ``null``).
|
||||
last_modified datetime Last modification of this object
|
||||
meta_data dict Values set for organizer-specific meta data parameters.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The ``meta_data`` field has been added.
|
||||
|
||||
.. versionchanged:: 2.1
|
||||
|
||||
The ``event`` field has been added, together with filters on the list of dates and an organizer-level list.
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
|
||||
.. versionchanged:: 2.7
|
||||
|
||||
The attribute ``is_public`` has been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attributes ``seating_plan`` and ``seat_category_mapping`` have been added.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
|
||||
The attributes ``geo_lat`` and ``geo_lon`` have been added.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
|
||||
The ``disabled`` attribute has been added to ``item_price_overrides`` and ``variation_price_overrides``.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
|
||||
The ``last_modified`` attribute has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
|
||||
The sub-events resource can now be filtered by meta data attributes.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/subevents/
|
||||
|
||||
Returns a list of all sub-events of an event.
|
||||
@@ -120,23 +70,16 @@ Endpoints
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"event": "sampleconf",
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"disabled": false,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
@@ -147,107 +90,12 @@ Endpoints
|
||||
}
|
||||
|
||||
:query page: The page number in case of a multi-page result set, default is 1
|
||||
:query active: If set to ``true``/``false``, only events with a matching value of ``active`` are returned.
|
||||
:query is_future: If set to ``true`` (``false``), only events that happen currently or in the future are (not) returned.
|
||||
:query is_past: If set to ``true`` (``false``), only events that are over are (not) returned.
|
||||
:query ends_after: If set to a date and time, only events that happen during of after the given time are returned.
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:query datetime modified_since: Only return objects that have changed since the given date. Be careful: This does not
|
||||
allow you to know if a subevent was deleted.
|
||||
:query array attr[meta_data_key]: By providing the key and value of a meta data attribute, the list of sub-events
|
||||
will only contain the sub-events matching the set criteria. Providing ``?attr[Format]=Seminar`` would return
|
||||
only those sub-events having set their ``Format`` meta data to ``Seminar``, ``?attr[Format]=`` only those, that
|
||||
have no value set. Please note that this filter will respect default values set on
|
||||
organizer or event level.
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/subevents/
|
||||
|
||||
Creates a new subevent.
|
||||
|
||||
Permission required: "Can create events"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/subevents/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"disabled": false,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"disabled": false,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The sub-event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/subevents/(id)/
|
||||
|
||||
Returns information on one sub-event, identified by its ID.
|
||||
@@ -271,23 +119,16 @@ Endpoints
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"event": "sampleconf",
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"disabled": false,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
@@ -295,175 +136,9 @@ Endpoints
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:param id: The ``id`` field of the sub-event to fetch
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param id: The ``slug`` field of the sub-event to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/subevents/(id)/
|
||||
|
||||
Updates a sub-event, identified by its ID. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to
|
||||
provide all fields of the resource, other fields will be reset to default. With ``PATCH``, you only need to provide
|
||||
the fields that you want to change.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/subevents/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "New Subevent Name"},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"disabled": false,
|
||||
"price": "23.42"
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "New Subevent Name"},
|
||||
"event": "sampleconf",
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"disabled": false,
|
||||
"price": "23.42"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:param id: The ``id`` field of the sub-event to update
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The sub-event could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/sub-event does not exist **or** you have no permission to update this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/subevents/(id)/
|
||||
|
||||
Delete a sub-event. Note that events with orders cannot be deleted to ensure data integrity.
|
||||
|
||||
Permission required: "Can change event settings"
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/subevents/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the main event
|
||||
:param id: The ``id`` field of the sub-event to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/sub-event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/subevents/
|
||||
|
||||
Returns a list of all sub-events of any event series you have access to within an organizer account.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/subevents/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": {"en": "First Sample Conference"},
|
||||
"event": "sampleconf",
|
||||
"active": false,
|
||||
"is_public": true,
|
||||
"date_from": "2017-12-27T10:00:00Z",
|
||||
"date_to": null,
|
||||
"date_admission": null,
|
||||
"presale_start": null,
|
||||
"presale_end": null,
|
||||
"location": null,
|
||||
"geo_lat": null,
|
||||
"geo_lon": null,
|
||||
"seating_plan": null,
|
||||
"seat_category_mapping": {},
|
||||
"item_price_overrides": [
|
||||
{
|
||||
"item": 2,
|
||||
"disabled": false,
|
||||
"price": "12.00"
|
||||
}
|
||||
],
|
||||
"variation_price_overrides": [],
|
||||
"meta_data": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query page: The page number in case of a multi-page result set, default is 1
|
||||
:query active: If set to ``true``/``false``, only events with a matching value of ``active`` are returned.
|
||||
:query event__live: If set to ``true``/``false``, only events with a matching value of ``live`` on the parent event are returned.
|
||||
:query is_future: If set to ``true`` (``false``), only events that happen currently or in the future are (not) returned.
|
||||
:query is_past: If set to ``true`` (``false``), only events that are over are (not) returned.
|
||||
:query ends_after: If set to a date and time, only events that happen during of after the given time are returned.
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
.. _rest-taxrules:
|
||||
|
||||
Tax rules
|
||||
=========
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Tax rules specify how tax should be calculated for specific products. Custom taxation rule sets are currently to
|
||||
available via the API.
|
||||
Tax rules specify how tax should be calculated for specific products.
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
|
||||
@@ -1,671 +0,0 @@
|
||||
.. spelling:: fullname
|
||||
|
||||
.. _`rest-teams`:
|
||||
|
||||
Teams
|
||||
=====
|
||||
|
||||
.. warning:: Unlike our user interface, the team API **does** allow you to lock yourself out by deleting or modifying
|
||||
the team your user or API key belongs to. Be careful around here!
|
||||
|
||||
Team resource
|
||||
-------------
|
||||
|
||||
The team resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the team
|
||||
name string Team name
|
||||
all_events boolean Whether this team has access to all events
|
||||
limit_events list List of event slugs this team has access to
|
||||
can_create_events boolean
|
||||
can_change_teams boolean
|
||||
can_change_organizer_settings boolean
|
||||
can_manage_gift_cards boolean
|
||||
can_change_event_settings boolean
|
||||
can_change_items boolean
|
||||
can_view_orders boolean
|
||||
can_change_orders boolean
|
||||
can_view_vouchers boolean
|
||||
can_change_vouchers boolean
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Team member resource
|
||||
--------------------
|
||||
|
||||
The team member resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the user
|
||||
email string The user's email address
|
||||
fullname string The user's full name (or ``null``)
|
||||
require_2fa boolean Whether this user uses two-factor-authentication
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Team invite resource
|
||||
--------------------
|
||||
|
||||
The team invite resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the invite
|
||||
email string The invitee's email address
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Team API token resource
|
||||
-----------------------
|
||||
|
||||
The team API token resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the invite
|
||||
name string Name of this API token
|
||||
active boolean Whether this API token is active (can never be set to
|
||||
``true`` again once ``false``)
|
||||
token string The actual API token. Will only be sent back during
|
||||
token creation.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Team endpoints
|
||||
--------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/teams/
|
||||
|
||||
Returns a list of all teams within a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/teams/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Admin team",
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/teams/(id)/
|
||||
|
||||
Returns information on one team, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/teams/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Admin team",
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param id: The ``id`` field of the team to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/teams/
|
||||
|
||||
Creates a new team
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/teams/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Admin team",
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Admin team",
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a team for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The team could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/teams/(id)/
|
||||
|
||||
Update a team. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/teams/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"can_create_events": true
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Admin team",
|
||||
"all_events": true,
|
||||
"limit_events": [],
|
||||
"can_create_events": true,
|
||||
...
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the team to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The team could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/teams/(id)/
|
||||
|
||||
Deletes a team.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/teams/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the team to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
||||
|
||||
Team member endpoints
|
||||
---------------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/teams/(team)/members/
|
||||
|
||||
Returns a list of all members of a team.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/teams/1/members/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"fullname": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"require_2fa": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param team: The ``id`` field of the team to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested team does not exist
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/teams/(team)/members/(id)/
|
||||
|
||||
Returns information on one team member, identified by their ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/teams/1/members/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"fullname": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"require_2fa": true
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param team: The ``id`` field of the team to fetch
|
||||
:param id: The ``id`` field of the member to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested team or member does not exist
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/teams/(team)/members/(id)/
|
||||
|
||||
Removes a member from the team.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/teams/1/members/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param team: The ``id`` field of the team to modify
|
||||
:param id: The ``id`` field of the member to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
:statuscode 404: The requested team or member does not exist
|
||||
|
||||
Team invite endpoints
|
||||
---------------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/teams/(team)/invites/
|
||||
|
||||
Returns a list of all invitations to a team.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/teams/1/invites/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"email": "john@example.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param team: The ``id`` field of the team to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested team does not exist
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/teams/(team)/invites/(id)/
|
||||
|
||||
Returns information on one invite, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/teams/1/invites/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"email": "john@example.org"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param team: The ``id`` field of the team to fetch
|
||||
:param id: The ``id`` field of the invite to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested team or invite does not exist
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/teams/(team)/invites/
|
||||
|
||||
Invites someone into the team. Note that if the user already has a pretix account, you will receive a response without
|
||||
an ``id`` and instead of an invite being created, the user will be directly added to the team.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/teams/1/invites/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"email": "mark@example.org"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"email": "mark@example.org"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param team: The ``id`` field of the team to modify
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
:statuscode 404: The requested team does not exist
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/teams/(team)/invites/(id)/
|
||||
|
||||
Revokes an invite.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/teams/1/invites/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param team: The ``id`` field of the team to modify
|
||||
:param id: The ``id`` field of the invite to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
:statuscode 404: The requested team or invite does not exist
|
||||
|
||||
Team API token endpoints
|
||||
------------------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/teams/(team)/tokens/
|
||||
|
||||
Returns a list of all API tokens of a team.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/teams/1/tokens/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"active": true,
|
||||
"name": "Test token"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param team: The ``id`` field of the team to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested team does not exist
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/teams/(team)/tokens/(id)/
|
||||
|
||||
Returns information on one token, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/teams/1/tokens/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"active": true,
|
||||
"name": "Test token"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param team: The ``id`` field of the team to fetch
|
||||
:param id: The ``id`` field of the token to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
:statuscode 404: The requested team or token does not exist
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/teams/(team)/tokens/
|
||||
|
||||
Creates a new token.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/teams/1/tokens/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"name": "New token"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"name": "New token",
|
||||
"active": true,
|
||||
"token": "",
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param team: The ``id`` field of the team to create a token for
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
:statuscode 404: The requested team does not exist
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/teams/(team)/tokens/(id)/
|
||||
|
||||
Disables a token.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/teams/1/tokens/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "My token",
|
||||
"active": false
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param team: The ``id`` field of the team to modify
|
||||
:param id: The ``id`` field of the token to delete
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
:statuscode 404: The requested team or token does not exist
|
||||
@@ -18,8 +18,8 @@ max_usages integer The maximum num
|
||||
redeemed integer The number of times this voucher already has been
|
||||
redeemed.
|
||||
valid_until datetime The voucher expiration date (or ``null``).
|
||||
block_quota boolean If ``true``, quota is blocked for this voucher.
|
||||
allow_ignore_quota boolean If ``true``, this voucher can be redeemed even if a
|
||||
block_quota boolean If ``True``, quota is blocked for this voucher.
|
||||
allow_ignore_quota boolean If ``True``, this voucher can be redeemed even if a
|
||||
product is sold out and even if quota is not blocked
|
||||
for this voucher.
|
||||
price_mode string Determines how this voucher affects product prices.
|
||||
@@ -38,11 +38,9 @@ quota integer An ID of a quot
|
||||
attached either to a specific product or to all
|
||||
products within one quota or it can be available
|
||||
for all items without restriction.
|
||||
seat string ``seat_guid`` attribute of a specific seat (or ``null``)
|
||||
tag string A string that is used for grouping vouchers
|
||||
comment string An internal comment on the voucher
|
||||
subevent integer ID of the date inside an event series this voucher belongs to (or ``null``).
|
||||
show_hidden_items boolean Only if set to ``true``, this voucher allows to buy products with the property ``hide_without_voucher``. Defaults to ``true``.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
@@ -50,14 +48,6 @@ show_hidden_items boolean Only if set to
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attribute ``show_hidden_items`` has been added.
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
|
||||
The attribute ``seat`` has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
@@ -101,8 +91,7 @@ Endpoints
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"seat": null,
|
||||
"subevent": null,
|
||||
"subevent": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -168,7 +157,6 @@ Endpoints
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"seat": null,
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
@@ -232,7 +220,6 @@ Endpoints
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"seat": null,
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
@@ -244,76 +231,6 @@ Endpoints
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
:statuscode 409: The server was unable to acquire a lock and could not process your request. You can try again after a short waiting period.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/vouchers/batch_create/
|
||||
|
||||
Creates multiple new vouchers atomically.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/vouchers/batch_create/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 408
|
||||
|
||||
[
|
||||
{
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
"max_usages": 1,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "12.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
},
|
||||
{
|
||||
"code": "ASDKLJCYXCASDASD",
|
||||
"max_usages": 1,
|
||||
"valid_until": null,
|
||||
"block_quota": false,
|
||||
"allow_ignore_quota": false,
|
||||
"price_mode": "set",
|
||||
"value": "12.00",
|
||||
"item": 1,
|
||||
"variation": null,
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"subevent": null
|
||||
},
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"code": "43K6LKM37FBVR2YG",
|
||||
…
|
||||
}, …
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a vouchers for
|
||||
:param event: The ``slug`` field of the event to create a vouchers for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The vouchers could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
:statuscode 409: The server was unable to acquire a lock and could not process your request. You can try again after a short waiting period.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/vouchers/(id)/
|
||||
|
||||
Update a voucher. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
@@ -334,7 +251,7 @@ Endpoints
|
||||
|
||||
{
|
||||
"price_mode": "set",
|
||||
"value": "24.00"
|
||||
"value": "24.00",
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
@@ -360,7 +277,6 @@ Endpoints
|
||||
"quota": null,
|
||||
"tag": "testvoucher",
|
||||
"comment": "",
|
||||
"seat": null,
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
|
||||
@@ -27,12 +27,6 @@ subevent integer ID of the date
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
.. versionchanged:: 1.15
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added as well as a method to send out
|
||||
vouchers.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
@@ -127,161 +121,3 @@ Endpoints
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/waitinglistentries/
|
||||
|
||||
Create a new entry.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 408
|
||||
|
||||
{
|
||||
"email": "waiting@example.org",
|
||||
"item": 3,
|
||||
"variation": null,
|
||||
"locale": "de",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"created": "2017-12-01T10:00:00Z",
|
||||
"email": "waiting@example.org",
|
||||
"voucher": null,
|
||||
"item": 3,
|
||||
"variation": null,
|
||||
"locale": "de",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create an entry for
|
||||
:param event: The ``slug`` field of the event to create an entry for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The voucher could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this
|
||||
resource **or** entries cannot be created for this item at this time.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/waitinglistentries/(id)/
|
||||
|
||||
Update an entry. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id``, ``voucher`` and ``created`` fields. You can only change
|
||||
an entry as long as no ``voucher`` is set.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 408
|
||||
|
||||
{
|
||||
"item": 4
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"created": "2017-12-01T10:00:00Z",
|
||||
"email": "waiting@example.org",
|
||||
"voucher": null,
|
||||
"item": 4,
|
||||
"variation": null,
|
||||
"locale": "de",
|
||||
"subevent": null
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the entry to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The entry could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this
|
||||
resource **or** entries cannot be created for this item at this time **or** this entry already
|
||||
has a voucher assigned
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/waitinglistentries/(id)/send_voucher/
|
||||
|
||||
Manually sends a voucher to someone on the waiting list
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/1/send_voucher/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 0
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the entry to modify
|
||||
:statuscode 204: no error
|
||||
:statuscode 400: The voucher could not be sent out, see body for details (e.g. voucher has already been sent or
|
||||
item is not available).
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to do this
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/waitinglistentries/(id)/
|
||||
|
||||
Delete an entry. Note that you cannot delete an entry once it is assigned a voucher.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/waitinglistentries/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the entry to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this
|
||||
resource **or** this entry already has a voucher assigned.
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
.. _`rest-webhooks`:
|
||||
|
||||
Webhooks
|
||||
========
|
||||
|
||||
.. note:: This page is about how to modify webhook settings themselves through the REST API. If you just want to know
|
||||
how webhooks work, go here: :ref:`webhooks`
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
The webhook resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the webhook
|
||||
enabled boolean If ``false``, this webhook will not receive any notifications
|
||||
target_url string The URL to call
|
||||
all_events boolean If ``true``, this webhook will receive notifications
|
||||
on all events of this organizer
|
||||
limit_events list of strings If ``all_events`` is ``false``, this is a list of
|
||||
event slugs this webhook is active for
|
||||
action_types list of strings A list of action type filters that limit the
|
||||
notifications sent to this webhook. See below for
|
||||
valid values
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
The following values for ``action_types`` are valid with pretix core:
|
||||
|
||||
* ``pretix.event.order.placed``
|
||||
* ``pretix.event.order.placed.require_approval``
|
||||
* ``pretix.event.order.paid``
|
||||
* ``pretix.event.order.canceled``
|
||||
* ``pretix.event.order.reactivated``
|
||||
* ``pretix.event.order.expired``
|
||||
* ``pretix.event.order.modified``
|
||||
* ``pretix.event.order.contact.changed``
|
||||
* ``pretix.event.order.changed.*``
|
||||
* ``pretix.event.order.refund.created.externally``
|
||||
* ``pretix.event.order.approved``
|
||||
* ``pretix.event.order.denied``
|
||||
* ``pretix.event.checkin``
|
||||
* ``pretix.event.checkin.reverted``
|
||||
* ``pretix.event.added``
|
||||
* ``pretix.event.changed``
|
||||
* ``pretix.event.deleted``
|
||||
* ``pretix.subevent.added``
|
||||
* ``pretix.subevent.changed``
|
||||
* ``pretix.subevent.deleted``
|
||||
|
||||
Installed plugins might register more valid values.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/webhooks/
|
||||
|
||||
Returns a list of all webhooks within a given organizer.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/webhooks/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 2,
|
||||
"enabled": true,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/webhooks/(id)/
|
||||
|
||||
Returns information on one webhook, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/webhooks/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"enabled": true,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param id: The ``id`` field of the webhook to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/webhooks/
|
||||
|
||||
Creates a new webhook
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/webhooks/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"enabled": true,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"enabled": true,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to create a webhook for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The webhook could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/webhooks/(id)/
|
||||
|
||||
Update a webhook. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/webhooks/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"enabled": false
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"enabled": false,
|
||||
"target_url": "https://httpstat.us/200",
|
||||
"all_events": false,
|
||||
"limit_events": ["democon"],
|
||||
"action_types": ["pretix.event.order.modified", "pretix.event.order.changed.*"]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the webhook to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The webhook could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/webhook/(id)/
|
||||
|
||||
Delete a webhook. Currently, this will not delete but just disable the webhook.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/webhooks/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the webhook to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to delete this resource.
|
||||
@@ -1,36 +0,0 @@
|
||||
.. _`rest-tokenauth`:
|
||||
|
||||
Token-based authentication
|
||||
==========================
|
||||
|
||||
Obtaining an API token
|
||||
----------------------
|
||||
|
||||
To authenticate your API requests with Tokens, you need to obtain a team-level API token.
|
||||
You can create a token in the pretix web interface on the level of organizer teams. Create
|
||||
a new team or choose an existing team that has the level of permissions the token should
|
||||
have and create a new token using the form below the list of team members:
|
||||
|
||||
.. image:: img/token_form.png
|
||||
:class: screenshot
|
||||
|
||||
You can enter a description for the token to distinguish from other tokens later on.
|
||||
Once you click "Add", you will be provided with an API token in the success message.
|
||||
Copy this token, as you won't be able to retrieve it again.
|
||||
|
||||
.. image:: img/token_success.png
|
||||
:class: screenshot
|
||||
|
||||
Using an API token
|
||||
------------------
|
||||
|
||||
You need to include the API token with every request to pretix' API in the ``Authorization`` header
|
||||
like the following:
|
||||
|
||||
.. sourcecode:: http
|
||||
:emphasize-lines: 3
|
||||
|
||||
GET /api/v1/organizers/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Authorization: Token e1l6gq2ye72thbwkacj7jbri7a7tvxe614ojv8ybureain92ocub46t5gab5966k
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
.. _`webhooks`:
|
||||
|
||||
Webhooks
|
||||
========
|
||||
|
||||
pretix can send webhook calls to notify your application of any changes that happen inside pretix. This is especially
|
||||
useful for everything triggered by an actual user, such as a new ticket sale or the arrival of a payment.
|
||||
|
||||
You can register any number of webhook URLs that pretix will notify any time one of the supported events occurs inside
|
||||
your organizer account. A great example use case of webhooks would be to add the buyer to your mailing list every time
|
||||
a new order comes in.
|
||||
|
||||
Configuring webhooks
|
||||
--------------------
|
||||
|
||||
You can find the list of your active webhooks in the "Webhook" section of your organizer account:
|
||||
|
||||
.. thumbnail:: ../screens/organizer/webhook_list.png
|
||||
:align: center
|
||||
:class: screenshot
|
||||
|
||||
Click "Create webhook" if you want to add a new URL. You will then be able to enter the URL pretix shall call for
|
||||
notifications. You need to select any number of notification types that you want to receive and you can optionally
|
||||
filter the events you want to receive notifications for.
|
||||
|
||||
.. thumbnail:: ../screens/organizer/webhook_edit.png
|
||||
:align: center
|
||||
:class: screenshot
|
||||
|
||||
You can also configure webhooks :ref:`through the API itself <rest-webhooks>`.
|
||||
|
||||
Receiving webhooks
|
||||
------------------
|
||||
|
||||
Creating a webhook endpoint on your server is no different from creating any other page on your website. If your
|
||||
website is written in PHP, you might just create a new ``.php`` file on your server; if you use a web framework like
|
||||
Symfony or Django, you would just create a new route with the desired URL.
|
||||
|
||||
We will call your URL with a HTTP ``POST`` request with a ``JSON`` body. In PHP, you can parse this like this::
|
||||
|
||||
$input = @file_get_contents('php://input');
|
||||
$event_json = json_decode($input);
|
||||
// Do something with $event_json
|
||||
|
||||
In Django, you would create a view like this::
|
||||
|
||||
def my_webhook_view(request):
|
||||
event_json = json.loads(request.body)
|
||||
# Do something with event_json
|
||||
return HttpResponse(status=200)
|
||||
|
||||
More samples for the language of your choice are easy to find online.
|
||||
|
||||
The exact body of the request varies by notification type, but for the main types included with pretix core, such as
|
||||
those related to changes of an order, it will look like this::
|
||||
|
||||
{
|
||||
"notification_id": 123455,
|
||||
"organizer": "acmecorp",
|
||||
"event": "democon",
|
||||
"code": "ABC23",
|
||||
"action": "pretix.event.order.placed"
|
||||
}
|
||||
|
||||
Notifications regarding a check-in will contain more details like ``orderposition_id``
|
||||
and ``checkin_list``.
|
||||
|
||||
.. warning:: You should not trust data supplied to your webhook, but only use it as a trigger to fetch updated data.
|
||||
Anyone could send data there if they guess the correct URL and you won't be able to tell. Therefore, we
|
||||
only include the minimum amount of data necessary for you to fetch the changed objects from our
|
||||
:ref:`rest-api` in an authenticated way.
|
||||
|
||||
.. warning:: In very rare cases, you could receive the same webhook notification twice. We try to avoid it, but we
|
||||
prefer it over missing a notification.
|
||||
|
||||
If you want to further prevent others from accessing your webhook URL, you can also use `Basic authentication`_ and
|
||||
supply the URL to us in the format of ``https://username:password@domain.com/path/``.
|
||||
We recommend that you use HTTPS for your webhook URL and might require it in the future. If HTTPS is used, we require
|
||||
that a valid certificate is in use.
|
||||
|
||||
.. note:: If you use a web framework that makes use of automatic CSRF protection, this protection might prevent us
|
||||
from calling your webhook URL. In this case, we recommend that you turn of CSRF protection selectively
|
||||
for that route. In Django, you can do this by putting the ``@csrf_exempt`` decorator on your view. In
|
||||
Rails, you can pass an ``except`` parameter to ``protect_from_forgery``.
|
||||
|
||||
|
||||
Responding to a webhook
|
||||
-----------------------
|
||||
|
||||
If you successfully received a webhook call, your endpoint should return a HTTP status code between ``200`` and ``299``.
|
||||
If any other status code is returned, we will assume you did not receive the call. This does mean that any redirection
|
||||
or ``304 Not Modified`` response will be treated as a failure. pretix will not follow any ``301`` or ``302`` redirect
|
||||
headers and pretix will ignore all other information in your response headers or body.
|
||||
|
||||
If we do not receive a status code in the range of ``200`` and ``299``, pretix will retry to deliver for up to three
|
||||
days with an exponential back off. Therefore, we recommend that you implement your endpoint in a way where calling it
|
||||
multiple times for the same event due to a perceived error does not do any harm.
|
||||
|
||||
There is only one exception: If status code ``410 Gone`` is returned, we will assume the
|
||||
endpoint does not exist any more and automatically disable the webhook.
|
||||
|
||||
.. note:: If you use a self-hosted version of pretix (i.e. not our SaaS offering at pretix.eu) and you did not
|
||||
configure a background task queue, failed webhooks will not be retried.
|
||||
|
||||
Debugging webhooks
|
||||
------------------
|
||||
|
||||
If you want to debug your webhooks, you can view a log of all sent notifications and the responses of your server for
|
||||
30 days right next to your configuration.
|
||||
|
||||
.. _Basic authentication: https://en.wikipedia.org/wiki/Basic_access_authentication
|
||||
@@ -1,11 +0,0 @@
|
||||
from enchant.tokenize import get_tokenizer, Filter, unit_tokenize
|
||||
|
||||
class CheckinFilter(Filter):
|
||||
""" If a word looks like checkin_count, it refers to a so-called variable in
|
||||
the code, and is treated as being spelled right."""
|
||||
|
||||
def _split(self, word):
|
||||
if word[:8] == "checkin_":
|
||||
return unit_tokenize(word[8:])
|
||||
|
||||
return unit_tokenize(word)
|
||||
37
doc/conf.py
37
doc/conf.py
@@ -31,13 +31,6 @@ import django
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pretix.testutils.settings")
|
||||
django.setup()
|
||||
|
||||
|
||||
try:
|
||||
import enchant
|
||||
HAS_PYENCHANT = True
|
||||
except:
|
||||
HAS_PYENCHANT = False
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
@@ -52,10 +45,7 @@ extensions = [
|
||||
'sphinx.ext.coverage',
|
||||
'sphinxcontrib.httpdomain',
|
||||
'sphinxcontrib.images',
|
||||
'sphinxemoji.sphinxemoji',
|
||||
]
|
||||
if HAS_PYENCHANT:
|
||||
extensions.append('sphinxcontrib.spelling')
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -67,7 +57,7 @@ source_suffix = '.rst'
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
master_doc = 'contents'
|
||||
|
||||
# General information about the project.
|
||||
project = 'pretix'
|
||||
@@ -235,7 +225,7 @@ latex_elements = {
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
('index', 'pretix.tex', 'pretix Documentation',
|
||||
('contents', 'pretix.tex', 'pretix Documentation',
|
||||
'Raphael Michel', 'manual'),
|
||||
]
|
||||
|
||||
@@ -300,26 +290,3 @@ texinfo_documents = [
|
||||
images_config = {
|
||||
'default_image_width': '250px'
|
||||
}
|
||||
|
||||
linkcheck_ignore = [
|
||||
r'http://localhost.*', r'.*yourdomain.*', r'https://en.wikipedia.org', 'https://pretix.eu/',
|
||||
]
|
||||
|
||||
# -- Options for Spelling output ------------------------------------------
|
||||
if HAS_PYENCHANT:
|
||||
# String specifying the language, as understood by PyEnchant and enchant.
|
||||
# Defaults to en_US for US English.
|
||||
spelling_lang = 'en_US'
|
||||
|
||||
# String specifying a file containing a list of words known to be spelled
|
||||
# correctly but that do not appear in the language dictionary selected by
|
||||
# spelling_lang. The file should contain one word per line.
|
||||
spelling_word_list_filename='spelling_wordlist.txt'
|
||||
|
||||
# Boolean controlling whether suggestions for misspelled words are printed.
|
||||
# Defaults to False.
|
||||
spelling_show_suggestions=True
|
||||
|
||||
# List of filter classes to be added to the tokenizer that produces words to be checked.
|
||||
from checkin_filter import CheckinFilter
|
||||
spelling_filters=[CheckinFilter]
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
Pluggable authentication backends
|
||||
=================================
|
||||
|
||||
Plugins can supply additional authentication backends. This is mainly useful in self-hosted installations
|
||||
and allows you to use company-wide login mechanisms such as LDAP or OAuth for accessing pretix' backend.
|
||||
|
||||
Every authentication backend contains an implementation of the interface defined in ``pretix.base.auth.BaseAuthBackend``
|
||||
(see below). Note that pretix authentication backends work differently than plain Django authentication backends.
|
||||
Basically, three pre-defined flows are supported:
|
||||
|
||||
* Authentication mechanisms that rely on a **set of input parameters**, e.g. a username and a password. These can be
|
||||
implemented by supplying the ``login_form_fields`` property and a ``form_authenticate`` method.
|
||||
|
||||
* Authentication mechanisms that rely on **external sessions**, e.g. a cookie or a proxy HTTP header. These can be
|
||||
implemented by supplying a ``request_authenticate`` method.
|
||||
|
||||
* Authentication mechanisms that rely on **redirection**, e.g. to an OAuth provider. These can be implemented by
|
||||
supplying a ``authentication_url`` method and implementing a custom return view.
|
||||
|
||||
Authentication backends are *not* collected through a signal. Instead, they must explicitly be set through the
|
||||
``auth_backends`` directive in the ``pretix.cfg`` :ref:`configuration file <config>`.
|
||||
|
||||
In each of these methods (``form_authenticate``, ``request_authenticate`` or your custom view) you are supposed to
|
||||
either get an existing :py:class:`pretix.base.models.User` object from the database or create a new one. There are a
|
||||
few rules you need to follow:
|
||||
|
||||
* You **MUST** only return users with the ``auth_backend`` attribute set to the ``identifier`` value of your backend.
|
||||
|
||||
* You **MUST** create new users with the ``auth_backend`` attribute set to the ``identifier`` value of your backend.
|
||||
|
||||
* Every user object **MUST** have an email address. Email addresses are globally unique. If the email address is
|
||||
already registered to a user who signs in through a different backend, you **SHOULD** refuse the login.
|
||||
|
||||
The backend interface
|
||||
---------------------
|
||||
|
||||
.. class:: pretix.base.auth.BaseAuthBackend
|
||||
|
||||
The central object of each backend is the subclass of ``BaseAuthBackend``.
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: verbose_name
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: login_form_fields
|
||||
|
||||
.. autoattribute:: visible
|
||||
|
||||
.. automethod:: form_authenticate
|
||||
|
||||
.. automethod:: request_authenticate
|
||||
|
||||
.. automethod:: authentication_url
|
||||
|
||||
Logging users in
|
||||
----------------
|
||||
|
||||
If you return a user from ``form_authenticate`` or ``request_authenticate``, the system will handle everything else
|
||||
for you correctly. However, if you use a redirection method and build a custom view to verify the login, we strongly
|
||||
recommend that you use the following utility method to correctly set session values and enforce two-factor
|
||||
authentication (if activated):
|
||||
|
||||
.. autofunction:: pretix.control.views.auth.process_login
|
||||
@@ -14,9 +14,7 @@ Control panel views
|
||||
-------------------
|
||||
|
||||
If you want to add a custom view to the control area of an event, just register an URL in your
|
||||
``urls.py`` that lives in the ``/control/`` subpath:
|
||||
|
||||
.. code-block:: python
|
||||
``urls.py`` that lives in the ``/control/`` subpath::
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
@@ -27,7 +25,7 @@ If you want to add a custom view to the control area of an event, just register
|
||||
views.admin_view, name='backend'),
|
||||
]
|
||||
|
||||
It is required that your URL parameters are called ``organizer`` and ``event``. If you want to
|
||||
It is required that your URL paramaters are called ``organizer`` and ``event``. If you want to
|
||||
install a view on organizer level, you can leave out the ``event``.
|
||||
|
||||
You can then implement the view as you would normally do. Our middleware will automatically
|
||||
@@ -46,9 +44,7 @@ If only the ``organizer`` parameter is present, it will be ensured that:
|
||||
* The user has permission to access view the current organizer
|
||||
|
||||
If you want to require specific permission types, we provide you with a decorator or a mixin for
|
||||
your views:
|
||||
|
||||
.. code-block:: python
|
||||
your views::
|
||||
|
||||
from pretix.control.permissions import (
|
||||
event_permission_required, EventPermissionRequiredMixin
|
||||
@@ -65,13 +61,12 @@ your views:
|
||||
...
|
||||
|
||||
Similarly, there is ``organizer_permission_required`` and ``OrganizerPermissionRequiredMixin``. In case of
|
||||
event-related views, there is also a signal that allows you to add the view to the event navigation like this:
|
||||
event-related views, there is also a signal that allows you to add the view to the event navigation like this::
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.urls import resolve, reverse
|
||||
from django.core.urlresolvers import resolve, reverse
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from pretix.control.signals import nav_event
|
||||
|
||||
|
||||
@@ -95,9 +90,7 @@ Event settings view
|
||||
-------------------
|
||||
|
||||
A special case of a control panel view is a view hooked into the event settings page. For this case, there is a
|
||||
special navigation signal:
|
||||
|
||||
.. code-block:: python
|
||||
special navigation signal::
|
||||
|
||||
@receiver(nav_event_settings, dispatch_uid='friends_tickets_nav_settings')
|
||||
def navbar_settings(sender, request, **kwargs):
|
||||
@@ -112,9 +105,7 @@ special navigation signal:
|
||||
}]
|
||||
|
||||
Also, your view should inherit from ``EventSettingsViewMixin`` and your template from ``pretixcontrol/event/settings_base.html``
|
||||
for good integration. If you just want to display a form, you could do it like the following:
|
||||
|
||||
.. code-block:: python
|
||||
for good integration. If you just want to display a form, you could do it like the following::
|
||||
|
||||
class MySettingsView(EventSettingsViewMixin, EventSettingsFormView):
|
||||
model = Event
|
||||
@@ -156,9 +147,7 @@ Including a custom view into the participant-facing frontend is a little bit dif
|
||||
no path prefix like ``control/``.
|
||||
|
||||
First, define your URL in your ``urls.py``, but this time in the ``event_patterns`` section and wrapped by
|
||||
``event_url``:
|
||||
|
||||
.. code-block:: python
|
||||
``event_url``::
|
||||
|
||||
from pretix.multidomain import event_url
|
||||
|
||||
@@ -193,9 +182,8 @@ standard Django request handling: There are `ViewSets`_ to group related views i
|
||||
automatically build URL configurations from them.
|
||||
|
||||
To integrate a custom viewset with pretix' REST API, you can just register with one of our routers within the
|
||||
``urls.py`` module of your plugin:
|
||||
``urls.py`` module of your plugin::
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pretix.api.urls import event_router, router, orga_router
|
||||
|
||||
@@ -212,9 +200,7 @@ in the control panel. However, you need to make sure on your own only to return
|
||||
.event`` and ``request.organizer`` are available as usual.
|
||||
|
||||
To require a special permission like ``can_view_orders``, you do not need to inherit from a special ViewSet base
|
||||
class, you can just set the ``permission`` attribute on your viewset:
|
||||
|
||||
.. code-block:: python
|
||||
class, you can just set the ``permission`` attribute on your viewset::
|
||||
|
||||
class MyViewSet(ModelViewSet):
|
||||
permission = 'can_view_orders'
|
||||
@@ -222,9 +208,8 @@ class, you can just set the ``permission`` attribute on your viewset:
|
||||
|
||||
If you want to check the permission only for some methods of your viewset, you have to do it yourself. Note here that
|
||||
API authentications can be done via user sessions or API tokens and you should therefore check something like the
|
||||
following:
|
||||
following::
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
perm_holder = (request.auth if isinstance(request.auth, TeamAPIToken) else request.user)
|
||||
if perm_holder.has_event_permission(request.event.organizer, request.event, 'can_view_orders'):
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
Writing an HTML e-mail renderer plugin
|
||||
======================================
|
||||
|
||||
An email renderer class controls how the HTML part of e-mails sent by pretix is built.
|
||||
The creation of such a plugin is very similar to creating an export output.
|
||||
|
||||
Please read :ref:`Creating a plugin <pluginsetup>` first, if you haven't already.
|
||||
|
||||
Output registration
|
||||
-------------------
|
||||
|
||||
The email HTML renderer API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available email renderers. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.email.BaseHTMLMailRenderer``
|
||||
that we'll provide in this plugin:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_html_mail_renderers
|
||||
|
||||
|
||||
@receiver(register_html_mail_renderers, dispatch_uid="renderer_custom")
|
||||
def register_mail_renderers(sender, **kwargs):
|
||||
from .email import MyMailRenderer
|
||||
return MyMailRenderer
|
||||
|
||||
|
||||
The renderer class
|
||||
------------------
|
||||
|
||||
.. class:: pretix.base.email.BaseHTMLMailRenderer
|
||||
|
||||
The central object of each email renderer is the subclass of ``BaseHTMLMailRenderer``.
|
||||
|
||||
.. py:attribute:: BaseHTMLMailRenderer.event
|
||||
|
||||
The default constructor sets this property to the event we are currently
|
||||
working for.
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: verbose_name
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: thumbnail_filename
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: is_available
|
||||
|
||||
.. automethod:: render
|
||||
|
||||
This is an abstract method, you **must** implement this!
|
||||
|
||||
Helper class for template-base renderers
|
||||
----------------------------------------
|
||||
|
||||
The email renderer that ships with pretix is based on Django templates to generate HTML.
|
||||
In case you also want to render emails based on a template, we provided a ready-made base
|
||||
class ``TemplateBasedMailRenderer`` that you can re-use to perform the following steps:
|
||||
|
||||
* Convert the body text and the signature to HTML using our markdown renderer
|
||||
|
||||
* Render the template
|
||||
|
||||
* Call `inlinestyler`_ to convert all ``<style>`` style sheets to inline ``style=""``
|
||||
attributes for better compatibility
|
||||
|
||||
To use it, you just need to implement some variables:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ClassicMailRenderer(TemplateBasedMailRenderer):
|
||||
verbose_name = _('pretix default')
|
||||
identifier = 'classic'
|
||||
thumbnail_filename = 'pretixbase/email/thumb.png'
|
||||
template_name = 'pretixbase/email/plainwrapper.html'
|
||||
|
||||
The template is passed the following context variables:
|
||||
|
||||
``site``
|
||||
Name of the pretix installation (``settings.PRETIX_INSTANCE_NAME``)
|
||||
|
||||
``site_url``
|
||||
Root URL of the pretix installation (``settings.SITE_URL``)
|
||||
|
||||
``body``
|
||||
The body as markdown (render with ``{{ body|safe }}``)
|
||||
|
||||
``subject``
|
||||
The email subject
|
||||
|
||||
``color``
|
||||
The primary color of the event
|
||||
|
||||
``event``
|
||||
The ``Event`` object
|
||||
|
||||
``signature`` (optional, only if configured)
|
||||
The signature with event organizer contact details as markdown (render with ``{{ signature|safe }}``)
|
||||
|
||||
``order`` (optional, only if applicable)
|
||||
The ``Order`` object
|
||||
|
||||
``position`` (optional, only if applicable)
|
||||
The ``OrderPosition`` object
|
||||
|
||||
.. _inlinestyler: https://pypi.org/project/inlinestyler/
|
||||
@@ -17,38 +17,18 @@ Exporter registration
|
||||
The exporter API does not make a lot of usage from signals, however, it does use a signal to get a list of
|
||||
all available exporters. Your plugin should listen for this signal and return the subclass of
|
||||
``pretix.base.exporter.BaseExporter``
|
||||
that we'll provide in this plugin:
|
||||
|
||||
.. code-block:: python
|
||||
that we'll provide in this plugin::
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_data_exporters
|
||||
from pretix.base.signals import register_data_exporter
|
||||
|
||||
|
||||
@receiver(register_data_exporters, dispatch_uid="exporter_myexporter")
|
||||
@receiver(register_data_exporter, dispatch_uid="exporter_myexporter")
|
||||
def register_data_exporter(sender, **kwargs):
|
||||
from .exporter import MyExporter
|
||||
return MyExporter
|
||||
|
||||
Some exporters might also prove to be useful, when provided on an organizer-level. In order to declare your
|
||||
exporter as capable of providing exports spanning multiple events, your plugin should listen for this signal
|
||||
and return the subclass of ``pretix.base.exporter.BaseExporter`` that we'll provide in this plugin:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_multievent_data_exporters
|
||||
|
||||
|
||||
@receiver(register_multievent_data_exporters, dispatch_uid="multieventexporter_myexporter")
|
||||
def register_multievent_data_exporter(sender, **kwargs):
|
||||
from .exporter import MyExporter
|
||||
return MyExporter
|
||||
|
||||
If your exporter supports both event-level and multi-event level exports, you will need to listen for both
|
||||
signals.
|
||||
|
||||
The exporter class
|
||||
------------------
|
||||
|
||||
@@ -11,9 +11,7 @@ Core
|
||||
----
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: periodic_task, event_live_issues, event_copy_data, email_filter, register_notification_types,
|
||||
item_copy_data, register_sales_channels, register_global_settings, quota_availability, global_email_filter,
|
||||
register_ticket_secret_generators
|
||||
:members: periodic_task, event_live_issues, event_copy_data, email_filter
|
||||
|
||||
Order events
|
||||
""""""""""""
|
||||
@@ -21,24 +19,17 @@ Order events
|
||||
There are multiple signals that will be sent out in the ordering cycle:
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: validate_cart, validate_cart_addons, validate_order, order_fee_calculation, order_paid, order_placed, order_canceled, order_reactivated, order_expired, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download, order_split, order_gracefully_delete, invoice_line_text
|
||||
|
||||
Check-ins
|
||||
"""""""""
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: checkin_created
|
||||
|
||||
:members: validate_cart, order_fee_calculation, order_paid, order_placed, order_fee_type_name, allow_ticket_download
|
||||
|
||||
Frontend
|
||||
--------
|
||||
|
||||
.. automodule:: pretix.presale.signals
|
||||
:members: html_head, html_footer, footer_link, front_page_top, front_page_bottom, front_page_bottom_widget, fee_calculation_for_cart, contact_form_fields, question_form_fields, contact_form_fields_overrides, question_form_fields_overrides, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, sass_preamble, sass_postamble, render_seating_plan, checkout_flow_steps, position_info, position_info_top, item_description, global_html_head, global_html_footer, global_html_page_header
|
||||
:members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, fee_calculation_for_cart, contact_form_fields, question_form_fields, checkout_confirm_messages, checkout_confirm_page_content
|
||||
|
||||
|
||||
.. automodule:: pretix.presale.signals
|
||||
:members: order_info, order_info_top, order_meta_from_request
|
||||
:members: order_info, order_meta_from_request
|
||||
|
||||
Request flow
|
||||
""""""""""""
|
||||
@@ -56,36 +47,26 @@ Backend
|
||||
-------
|
||||
|
||||
.. automodule:: pretix.control.signals
|
||||
:members: nav_event, html_head, html_page_start, quota_detail_html, nav_topbar, nav_global, nav_organizer, nav_event_settings,
|
||||
order_info, event_settings_widget, oauth_application_registered, order_position_buttons, subevent_forms,
|
||||
item_formsets, order_search_filter_q, order_search_forms
|
||||
:members: nav_event, html_head, quota_detail_html, nav_topbar, nav_global, nav_organizer, nav_event_settings, order_info, event_settings_widget
|
||||
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: logentry_display, logentry_object_link, requiredaction_display, timeline_events
|
||||
:members: logentry_display, logentry_object_link, requiredaction_display
|
||||
|
||||
Vouchers
|
||||
""""""""
|
||||
|
||||
.. automodule:: pretix.control.signals
|
||||
:members: item_forms, voucher_form_class, voucher_form_html, voucher_form_validation
|
||||
:members: voucher_form_class, voucher_form_html, voucher_form_validation
|
||||
|
||||
Dashboards
|
||||
""""""""""
|
||||
|
||||
.. automodule:: pretix.control.signals
|
||||
:members: event_dashboard_widgets, user_dashboard_widgets, event_dashboard_top
|
||||
:members: event_dashboard_widgets, user_dashboard_widgets
|
||||
|
||||
Ticket designs
|
||||
""""""""""""""
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: layout_text_variables
|
||||
|
||||
.. automodule:: pretix.plugins.ticketoutputpdf.signals
|
||||
:members: override_layout
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: validate_event_settings, api_event_settings_fields
|
||||
:members: layout_text_variables
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. _`importcol`:
|
||||
|
||||
Extending the order import process
|
||||
==================================
|
||||
|
||||
It's possible through the backend to import orders into pretix, for example from a legacy ticketing system. If your
|
||||
plugins defines additional data structures around orders, it might be useful to make it possible to import them as well.
|
||||
|
||||
Import process
|
||||
--------------
|
||||
|
||||
Here's a short description of pretix' import process to show you where the system will need to interact with your plugin.
|
||||
You can find more detailed descriptions of the attributes and methods further below.
|
||||
|
||||
1. The user uploads a CSV file. The system tries to parse the CSV file and understand its column headers.
|
||||
|
||||
2. A preview of the file is shown to the user and the user is asked to assign the various different input parameters to
|
||||
columns of the file or static values. For example, the user either needs to manually select a product or specify a
|
||||
column that contains a product. For this purpose, a select field is rendered for every possible input column,
|
||||
allowing the user to choose between a default/empty value (defined by your ``default_value``/``default_label``)
|
||||
attributes, the columns of the uploaded file, or a static value (defined by your ``static_choices`` method).
|
||||
|
||||
3. The user submits its assignment and the system uses the ``resolve`` method of all columns to get the raw value for
|
||||
all columns.
|
||||
|
||||
4. The system uses the ``clean`` method of all columns to verify that all input fields are valid and transformed to the
|
||||
correct data type.
|
||||
|
||||
5. The system prepares internal model objects (``Order`` etc) and uses the ``assign`` method of all columns to assign
|
||||
these objects with actual values.
|
||||
|
||||
6. The system saves all of these model objects to the database in a database transaction. Plugins can create additional
|
||||
objects in this stage through their ``save`` method.
|
||||
|
||||
Column registration
|
||||
-------------------
|
||||
|
||||
The import API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available import columns. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.orderimport.ImportColumn``
|
||||
that we'll provide in this plugin:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import order_import_columns
|
||||
|
||||
|
||||
@receiver(order_import_columns, dispatch_uid="custom_columns")
|
||||
def register_column(sender, **kwargs):
|
||||
return [
|
||||
EmailColumn(sender),
|
||||
]
|
||||
|
||||
The column class API
|
||||
--------------------
|
||||
|
||||
.. class:: pretix.base.orderimport.ImportColumn
|
||||
|
||||
The central object of each import extension is the subclass of ``ImportColumn``.
|
||||
|
||||
.. py:attribute:: ImportColumn.event
|
||||
|
||||
The default constructor sets this property to the event we are currently
|
||||
working for.
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: verbose_name
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: default_value
|
||||
|
||||
.. autoattribute:: default_label
|
||||
|
||||
.. autoattribute:: initial
|
||||
|
||||
.. automethod:: static_choices
|
||||
|
||||
.. automethod:: resolve
|
||||
|
||||
.. automethod:: clean
|
||||
|
||||
.. automethod:: assign
|
||||
|
||||
.. automethod:: save
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
For example, the import column responsible for assigning email addresses looks like this:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
class EmailColumn(ImportColumn):
|
||||
identifier = 'email'
|
||||
verbose_name = _('E-mail address')
|
||||
|
||||
def clean(self, value, previous_values):
|
||||
if value:
|
||||
EmailValidator()(value)
|
||||
return value
|
||||
|
||||
def assign(self, value, order, position, invoice_address, **kwargs):
|
||||
order.email = value
|
||||
@@ -10,13 +10,6 @@ Contents:
|
||||
exporter
|
||||
ticketoutput
|
||||
payment
|
||||
payment_2.0
|
||||
email
|
||||
placeholder
|
||||
invoice
|
||||
shredder
|
||||
import
|
||||
customview
|
||||
auth
|
||||
general
|
||||
quality
|
||||
|
||||
@@ -13,11 +13,9 @@ Output registration
|
||||
-------------------
|
||||
|
||||
The invoice renderer API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available invoice renderers. Your plugin
|
||||
does use a signal to get a list of all available ticket outputs. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.invoice.BaseInvoiceRenderer``
|
||||
that we'll provide in this plugin:
|
||||
|
||||
.. code-block:: python
|
||||
that we'll provide in this plugin::
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
@@ -25,7 +23,7 @@ that we'll provide in this plugin:
|
||||
|
||||
|
||||
@receiver(register_invoice_renderers, dispatch_uid="output_custom")
|
||||
def register_invoice_renderers(sender, **kwargs):
|
||||
def register_infoice_renderers(sender, **kwargs):
|
||||
from .invoice import MyInvoiceRenderer
|
||||
return MyInvoiceRenderer
|
||||
|
||||
|
||||
@@ -9,19 +9,13 @@ is very similar to creating an export output.
|
||||
|
||||
Please read :ref:`Creating a plugin <pluginsetup>` first, if you haven't already.
|
||||
|
||||
.. warning:: We changed our payment provider API a lot in pretix 2.x. Our documentation page on :ref:`payment2.0`
|
||||
might be insightful even if you do not have a payment provider to port, as it outlines the rationale
|
||||
behind the current design.
|
||||
|
||||
Provider registration
|
||||
---------------------
|
||||
|
||||
The payment provider API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available payment providers. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.payment.BasePaymentProvider``
|
||||
that the plugin will provide:
|
||||
|
||||
.. code-block:: python
|
||||
that the plugin will provide::
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
@@ -37,7 +31,7 @@ that the plugin will provide:
|
||||
The provider class
|
||||
------------------
|
||||
|
||||
.. py:class:: pretix.base.payment.BasePaymentProvider
|
||||
.. class:: pretix.base.payment.BasePaymentProvider
|
||||
|
||||
The central object of each payment provider is the subclass of ``BasePaymentProvider``.
|
||||
|
||||
@@ -60,75 +54,53 @@ The provider class
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: public_name
|
||||
|
||||
.. autoattribute:: is_enabled
|
||||
|
||||
.. autoattribute:: priority
|
||||
.. automethod:: calculate_fee
|
||||
|
||||
.. autoattribute:: settings_form_fields
|
||||
|
||||
.. automethod:: settings_form_clean
|
||||
|
||||
.. automethod:: settings_content_render
|
||||
|
||||
.. automethod:: is_allowed
|
||||
.. automethod:: render_invoice_text
|
||||
|
||||
.. automethod:: payment_form_render
|
||||
|
||||
.. automethod:: payment_form
|
||||
|
||||
.. automethod:: is_allowed
|
||||
|
||||
.. autoattribute:: payment_form_fields
|
||||
|
||||
.. automethod:: payment_is_valid_session
|
||||
|
||||
.. automethod:: checkout_prepare
|
||||
|
||||
.. automethod:: payment_is_valid_session
|
||||
|
||||
.. automethod:: checkout_confirm_render
|
||||
|
||||
This is an abstract method, you **must** override this!
|
||||
|
||||
.. automethod:: execute_payment
|
||||
|
||||
.. automethod:: calculate_fee
|
||||
.. automethod:: payment_perform
|
||||
|
||||
.. automethod:: order_pending_mail_render
|
||||
|
||||
.. automethod:: payment_pending_render
|
||||
.. automethod:: order_pending_render
|
||||
|
||||
.. autoattribute:: abort_pending_allowed
|
||||
|
||||
.. automethod:: render_invoice_text
|
||||
This is an abstract method, you **must** override this!
|
||||
|
||||
.. automethod:: order_change_allowed
|
||||
|
||||
.. automethod:: payment_prepare
|
||||
.. automethod:: order_can_retry
|
||||
|
||||
.. automethod:: payment_control_render
|
||||
.. automethod:: order_prepare
|
||||
|
||||
.. automethod:: payment_refund_supported
|
||||
.. automethod:: order_paid_render
|
||||
|
||||
.. automethod:: payment_partial_refund_supported
|
||||
.. automethod:: order_control_render
|
||||
|
||||
.. automethod:: execute_refund
|
||||
.. automethod:: order_control_refund_render
|
||||
|
||||
.. automethod:: refund_control_render
|
||||
|
||||
.. automethod:: api_payment_details
|
||||
|
||||
.. automethod:: matching_id
|
||||
|
||||
.. automethod:: shred_payment_info
|
||||
|
||||
.. automethod:: cancel_payment
|
||||
|
||||
.. autoattribute:: is_implicit
|
||||
|
||||
.. autoattribute:: is_meta
|
||||
|
||||
.. autoattribute:: test_mode_message
|
||||
|
||||
.. autoattribute:: requires_invoice_immediately
|
||||
.. automethod:: order_control_refund_perform
|
||||
|
||||
|
||||
Additional views
|
||||
@@ -142,9 +114,7 @@ it is necessary to introduce additional views. One example is the PayPal
|
||||
provider. It redirects the user to a PayPal website in the
|
||||
:py:meth:`BasePaymentProvider.checkout_prepare` step of the checkout process
|
||||
and provides PayPal with a URL to redirect back to. This URL points to a
|
||||
view which looks roughly like this:
|
||||
|
||||
.. code-block:: python
|
||||
view which looks roughly like this::
|
||||
|
||||
@login_required
|
||||
def success(request):
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. _`payment2.0`:
|
||||
|
||||
Porting a payment provider from pretix 1.x to pretix 2.x
|
||||
========================================================
|
||||
|
||||
In pretix 2.x, we changed large parts of the payment provider API. This documentation details the changes we made
|
||||
and shows you how you can make an existing pretix 1.x payment provider compatible with pretix 2.x
|
||||
|
||||
Conceptual overview
|
||||
-------------------
|
||||
|
||||
In pretix 1.x, an order was always directly connected to a payment provider for the full life of an order. As long as
|
||||
an order was unpaid, this could still be changed in some cases, but once an order was paid, no changes to the payment
|
||||
provider were possible any more. Additionally, the internal state of orders allowed orders only to be fully paid or
|
||||
not paid at all. This leads to a couple of consequences:
|
||||
|
||||
* Payment-related functions (like "execute payment" or "do a refund") always operated on full orders.
|
||||
|
||||
* Changing the total of an order was basically impossible once an order was paid, since there was no concept of
|
||||
partial payments or partial refunds.
|
||||
|
||||
* Payment provider plugins needed to take complicated steps to detect cases that require human intervention, like e.g.
|
||||
|
||||
* An order has expired, no quota is left to revive it, but a payment has been received
|
||||
|
||||
* A payment has been received for a canceled order
|
||||
|
||||
* A payment has been received for an order that has already been paid with a different payment method
|
||||
|
||||
* An external payment service notified us of a refund/dispute
|
||||
|
||||
We noticed that we copied and repeated large portions of code in all our official payment provider plugins, just
|
||||
to deal with some of these cases.
|
||||
|
||||
* Sometimes, there is the need to mark an order as refunded within pretix, without automatically triggering a refund
|
||||
with an external API. Every payment method needed to implement a user interface for this independently.
|
||||
|
||||
* If a refund was not possible automatically, there was no way user to track which payments actually have been refunded
|
||||
manually and which are still left to do.
|
||||
|
||||
* When the payment with one payment provider failed and the user changed to a different payment provider, all
|
||||
information about the first payment was lost from the order object and could only be retrieved from order log data,
|
||||
which also made it hard to design a data shredder API to get rid of this data.
|
||||
|
||||
In pretix 2.x, we introduced two new models, :py:class:`OrderPayment <pretix.base.models.OrderPayment>` and
|
||||
:py:class:`OrderRefund <pretix.base.models.OrderRefund>`. Each instance of these is connected to an order and
|
||||
represents one single attempt to pay or refund a specific amount of money. Each one of these has an individual state,
|
||||
can individually fail or succeed, and carries an amount variable that can differ from the order total.
|
||||
|
||||
This has the following advantages:
|
||||
|
||||
* The system can now detect orders that are over- or underpaid, independent of the payment providers in use.
|
||||
|
||||
* Therefore, we can now allow partial payments, partial refunds, and changing paid orders, and automatically detect
|
||||
the cases listed above and notify the user.
|
||||
|
||||
Payment providers now interact with those payment and refund objects more than with orders.
|
||||
|
||||
Your to-do list
|
||||
---------------
|
||||
|
||||
Payment processing
|
||||
""""""""""""""""""
|
||||
|
||||
* The method ``BasePaymentProvider.order_pending_render`` has been removed and replaced by a new
|
||||
``BasePaymentProvider.payment_pending_render(request, payment)`` method that is passed an ``OrderPayment``
|
||||
object instead of an ``Order``.
|
||||
|
||||
* The method ``BasePaymentProvider.payment_form_render`` now receives a new ``total`` parameter.
|
||||
|
||||
* The method ``BasePaymentProvider.payment_perform`` has been removed and replaced by a new method
|
||||
``BasePaymentProvider.execute_payment(request, payment)`` that is passed an ``OrderPayment``
|
||||
object instead of an ``Order``.
|
||||
|
||||
* The function ``pretix.base.services.mark_order_paid`` has been removed, instead call ``payment.confirm()``
|
||||
on a pending ``OrderPayment`` object. If no further payments are required for this order, this will also
|
||||
mark the order as paid automatically. Note that ``payment.confirm()`` can still throw a ``QuotaExceededException``,
|
||||
however it will still mark the payment as complete (not the order!), so you should catch this exception and
|
||||
inform the user, but not abort the transaction.
|
||||
|
||||
* A new property ``BasePaymentProvider.abort_pending_allowed`` has been introduced. Only if set, the user will
|
||||
be able to retry a payment or switch the payment method when the order currently has a payment object in
|
||||
state ``"pending"``. This replaces ``BasePaymentProvider.order_can_retry``, which no longer exists.
|
||||
|
||||
* The methods ``BasePaymentProvider.retry_prepare`` and ``BasePaymentProvider.order_prepare`` have both been
|
||||
replaced by a new method ``BasePaymentProvider.payment_prepare(request, payment)`` that is passed an ``OrderPayment``
|
||||
object instead of an ``Order``. **Keep in mind that this payment object might have an amount property that
|
||||
differs from the order total, if the order is already partially paid.**
|
||||
|
||||
* The method ``BasePaymentProvider.order_paid_render`` has been removed.
|
||||
|
||||
* The method ``BasePaymentProvider.order_control_render`` has been removed and replaced by a new method
|
||||
``BasePaymentProvider.payment_control_render(request, payment)`` that is passed an ``OrderPayment``
|
||||
object instead of an ``Order``.
|
||||
|
||||
* There's no need to manually deal with excess payments or duplicate payments anymore, just setting the ``OrderPayment``
|
||||
methods to the correct state will do the job.
|
||||
|
||||
Creating refunds
|
||||
""""""""""""""""
|
||||
|
||||
* The methods ``BasePaymentProvider.order_control_refund_render`` and ``BasePaymentProvider.order_control_refund_perform``
|
||||
have been removed.
|
||||
|
||||
* Two new boolean methods ``BasePaymentProvider.payment_refund_supported(payment)`` and ``BasePaymentProvider.payment_partial_refund_supported(payment)``
|
||||
have been introduced. They should be set to return ``True`` if and only if the payment API allows to *automatically*
|
||||
transfer the money back to the customer.
|
||||
|
||||
* A new method ``BasePaymentProvider.execute_refund(refund)`` has been introduced. This method is called using a
|
||||
``OrderRefund`` object in ``"created"`` state and is expected to transfer the money back and confirm success with
|
||||
calling ``refund.done()``. This will only ever be called if either ``BasePaymentProvider.payment_refund_supported(payment)``
|
||||
or ``BasePaymentProvider.payment_partial_refund_supported(payment)`` return ``True``.
|
||||
|
||||
Processing external refunds
|
||||
"""""""""""""""""""""""""""
|
||||
|
||||
* If e.g. a webhook API notifies you that a payment has been disputed or refunded with the external API, you are
|
||||
expected to call ``OrderPayment.create_external_refund(self, amount, execution_date, info='{}')`` on this payment.
|
||||
This will create and return an appropriate ``OrderRefund`` object and send out a notification. However, it will not
|
||||
mark the order as refunded, but will ask the event organizer for a decision.
|
||||
|
||||
Data shredders
|
||||
""""""""""""""
|
||||
|
||||
* The method ``BasePaymentProvider.shred_payment_info`` is no longer passed an order, but instead **either**
|
||||
an ``OrderPayment`` **or** an ``OrderRefund``.
|
||||
@@ -1,83 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
Writing an e-mail placeholder plugin
|
||||
====================================
|
||||
|
||||
An email placeholder is a dynamic value that pretix users can use in their email templates.
|
||||
|
||||
Please read :ref:`Creating a plugin <pluginsetup>` first, if you haven't already.
|
||||
|
||||
Placeholder registration
|
||||
------------------------
|
||||
|
||||
The placeholder API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available email placeholders. Your plugin
|
||||
should listen for this signal and return an instance of a subclass of ``pretix.base.email.BaseMailTextPlaceholder``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_mail_placeholders
|
||||
|
||||
|
||||
@receiver(register_mail_placeholders, dispatch_uid="placeholder_custom")
|
||||
def register_mail_renderers(sender, **kwargs):
|
||||
from .email import MyPlaceholderClass
|
||||
return MyPlaceholder()
|
||||
|
||||
|
||||
Context mechanism
|
||||
-----------------
|
||||
|
||||
Emails are sent in different "contexts" within pretix. For example, many emails are sent in the
|
||||
the context of an order, but some are not, such as the notification of a waiting list voucher.
|
||||
|
||||
Not all placeholders make sense in every email, and placeholders usually depend some parameters
|
||||
themselves, such as the ``Order`` object. Therefore, placeholders are expected to explicitly declare
|
||||
what values they depend on and they will only be available in an email if all those dependencies are
|
||||
met. Currently, placeholders can depend on the following context parameters:
|
||||
|
||||
* ``event``
|
||||
* ``order``
|
||||
* ``position``
|
||||
* ``waiting_list_entry``
|
||||
* ``invoice_address``
|
||||
* ``payment``
|
||||
|
||||
There are a few more that are only to be used internally but not by plugins.
|
||||
|
||||
The placeholder class
|
||||
---------------------
|
||||
|
||||
.. class:: pretix.base.email.BaseMailTextPlaceholder
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: required_context
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. automethod:: render
|
||||
|
||||
This is an abstract method, you **must** implement this!
|
||||
|
||||
.. automethod:: render_sample
|
||||
|
||||
This is an abstract method, you **must** implement this!
|
||||
|
||||
Helper class for simple placeholders
|
||||
------------------------------------
|
||||
|
||||
pretix ships with a helper class that makes it easy to provide placeholders based on simple
|
||||
functions:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
placeholder = SimpleFunctionalMailTextPlaceholder(
|
||||
'code', ['order'], lambda order: order.code, sample='F8VVL'
|
||||
)
|
||||
|
||||
@@ -46,27 +46,18 @@ name string The human-readable name of your plugin
|
||||
author string Your name
|
||||
version string A human-readable version code of your plugin
|
||||
description string A more verbose description of what your plugin does.
|
||||
category string Category of a plugin. Either one of ``"FEATURE"``, ``"PAYMENT"``,
|
||||
``"INTEGRATION"``, ``"CUSTOMIZATION"``, ``"FORMAT"``, or ``"API"``,
|
||||
or any other string.
|
||||
visible boolean (optional) ``True`` by default, can hide a plugin so it cannot be normally activated.
|
||||
restricted boolean (optional) ``False`` by default, restricts a plugin such that it can only be enabled
|
||||
for an event by system administrators / superusers.
|
||||
compatibility string Specifier for compatible pretix versions.
|
||||
================== ==================== ===========================================================
|
||||
|
||||
A working example would be:
|
||||
A working example would be::
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
from pretix.base.plugins import PluginConfig
|
||||
except ImportError:
|
||||
raise RuntimeError("Please use pretix 2.7 or above to run this plugin!")
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class PaypalApp(PluginConfig):
|
||||
class PaypalApp(AppConfig):
|
||||
name = 'pretix_paypal'
|
||||
verbose_name = _("PayPal")
|
||||
|
||||
@@ -74,33 +65,26 @@ A working example would be:
|
||||
name = _("PayPal")
|
||||
author = _("the pretix team")
|
||||
version = '1.0.0'
|
||||
category = 'PAYMENT
|
||||
visible = True
|
||||
restricted = False
|
||||
description = _("This plugin allows you to receive payments via PayPal")
|
||||
compatibility = "pretix>=2.7.0"
|
||||
|
||||
|
||||
default_app_config = 'pretix_paypal.PaypalApp'
|
||||
|
||||
The ``AppConfig`` class may implement a property ``compatibility_errors``, that checks
|
||||
The ``AppConfig`` class may implement a property ``compatiblity_errors``, that checks
|
||||
whether the pretix installation meets all requirements of the plugin. If so,
|
||||
it should contain ``None`` or an empty list, otherwise a list of strings containing
|
||||
human-readable error messages. We recommend using the ``django.utils.functional.cached_property``
|
||||
decorator, as it might get called a lot. You can also implement ``compatibility_warnings``,
|
||||
those will be displayed but not block the plugin execution.
|
||||
|
||||
The ``AppConfig`` class may implement a method ``is_available(event)`` that checks if a plugin
|
||||
is available for a specific event. If not, it will not be shown in the plugin list of that event.
|
||||
|
||||
Plugin registration
|
||||
-------------------
|
||||
|
||||
Somehow, pretix needs to know that your plugin exists at all. For this purpose, we
|
||||
make use of the `entry point`_ feature of setuptools. To register a plugin that lives
|
||||
in a separate python package, your ``setup.py`` should contain something like this:
|
||||
|
||||
.. code-block:: python
|
||||
in a separate python package, your ``setup.py`` should contain something like this::
|
||||
|
||||
setup(
|
||||
args...,
|
||||
@@ -122,9 +106,7 @@ The various components of pretix define a number of signals which your plugin ca
|
||||
listen for. We will go into the details of the different signals in the following
|
||||
pages. We suggest that you put your signal receivers into a ``signals`` submodule
|
||||
of your plugin. You should extend your ``AppConfig`` (see above) by the following
|
||||
method to make your receivers available:
|
||||
|
||||
.. code-block:: python
|
||||
method to make your receivers available::
|
||||
|
||||
class PaypalApp(AppConfig):
|
||||
…
|
||||
@@ -133,9 +115,7 @@ method to make your receivers available:
|
||||
from . import signals # NOQA
|
||||
|
||||
You can optionally specify code that is executed when your plugin is activated for an event
|
||||
in the ``installed`` method:
|
||||
|
||||
.. code-block:: python
|
||||
in the ``installed`` method::
|
||||
|
||||
class PaypalApp(AppConfig):
|
||||
…
|
||||
@@ -144,7 +124,7 @@ in the ``installed`` method:
|
||||
pass # Your code here
|
||||
|
||||
|
||||
Note that ``installed`` will *not* be called if the plugin is indirectly activated for an event
|
||||
Note that ``installed`` will *not* be called if the plugin in indirectly activated for an event
|
||||
because the event is created with settings copied from another event.
|
||||
|
||||
Views
|
||||
@@ -159,8 +139,8 @@ your Django app label.
|
||||
with checking that the calling user is logged in, has appropriate permissions,
|
||||
etc. We plan on providing native support for this in a later version.
|
||||
|
||||
.. _Django app: https://docs.djangoproject.com/en/3.0/ref/applications/
|
||||
.. _signal dispatcher: https://docs.djangoproject.com/en/3.0/topics/signals/
|
||||
.. _namespace packages: https://legacy.python.org/dev/peps/pep-0420/
|
||||
.. _entry point: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#locating-plugins
|
||||
.. _Django app: https://docs.djangoproject.com/en/1.7/ref/applications/
|
||||
.. _signal dispatcher: https://docs.djangoproject.com/en/1.7/topics/signals/
|
||||
.. _namespace packages: http://legacy.python.org/dev/peps/pep-0420/
|
||||
.. _entry point: https://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins
|
||||
.. _cookiecutter: https://cookiecutter.readthedocs.io/en/latest/
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. _`pluginquality`:
|
||||
|
||||
Plugin quality checklist
|
||||
========================
|
||||
|
||||
If you want to write a high-quality pretix plugin, this is a list of things you should check before
|
||||
you publish it. This is also a list of things that we check, if we consider installing an externally
|
||||
developed plugin on our hosted infrastructure.
|
||||
|
||||
A. Meta
|
||||
-------
|
||||
|
||||
#. The plugin is clearly licensed under an appropriate license.
|
||||
|
||||
#. The plugin has an unambiguous name, description, and author metadata.
|
||||
|
||||
#. The plugin has a clear versioning scheme and the latest version of the plugin is kept compatible to the latest
|
||||
stable version of pretix.
|
||||
|
||||
#. The plugin is properly packaged using standard Python packaging tools.
|
||||
|
||||
#. The plugin correctly declares its external dependencies.
|
||||
|
||||
#. A contact address is provided in case of security issues.
|
||||
|
||||
B. Isolation
|
||||
------------
|
||||
|
||||
#. If any signal receivers use the `dispatch_uid`_ feature, the UIDs are prefixed by the plugin's name and do not
|
||||
clash with other plugins.
|
||||
|
||||
#. If any templates or static files are shipped, they are located in subdirectories with the name of the plugin and do
|
||||
not clash with other plugins or core files.
|
||||
|
||||
#. Any keys stored to the settings store are prefixed with the plugin's name and do not clash with other plugins or
|
||||
core.
|
||||
|
||||
#. Any keys stored to the user session are prefixed with the plugin's name and do not clash with other plugins or
|
||||
core.
|
||||
|
||||
#. Any registered URLs are unlikely to clash with other plugins or future core URLs.
|
||||
|
||||
C. Security
|
||||
-----------
|
||||
|
||||
#. All important actions are logged to the :ref:`shared log storage <logging>` and a signal receiver is registered to
|
||||
provide a human-readable representation of the log entry.
|
||||
|
||||
#. All views require appropriate permissions and use the ``event_urls`` mechanism if appropriate.
|
||||
:ref:`Read more <customview>`
|
||||
|
||||
#. Any session data for customers is stored in the cart session system if appropriate.
|
||||
|
||||
#. If the plugin is a payment provider:
|
||||
|
||||
#. No credit card numbers may be stored within pretix.
|
||||
|
||||
#. A notification/webhook system is implemented to notify pretix of any refunds.
|
||||
|
||||
#. If such a webhook system is implemented, contents of incoming webhooks are either verified using a cryptographic
|
||||
signature or are not being trusted and all data is fetched from an API instead.
|
||||
|
||||
D. Privacy
|
||||
----------
|
||||
|
||||
#. No personal data is stored that is not required for the plugin's functionality.
|
||||
|
||||
#. For any personal data that is saved to the database, an appropriate :ref:`data shredder <shredder>` is provided
|
||||
that offers the data for download and then removes it from the database (including log entries).
|
||||
|
||||
E. Internationalization
|
||||
-----------------------
|
||||
|
||||
#. All user-facing strings in templates, Python code, and templates are wrapped in `gettext calls`_.
|
||||
|
||||
#. No languages, time zones, date formats, or time formats are hardcoded.
|
||||
|
||||
#. Installing the plugin automatically compiles ``.po`` files to ``.mo`` files. This is fulfilled automatically if
|
||||
you use the ``setup.py`` file form our plugin cookiecutter.
|
||||
|
||||
F. Functionality
|
||||
----------------
|
||||
|
||||
#. If the plugin adds any database models or relationships from the settings storage to database models, it registers
|
||||
a receiver to the :py:attr:`pretix.base.signals.event_copy_data` or :py:attr:`pretix.base.signals.item_copy_data`
|
||||
signals.
|
||||
|
||||
#. If the plugin is a payment provider:
|
||||
|
||||
#. A webhook-like system is implemented if payment confirmations are not sent instantly.
|
||||
|
||||
#. Refunds are implemented, if possible.
|
||||
|
||||
#. In case of overpayment or external refunds, a "required action" is created to notify the event organizer.
|
||||
|
||||
#. If the plugin adds steps to the checkout process, it has been tested in combination with the pretix widget.
|
||||
|
||||
G. Code quality
|
||||
---------------
|
||||
|
||||
#. `isort`_ and `flake8`_ are used to ensure consistent code styling.
|
||||
|
||||
#. Unit tests are provided for important pieces of business logic.
|
||||
|
||||
#. Functional tests are provided for important interface parts.
|
||||
|
||||
#. Tests are provided to check that permission checks are working.
|
||||
|
||||
#. Continuous Integration is set up to check that tests are passing and styling is consistent.
|
||||
|
||||
H. Specific to pretix.eu
|
||||
------------------------
|
||||
|
||||
#. pretix.eu integrates the data stored by this plugin with its data report features.
|
||||
|
||||
#. pretix.eu integrates this plugin in its generated privacy statements, if necessary.
|
||||
|
||||
|
||||
.. _isort: https://www.google.de/search?q=isort&oq=isort&aqs=chrome..69i57j0j69i59j69i60l2j69i59.599j0j4&sourceid=chrome&ie=UTF-8
|
||||
.. _flake8: http://flake8.pycqa.org/en/latest/
|
||||
.. _gettext calls: https://docs.djangoproject.com/en/2.0/topics/i18n/translation/
|
||||
.. _dispatch_uid: https://docs.djangoproject.com/en/2.0/topics/signals/#django.dispatch.Signal.connect
|
||||
@@ -1,94 +0,0 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. _`shredder`:
|
||||
|
||||
Writing a data shredder
|
||||
=======================
|
||||
|
||||
If your plugin adds the ability to store personal data within pretix, you should also implement a "data shredder"
|
||||
to anonymize or pseudonymize the data later.
|
||||
|
||||
Shredder registration
|
||||
---------------------
|
||||
|
||||
The data shredder API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available data shredders. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.shredder.BaseDataShredder``
|
||||
that we'll provide in this plugin:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_data_shredders
|
||||
|
||||
|
||||
@receiver(register_data_shredders, dispatch_uid="custom_data_shredders")
|
||||
def register_shredder(sender, **kwargs):
|
||||
return [
|
||||
PluginDataShredder,
|
||||
]
|
||||
|
||||
The shredder class
|
||||
------------------
|
||||
|
||||
.. class:: pretix.base.shredder.BaseDataShredder
|
||||
|
||||
The central object of each data shredder is the subclass of ``BaseDataShredder``.
|
||||
|
||||
.. py:attribute:: BaseDataShredder.event
|
||||
|
||||
The default constructor sets this property to the event we are currently
|
||||
working for.
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: verbose_name
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: description
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. automethod:: generate_files
|
||||
|
||||
.. automethod:: shred_data
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
For example, the core data shredder responsible for removing invoice address information including their history
|
||||
looks like this:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
class InvoiceAddressShredder(BaseDataShredder):
|
||||
verbose_name = _('Invoice addresses')
|
||||
identifier = 'invoice_addresses'
|
||||
description = _('This will remove all invoice addresses from orders, '
|
||||
'as well as logged changes to them.')
|
||||
|
||||
def generate_files(self) -> List[Tuple[str, str, str]]:
|
||||
yield 'invoice-addresses.json', 'application/json', json.dumps({
|
||||
ia.order.code: InvoiceAddressSerializer(ia).data
|
||||
for ia in InvoiceAddress.objects.filter(order__event=self.event)
|
||||
}, indent=4)
|
||||
|
||||
@transaction.atomic
|
||||
def shred_data(self):
|
||||
InvoiceAddress.objects.filter(order__event=self.event).delete()
|
||||
|
||||
for le in self.event.logentry_set.filter(action_type="pretix.event.order.modified"):
|
||||
d = le.parsed_data
|
||||
if 'invoice_data' in d and not isinstance(d['invoice_data'], bool):
|
||||
for field in d['invoice_data']:
|
||||
if d['invoice_data'][field]:
|
||||
d['invoice_data'][field] = '█'
|
||||
le.data = json.dumps(d)
|
||||
le.shredded = True
|
||||
le.save(update_fields=['data', 'shredded'])
|
||||
|
||||
@@ -17,9 +17,7 @@ Output registration
|
||||
The ticket output API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available ticket outputs. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.ticketoutput.BaseTicketOutput``
|
||||
that we'll provide in this plugin:
|
||||
|
||||
.. code-block:: python
|
||||
that we'll provide in this plugin::
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
@@ -71,13 +69,3 @@ The output class
|
||||
.. automethod:: generate_order
|
||||
|
||||
.. autoattribute:: download_button_text
|
||||
|
||||
.. autoattribute:: download_button_icon
|
||||
|
||||
.. autoattribute:: multi_download_button_text
|
||||
|
||||
.. autoattribute:: long_download_button_text
|
||||
|
||||
.. autoattribute:: preview_allowed
|
||||
|
||||
.. autoattribute:: javascript_required
|
||||
|
||||
@@ -82,12 +82,6 @@ Orders
|
||||
^^^^^^
|
||||
|
||||
If a customer completes the checkout process, an **Order** will be created containing all the entered information.
|
||||
An order can be in one of currently four states that are listed in the diagram below:
|
||||
An order can be in one of currently five states that are listed in the diagram below:
|
||||
|
||||
.. image:: /images/order_states.png
|
||||
|
||||
There are additional "fake" states that are displayed like states but not represented as states in the system:
|
||||
|
||||
* An order is considered **canceled (with paid fee)** if it is in **paid** status but does not include any non-cancelled positions.
|
||||
|
||||
* An order is considered **requiring approval** if it is in **pending** status with the ``require_approval`` attribute set to ``True``.
|
||||
|
||||
@@ -77,6 +77,6 @@ Attribution
|
||||
-----------
|
||||
|
||||
This Code of Conduct is adapted from the `Contributor Covenant`_, version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/
|
||||
available at http://contributor-covenant.org/version/1/4/
|
||||
|
||||
.. _Contributor Covenant: https://www.contributor-covenant.org
|
||||
.. _Contributor Covenant: http://contributor-covenant.org
|
||||
|
||||
@@ -7,7 +7,7 @@ Coding style and quality
|
||||
for more information. Use four spaces for indentation.
|
||||
|
||||
* We sort our imports by a certain schema, but you don't have to do this by hand. Again, ``setup.cfg`` contains
|
||||
some definitions that allow the command ``isort <directory>`` to automatically sort the imports in your source
|
||||
some definitions that allow the command ``isort -rc <directory>`` to automatically sort the imports in your source
|
||||
files.
|
||||
|
||||
* For templates and models, please take a look at the `Django Coding Style`_. We like Django's `class-based views`_ and
|
||||
@@ -18,13 +18,13 @@ Coding style and quality
|
||||
* We expect all new code to come with proper tests. When writing new tests, please write them using `pytest-style`_
|
||||
test functions and raw ``assert`` statements. Use `fixtures`_ to prevent repetitive code. Some old parts of pretix'
|
||||
test suite are in the style of Python's unit test module. If you extend those files, you might continue in this style,
|
||||
but please use ``pytest`` style for any new test files.
|
||||
but please use pytest style for any new test files.
|
||||
|
||||
* Please keep the first line of your commit messages short. When referencing an issue, please phrase it like
|
||||
``Fix #123 -- Problems with order creation`` or ``Refs #123 -- Fix this part of that bug``.
|
||||
|
||||
|
||||
.. _PEP 8: https://legacy.python.org/dev/peps/pep-0008/
|
||||
.. _PEP 8: http://legacy.python.org/dev/peps/pep-0008/
|
||||
.. _flake8: https://pypi.python.org/pypi/flake8
|
||||
.. _Django Coding Style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/
|
||||
.. _translation: https://docs.djangoproject.com/en/1.11/topics/i18n/translation/
|
||||
|
||||
@@ -12,9 +12,7 @@ Implementing a task
|
||||
-------------------
|
||||
|
||||
A common pattern for implementing asynchronous tasks can be seen a lot in ``pretix.base.services``
|
||||
and looks like this:
|
||||
|
||||
.. code-block:: python
|
||||
and looks like this::
|
||||
|
||||
from pretix.celery_app import app
|
||||
|
||||
@@ -36,15 +34,13 @@ If your user needs to wait for the response of the asynchronous task, there are
|
||||
that will probably move to ``pretix.base`` at some point. They consist of the view mixin ``AsyncAction`` that allows
|
||||
you to easily write a view that kicks off and waits for an asynchronous task. ``AsyncAction`` will determine whether
|
||||
to run the task asynchronously or not and will do some magic to look nice for users with and without JavaScript support.
|
||||
A usage example taken directly from the code is:
|
||||
|
||||
.. code-block:: python
|
||||
A usage example taken directly from the code is::
|
||||
|
||||
class OrderCancelDo(EventViewMixin, OrderDetailMixin, AsyncAction, View):
|
||||
"""
|
||||
A view that executes a task asynchronously. A POST request will kick off the
|
||||
task into the background or run it in the foreground if celery is not installed.
|
||||
In the former case, subsequent GET calls can be used to determine the current
|
||||
In the former case, subsequent GET calls can be used to determinine the current
|
||||
status of the task.
|
||||
"""
|
||||
|
||||
@@ -83,9 +79,7 @@ A usage example taken directly from the code is:
|
||||
return super().get_error_message(exception)
|
||||
|
||||
On the client side, this can be used by simply adding a ``data-asynctask`` attribute to an HTML form. This will enable
|
||||
AJAX sending of the form and display a loading indicator:
|
||||
|
||||
.. code-block:: html
|
||||
AJAX sending of the form and display a loading indicator::
|
||||
|
||||
<form method="post" data-asynctask
|
||||
action="{% eventurl request.event "presale:event.order.cancel.do" … %}">
|
||||
|
||||
@@ -27,9 +27,7 @@ numbers and dates, ``LazyDate`` and ``LazyNumber``. There also is a ``LazyLocale
|
||||
exceptions with gettext-localized exception messages.
|
||||
|
||||
Last, but definitely not least, we have the ``language`` context manager (``pretix.base.i18n.language``) that allows
|
||||
you to execute a piece of code with a different locale:
|
||||
|
||||
.. code-block:: python
|
||||
you to execute a piece of code with a different locale::
|
||||
|
||||
with language('de'):
|
||||
render_mail_template()
|
||||
|
||||
@@ -16,5 +16,4 @@ Contents:
|
||||
settings
|
||||
background
|
||||
email
|
||||
permissions
|
||||
logging
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
Logging and notifications
|
||||
=========================
|
||||
Logging
|
||||
=======
|
||||
|
||||
As pretix is handling monetary transactions, we are very careful to make it possible to review all changes
|
||||
in the system that lead to the current state.
|
||||
|
||||
.. _`logging`:
|
||||
|
||||
Logging changes
|
||||
---------------
|
||||
|
||||
@@ -16,14 +14,12 @@ We recommend all relevant models to inherit from ``LoggedModel`` as it simplifie
|
||||
.. autoclass:: pretix.base.models.LoggedModel
|
||||
:members: log_action, all_logentries
|
||||
|
||||
To actually log an action, you can just call the ``log_action`` method on your object:
|
||||
|
||||
.. code-block:: python
|
||||
To actually log an action, you can just call the ``log_action`` method on your object::
|
||||
|
||||
order.log_action('pretix.event.order.canceled', user=user, data={})
|
||||
|
||||
The positional ``action`` argument should represent the type of action and should be globally unique, we
|
||||
recommend to prefix it with your package name, e.g. ``paypal.payment.rejected``. The ``user`` argument is
|
||||
recomment do prefix it with your packagename, e.g. ``paypal.payment.rejected``. The ``user`` argument is
|
||||
optional and may contain the user who performed the action. The optional ``data`` argument can contain
|
||||
additional information about this action.
|
||||
|
||||
@@ -31,9 +27,7 @@ Logging form actions
|
||||
""""""""""""""""""""
|
||||
|
||||
A very common use case is to log the changes to a model that have been done in a ``ModelForm``. In this case,
|
||||
we generally use a custom ``form_valid`` method on our ``FormView`` that looks like this:
|
||||
|
||||
.. code-block:: python
|
||||
we generally use a custom ``form_valid`` method on our ``FormView`` that looks like this::
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
@@ -44,9 +38,7 @@ we generally use a custom ``form_valid`` method on our ``FormView`` that looks l
|
||||
messages.success(self.request, _('Your changes have been saved.'))
|
||||
return super().form_valid(form)
|
||||
|
||||
It gets a little bit more complicated if your form allows file uploads:
|
||||
|
||||
.. code-block:: python
|
||||
It gets a little bit more complicated if your form allows file uploads::
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
@@ -73,11 +65,9 @@ following ready-to-include template::
|
||||
|
||||
We now need a way to translate the action codes like ``pretix.event.changed`` into human-readable
|
||||
strings. The :py:attr:`pretix.base.signals.logentry_display` signals allows you to do so. A simple
|
||||
implementation could look like:
|
||||
implementation could look like::
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import ugettext as _
|
||||
from pretix.base.signals import logentry_display
|
||||
|
||||
@receiver(signal=logentry_display)
|
||||
@@ -91,73 +81,12 @@ implementation could look like:
|
||||
if logentry.action_type in plains:
|
||||
return plains[logentry.action_type]
|
||||
|
||||
Sending notifications
|
||||
---------------------
|
||||
|
||||
If you think that the logged information might be important or urgent enough to send out a notification to interested
|
||||
organizers. In this case, you should listen for the :py:attr:`pretix.base.signals.register_notification_types` signal
|
||||
to register a notification type:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@receiver(register_notification_types)
|
||||
def register_my_notification_types(sender, **kwargs):
|
||||
return [MyNotificationType(sender)]
|
||||
|
||||
Note that this event is different than other events send out by pretix: ``sender`` may be an event or ``None``. The
|
||||
latter case is required to let the user define global notification preferences for all events.
|
||||
|
||||
You also need to implement a custom class that specifies how notifications should be handled for your notification type.
|
||||
You should subclass the base ``NotificationType`` class and implement all its members:
|
||||
|
||||
.. autoclass:: pretix.base.notifications.NotificationType
|
||||
:members: action_type, verbose_name, required_permission, build_notification
|
||||
|
||||
A simple implementation could look like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyNotificationType(NotificationType):
|
||||
required_permission = "can_view_orders"
|
||||
action_type = "pretix.event.order.paid"
|
||||
verbose_name = _("Order has been paid")
|
||||
|
||||
def build_notification(self, logentry: LogEntry):
|
||||
order = logentry.content_object
|
||||
|
||||
order_url = build_absolute_uri(
|
||||
'control:event.order',
|
||||
kwargs={
|
||||
'organizer': logentry.event.organizer.slug,
|
||||
'event': logentry.event.slug,
|
||||
'code': order.code
|
||||
}
|
||||
)
|
||||
|
||||
n = Notification(
|
||||
event=logentry.event,
|
||||
title=_('Order {code} has been marked as paid').format(code=order.code),
|
||||
url=order_url
|
||||
)
|
||||
n.add_attribute(_('Order code'), order.code)
|
||||
n.add_action(_('View order details'), order_url)
|
||||
return n
|
||||
|
||||
As you can see, the relevant code is in the ``build_notification`` method that is supposed to create a ``Notification``
|
||||
method that has a title, description, URL, attributes, and actions. The full definition of ``Notification`` is the
|
||||
following:
|
||||
|
||||
.. autoclass:: pretix.base.notifications.Notification
|
||||
:members: add_action, add_attribute
|
||||
|
||||
|
||||
Logging technical information
|
||||
-----------------------------
|
||||
|
||||
If you just want to log technical information to a log file on disk that does not need to be parsed
|
||||
and displayed later, you can just use Python's ``logging`` module:
|
||||
|
||||
.. code-block:: python
|
||||
and displayed later, you can just use Python's ``logging`` module::
|
||||
|
||||
import logging
|
||||
|
||||
@@ -165,9 +94,7 @@ and displayed later, you can just use Python's ``logging`` module:
|
||||
|
||||
logger.info('Startup complete.')
|
||||
|
||||
This is also very useful to provide debugging information when an exception occurs:
|
||||
|
||||
.. code-block:: python
|
||||
This is also very useful to provide debugging information when an exception occurs::
|
||||
|
||||
try:
|
||||
foo()
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. spelling:: answ contrib
|
||||
|
||||
Data model
|
||||
==========
|
||||
|
||||
@@ -23,7 +21,7 @@ Organizers and events
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.Event
|
||||
:members: get_date_from_display, get_time_from_display, get_date_to_display, get_date_range_display, presale_has_ended, presale_is_running, cache, lock, get_plugins, get_mail_backend, payment_term_last, get_payment_providers, get_invoice_renderers, invoice_renderer, settings
|
||||
:members: get_date_from_display, get_time_from_display, get_date_to_display, get_date_range_display, presale_has_ended, presale_is_running, cache, lock, get_plugins, get_mail_backend, payment_term_last, get_payment_providers, get_invoice_renderers, active_subevents, invoice_renderer, settings
|
||||
|
||||
.. autoclass:: pretix.base.models.SubEvent
|
||||
:members: get_date_from_display, get_time_from_display, get_date_to_display, get_date_range_display, presale_has_ended, presale_is_running
|
||||
@@ -31,9 +29,6 @@ Organizers and events
|
||||
.. autoclass:: pretix.base.models.Team
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.TeamAPIToken
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.RequiredAction
|
||||
:members:
|
||||
|
||||
@@ -86,15 +81,6 @@ Carts and Orders
|
||||
.. autoclass:: pretix.base.models.OrderPosition
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.OrderFee
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.OrderPayment
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.OrderRefund
|
||||
:members:
|
||||
|
||||
.. autoclass:: pretix.base.models.CartPosition
|
||||
:members:
|
||||
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
Permissions
|
||||
===========
|
||||
|
||||
pretix uses a fine-grained permission system to control who is allowed to control what parts of the system.
|
||||
The central concept here is the concept of *Teams*. You can read more on `configuring teams and permissions <user-teams>`_
|
||||
and the :class:`pretix.base.models.Team` model in the respective parts of the documentation. The basic digest is:
|
||||
An organizer account can have any number of teams, and any number of users can be part of a team. A team can be
|
||||
assigned a set of permissions and connected to some or all of the events of the organizer.
|
||||
|
||||
A second way to access pretix is via the REST API, which allows authentication via tokens that are bound to a team,
|
||||
but not to a user. You can read more at :class:`pretix.base.models.TeamAPIToken`. This page will show you how to
|
||||
work with permissions in plugins and within the pretix code base.
|
||||
|
||||
Requiring permissions for a view
|
||||
--------------------------------
|
||||
|
||||
pretix provides a number of useful mixins and decorators that allow you to specify that a user needs a certain
|
||||
permission level to access a view:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pretix.control.permissions import (
|
||||
OrganizerPermissionRequiredMixin, organizer_permission_required
|
||||
)
|
||||
|
||||
|
||||
class MyOrgaView(OrganizerPermissionRequiredMixin, View):
|
||||
permission = 'can_change_organizer_settings'
|
||||
# Only users with the permission ``can_change_organizer_settings`` on
|
||||
# this organizer can access this
|
||||
|
||||
|
||||
class MyOtherOrgaView(OrganizerPermissionRequiredMixin, View):
|
||||
permission = None
|
||||
# Only users with *any* permission on this organizer can access this
|
||||
|
||||
|
||||
@organizer_permission_required('can_change_organizer_settings')
|
||||
def my_orga_view(request, organizer, **kwargs):
|
||||
# Only users with the permission ``can_change_organizer_settings`` on
|
||||
# this organizer can access this
|
||||
|
||||
|
||||
@organizer_permission_required()
|
||||
def my_other_orga_view(request, organizer, **kwargs):
|
||||
# Only users with *any* permission on this organizer can access this
|
||||
|
||||
|
||||
Of course, the same is available on event level:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pretix.control.permissions import (
|
||||
EventPermissionRequiredMixin, event_permission_required
|
||||
)
|
||||
|
||||
|
||||
class MyEventView(EventPermissionRequiredMixin, View):
|
||||
permission = 'can_change_event_settings'
|
||||
# Only users with the permission ``can_change_event_settings`` on
|
||||
# this event can access this
|
||||
|
||||
|
||||
class MyOtherEventView(EventPermissionRequiredMixin, View):
|
||||
permission = None
|
||||
# Only users with *any* permission on this event can access this
|
||||
|
||||
|
||||
@event_permission_required('can_change_event_settings')
|
||||
def my_event_view(request, organizer, **kwargs):
|
||||
# Only users with the permission ``can_change_event_settings`` on
|
||||
# this event can access this
|
||||
|
||||
|
||||
@event_permission_required()
|
||||
def my_other_event_view(request, organizer, **kwargs):
|
||||
# Only users with *any* permission on this event can access this
|
||||
|
||||
You can also require that this view is only accessible by system administrators with an active "admin session"
|
||||
(see below for what this means):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pretix.control.permissions import (
|
||||
AdministratorPermissionRequiredMixin, administrator_permission_required
|
||||
)
|
||||
|
||||
|
||||
class MyGlobalView(AdministratorPermissionRequiredMixin, View):
|
||||
# ...
|
||||
|
||||
|
||||
@administrator_permission_required
|
||||
def my_global_view(request, organizer, **kwargs):
|
||||
# ...
|
||||
|
||||
In rare cases it might also be useful to expose a feature only to people who have a staff account but do not
|
||||
necessarily have an active admin session:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pretix.control.permissions import (
|
||||
StaffMemberRequiredMixin, staff_member_required
|
||||
)
|
||||
|
||||
|
||||
class MyGlobalView(StaffMemberRequiredMixin, View):
|
||||
# ...
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def my_global_view(request, organizer, **kwargs):
|
||||
# ...
|
||||
|
||||
|
||||
|
||||
Requiring permissions in the REST API
|
||||
-------------------------------------
|
||||
|
||||
When creating your own ``viewset`` using Django REST framework, you just need to set the ``permission`` attribute
|
||||
and pretix will check it automatically for you::
|
||||
|
||||
class MyModelViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
permission = 'can_view_orders'
|
||||
|
||||
Checking permission in code
|
||||
---------------------------
|
||||
|
||||
If you need to work with permissions manually, there are a couple of useful helper methods on the :class:`pretix.base.models.Event`,
|
||||
:class:`pretix.base.models.User` and :class:`pretix.base.models.TeamAPIToken` classes. Here's a quick overview.
|
||||
|
||||
Return all users that are in any team that is connected to this event::
|
||||
|
||||
>>> event.get_users_with_any_permission()
|
||||
<QuerySet: …>
|
||||
|
||||
Return all users that are in a team with a specific permission for this event::
|
||||
|
||||
>>> event.get_users_with_permission('can_change_event_settings')
|
||||
<QuerySet: …>
|
||||
|
||||
Determine if a user has a certain permission for a specific event::
|
||||
|
||||
>>> user.has_event_permission(organizer, event, 'can_change_event_settings', request=request)
|
||||
True
|
||||
|
||||
Determine if a user has any permission for a specific event::
|
||||
|
||||
>>> user.has_event_permission(organizer, event, request=request)
|
||||
True
|
||||
|
||||
In the two previous commands, the ``request`` argument is optional, but required to support staff sessions (see below).
|
||||
|
||||
The same method exists for organizer-level permissions::
|
||||
|
||||
>>> user.has_organizer_permission(organizer, 'can_change_event_settings', request=request)
|
||||
True
|
||||
|
||||
Sometimes, it might be more useful to get the set of permissions at once::
|
||||
|
||||
>>> user.get_event_permission_set(organizer, event)
|
||||
{'can_change_event_settings', 'can_view_orders', 'can_change_orders'}
|
||||
|
||||
>>> user.get_organizer_permission_set(organizer, event)
|
||||
{'can_change_organizer_settings', 'can_create_events'}
|
||||
|
||||
Within a view on the ``/control`` subpath, the results of these two methods are already available in the
|
||||
``request.eventpermset`` and ``request.orgapermset`` properties. This makes it convenient to query them in templates::
|
||||
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
…
|
||||
{% endif %}
|
||||
|
||||
You can also do the reverse to get any events a user has access to::
|
||||
|
||||
>>> user.get_events_with_permission('can_change_event_settings', request=request)
|
||||
<QuerySet: …>
|
||||
|
||||
>>> user.get_events_with_any_permission(request=request)
|
||||
<QuerySet: …>
|
||||
|
||||
Most of these methods work identically on :class:`pretix.base.models.TeamAPIToken`.
|
||||
|
||||
Staff sessions
|
||||
--------------
|
||||
|
||||
.. versionchanged:: 1.14
|
||||
|
||||
In 1.14, the ``User.is_superuser`` attribute has been deprecated and statically set to return ``False``. Staff
|
||||
sessions have been newly introduced.
|
||||
|
||||
System administrators of a pretix instance are identified by the ``is_staff`` attribute on the user model. By default,
|
||||
the regular permission rules apply for users with ``is_staff = True``. The only difference is that such users can
|
||||
temporarily turn on "staff mode" via a button in the user interface that grants them **all permissions** as long as
|
||||
staff mode is active. You can check if a user is in staff mode using their session key:
|
||||
|
||||
>>> user.has_active_staff_session(request.session.session_key)
|
||||
False
|
||||
|
||||
Staff mode has a hard time limit and during staff mode, a middleware will log all requests made by that user. Later,
|
||||
the user is able to also save a message to comment on what they did in their administrative session. This feature is
|
||||
intended to help compliance with data protection rules as imposed e.g. by GDPR.
|
||||
@@ -35,13 +35,11 @@ Forms
|
||||
-----
|
||||
|
||||
Hierarkey also provides a base class for forms that allow the modification of settings. pretix contains a
|
||||
subclass that also adds support for internationalized fields:
|
||||
subclass that also adds suport for internationalized fields:
|
||||
|
||||
.. autoclass:: pretix.base.forms.SettingsForm
|
||||
|
||||
You can simply use it like this:
|
||||
|
||||
.. code-block:: python
|
||||
You can simply use it like this::
|
||||
|
||||
class EventSettingsForm(SettingsForm):
|
||||
show_date_to = forms.BooleanField(
|
||||
@@ -58,9 +56,7 @@ You can simply use it like this:
|
||||
Defaults in plugins
|
||||
-------------------
|
||||
|
||||
Plugins can add custom hardcoded defaults in the following way:
|
||||
|
||||
.. code-block:: python
|
||||
Plugins can add custom hardcoded defaults in the following way::
|
||||
|
||||
from pretix.base.settings import settings_hierarkey
|
||||
|
||||
@@ -69,4 +65,4 @@ Plugins can add custom hardcoded defaults in the following way:
|
||||
Make sure that you include this code in a module that is imported at app loading time.
|
||||
|
||||
.. _django-hierarkey: https://github.com/raphaelm/django-hierarkey
|
||||
.. _documentation: https://django-hierarkey.readthedocs.io/en/latest/
|
||||
.. _documentation: https://django-hierarkey.readthedocs.io/en/latest/
|
||||
@@ -67,7 +67,7 @@ available as ``plugins:sendmail:send``.
|
||||
Generating a URL for the frontend is a complicated task, because you need to know whether the event's
|
||||
organizer uses a custom URL or not and then generate the URL with a different domain and different
|
||||
arguments based on this information. pretix provides some helpers to make this easier. The first helper
|
||||
is a python method that emulates a behavior similar to ``reverse``:
|
||||
is a python method that emulates a behaviour similar to ``reverse``:
|
||||
|
||||
.. autofunction:: pretix.multidomain.urlreverse.eventreverse
|
||||
|
||||
@@ -82,5 +82,5 @@ Implementation details
|
||||
----------------------
|
||||
|
||||
There are some other caveats when using a design like this, e.g. you have to care about cookie domains
|
||||
and referrer verification yourself. If you want to see how we built this, look into the ``pretix/multidomain/``
|
||||
and referer verification yourself. If you want to see how we built this, look into the ``pretix/multidomain/``
|
||||
sub-tree.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user