Skip to content

omniticket/helloasso

Omniticket's HelloAsso, under any PHP host: an association's event forms with their tiers, the registrations of an event, and a ticket's QR code checked among them - read only, through HelloAsso's API v5 (OAuth2 client credentials).

Floor
Provider · Omniticket
Version
1.x
Conformance suite
not wired
Verified for real
Verified in part
Licence
MIT
composer require omniticket/helloasso:1.x-dev

HelloAsso for omnisense/omniticket: an association's events - its forms of type Event - their tiers, their registrations, and a ticket code checked - through HelloAsso's API v5 (https://api.helloasso.com, documented at https://dev.helloasso.com; the sandbox https://api.helloasso-sandbox.com), with a bearer token from client credentials. An event's id is its form's slug. Reading only.

Operation HelloAsso API v5
token POST /oauth2/token (client credentials)
events() GET /v5/organizations/{slug}/forms?formTypes=Event
event($formSlug) GET /v5/organizations/{slug}/forms/Event/{formSlug}/public
attendees($formSlug) GET /v5/organizations/{slug}/forms/Event/{formSlug}/items?withDetails=true
check($formSlug, $code) the items, read whole

Lists come in pages of 100 by continuation token.

HelloAsso publishes a PHP SDK, helloasso/helloasso-php; it is not wrapped: it is GPL-3.0-or-later (this family is MIT), it brings its own HTTP stack where the family injects the application's client, and its generic OpenAPI\Client namespace collides with other generated clients. Its model documentation is what the tests' answers follow.

Installation

composer require omniticket/helloasso symfony/http-client

Requires PHP 8.2, omnisense/omniticket (1.x) and symfony/http-client-contracts (^3.0).

Credentials

The API client (client id and secret) of the association's back office, "Intégrations et API", and the association's slug, as in https://www.helloasso.com/associations/<slug>.

Options

Option Type Default Required
client_id string - yes
client_secret string - yes
organization string - yes the association's slug
url string https://api.helloasso.com no the sandbox: https://api.helloasso-sandbox.com

Capabilities

Contract Supported
EventCatalogInterface yes
AttendeeListInterface yes, not incremental: $updatedSince is a NotSupportedException
TicketCheckInterface yes, among the items; never "already used"

capabilities(): catalog, attendees, check and widget true, incremental false; terms https://dev.helloasso.com, https://www.helloasso.com/cgu; limits: no rate figure in what was read: keep calls moderate, cache the catalogue, renew the token only when it expires (30 minutes).

Behaviour

Token. Asked for on the first call (a form with grant_type=client_credentials, the id and the secret), kept until a minute before expires_in (1800 seconds when not said; at least 60). No token in the answer: ProviderException HelloAsso gave no access token.

Events. Each form: formSlug as the id, title, startDate, endDate, url, widgetFullUrl as the widget, the place's name and city. Status: Draft draft; Disabled, Deleted sales closed; ended when its end (else start) is past; upcoming before saleStartDate; sales closed after saleEndDate; Public on sale; else unknown. No places left.

One event. The public form, its tiers as rates: id, label, the price in EUR cents - a price of 0 with a minAmount is the buyer's to choose: no price, minAmount as the minimum -, saleStartDate, saleEndDate.

Attendees. One item per ticket: id, qrCode as the code, the user's first and last names, the payer's e-mail, name as the rate, order.id, ticketUrl. Status: a payment Refunded - refunded; Processed, Registered - valid; Waiting, Unknown or none - pending; anything else

  • cancelled. HelloAsso's API, as read, does not say whether a ticket was scanned.

Check. The event's items read, the code looked for among their QR codes: valid, void or unknown, never already used.

Example

<?php

require __DIR__.'/vendor/autoload.php';

use Omniticket\HelloAsso\HelloAssoFactory;
use Omniticket\Registry;
use Symfony\Component\HttpClient\HttpClient;

$registry = new Registry([new HelloAssoFactory(HttpClient::create(['timeout' => 15]))], [
    'asso' => ['factory' => 'helloasso', 'options' => [
        'client_id' => getenv('HELLOASSO_CLIENT_ID'),
        'client_secret' => getenv('HELLOASSO_CLIENT_SECRET'),
        'organization' => 'my-association',
    ]],
]);

foreach ($registry->catalog('asso')->events() as $event) {
    echo $event->title, ': ', $event->widgetUrl, "\n";     // the module to put in a frame
}

Not run live (no account). The incremental refusal was run on 2026-10-26: The "helloasso" provider (Omniticket\HelloAsso\HelloAssoProvider) does not read attendees changed since a moment (its items have no such filter).

Errors

  • 401, 403 (the client refused, at the token or a call): InvalidKeyException; 404: NotFoundException; another status of 400 or more, or an answer that is not JSON: ProviderException, the status as its code.
  • attendees() with a date: NotSupportedException, before any call.
  • A network failure: UnreachableException.

Verified, and not

Tests/HelloAssoProviderTest.php, against answers composed from the field names of HelloAsso's OpenAPI (as its SDK documents its models), not recorded: the token (asked once, kept), events and their status, one event whole (tiers, free choice, free), registrations (valid, refunded through a payment, cancelled), checks, pages by continuation token, a refused client; BareTest. Green in the family's harness on 2026-10-26. Not run live: no HelloAsso account or sandbox was used.

Responsibility

This package is an independent, unofficial client, affiliated with HelloAsso in no way. Whoever runs it keeps HelloAsso's terms (helloasso.com/cgu, dev.helloasso.com); see the README.

Propose a change docs/index.md