diff --git a/src/Api.php b/src/Api.php
index 07405e5..0ab3eb9 100644
--- a/src/Api.php
+++ b/src/Api.php
@@ -58,13 +58,26 @@ class Api {
         return $this;
     }
 
+    public function memberModel($member): Model {
+        $eloquentClass = config('nami.models.member');
+        return $eloquentClass::findByNamiId($member['id']) ?: $this->fillFromOverview(new $eloquentClass);
+    }
+
+    public function membersOf($groupId): Collection {
+        return collect($this->http()->get(self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/flist')->json()['data']);
+    }
+
+    public function member($groupId, $memberId) {
+        return $this->http()->get(self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$groupId.'/'.$memberId)->json()['data'];
+    }
+
     public function hasGroup($groupId): bool {
         return $this->groups()->search(function($group) use ($groupId) {
             return $group->id == $groupId;
         }) !== false;
     }
 
-    public function groups($parentGroupId  = null): Collection {
+    public function groups($parentGroupId = null): Collection {
         $parentGroupId = $parentGroupId ?: 'root';
         return collect($this->http()->get(self::$url.'/ica/rest/nami/gruppierungen/filtered-for-navigation/gruppierung/node/'.$parentGroupId)->json()['data'])->map(function($group) {
             return Group::fromResponse($group);
diff --git a/src/Group.php b/src/Group.php
index 4fe5942..c8b75a5 100644
--- a/src/Group.php
+++ b/src/Group.php
@@ -25,4 +25,14 @@ class Group implements Arrayable {
         return Nami::subgroupsOf($this->id);
     }
 
+    public function members(): MemberCollection {
+        return new MemberCollection(Nami::membersOf($this->id)->map(function($member) {
+            return $this->member($member['id']);
+        }));
+    }
+
+    public function member($id): Member {
+        return Member::fromNami(Nami::member($this->id, $id));
+    }
+
 }
diff --git a/src/Member.php b/src/Member.php
new file mode 100644
index 0000000..3c5df3f
--- /dev/null
+++ b/src/Member.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Zoomyboy\LaravelNami;
+
+use \ArrayAccess;
+use Illuminate\Support\Arr;
+use Illuminate\Database\Eloquent\Concerns\HasAttributes;
+use Illuminate\Database\Eloquent\Concerns\HidesAttributes;
+use Illuminate\Contracts\Support\Arrayable;
+use Illuminate\Database\Eloquent\Model;
+
+class Member extends Model {
+
+    use HasAttributes;
+    use HidesAttributes;
+
+    protected static $overviewAttributes = [
+        'vorname' => 'firstname',
+        'nachname' => 'lastname',
+        'spitzname' => 'nickname',
+        'staatsangehoerigkeitText' => 'other_country',
+        'strasse' => 'address',
+        'nameZusatz' => 'further_address',
+        'plz' => 'zip',
+        'ort' => 'location',
+        'id' => 'id',
+        'telefon1' => 'main_phone',
+        'telefon2' => 'mobile_phone',
+        'telefon3' => 'work_phone',
+        'telefax' => 'fax',
+        'email' => 'email',
+        'emailVertretungsberechtigter' => 'email_parents'
+    ];
+
+    protected $guarded = [];
+
+    public static function fromNami($item) {
+        $item = collect($item)
+            ->only(array_keys(static::$overviewAttributes))
+            ->mapWithKeys(function($item, $key) {
+                return [ data_get(static::$overviewAttributes, $key, $key) => $item ];
+            })
+            ->toArray();
+
+        return (new self($item));
+    }
+
+    public function __construct($member) {
+        parent::__construct($member);
+    }
+
+}
diff --git a/src/MemberCollection.php b/src/MemberCollection.php
new file mode 100644
index 0000000..fa23d0d
--- /dev/null
+++ b/src/MemberCollection.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace Zoomyboy\LaravelNami;
+
+use Illuminate\Support\Collection;
+
+class MemberCollection extends Collection {
+
+    public static function fromOverview($items) {
+        $self = new self($items);
+
+        return $self->map(function($item) {
+            return Member::fromOverview($item);
+        });
+    }
+
+}
diff --git a/tests/Stub/Member.php b/tests/Stub/Member.php
new file mode 100644
index 0000000..b26c7e8
--- /dev/null
+++ b/tests/Stub/Member.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Zoomyboy\LaravelNami\Tests\Stub;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Member extends Model {
+    
+    public $fillable = [ 'firstname', 'nami_id' ];
+
+    public static function findByNamiId($id) {
+        return self::where('nami_id', $id)->first();
+    }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 32ae056..72001a5 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -4,6 +4,8 @@ namespace Zoomyboy\LaravelNami\Tests;
 
 use Illuminate\Support\Facades\Config;
 use Zoomyboy\LaravelNami\NamiServiceProvider;
+use Illuminate\Support\Facades\Http;
+use Zoomyboy\LaravelNami\Tests\Stub\Member;
 
 class TestCase extends \Orchestra\Testbench\TestCase
 {
@@ -26,4 +28,15 @@ class TestCase extends \Orchestra\Testbench\TestCase
         Config::set('nami.auth.groupid', '55555');
     }
 
+    public function login() {
+        return [
+            'https://nami.dpsg.de/ica/pages/login.jsp' => Http::response('<html></html>', 200),
+            'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup' => Http::response($this->successJson, 200)
+        ];
+    }
+
+    public function fakeJson($file) {
+        return file_get_contents(__DIR__.'/json/'.$file);
+    }
+
 }
diff --git a/tests/Unit/MemberFakeTest.php b/tests/Unit/MemberFakeTest.php
new file mode 100644
index 0000000..e69de29
diff --git a/tests/Unit/PullMemberTest.php b/tests/Unit/PullMemberTest.php
new file mode 100644
index 0000000..a6470c1
--- /dev/null
+++ b/tests/Unit/PullMemberTest.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Zoomyboy\LaravelNami\Tests\Unit;
+
+use Zoomyboy\LaravelNami\Nami;
+use Zoomyboy\LaravelNami\Tests\TestCase;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Config;
+use Zoomyboy\LaravelNami\NamiServiceProvider;
+use Zoomyboy\LaravelNami\LoginException;
+use Zoomyboy\LaravelNami\Group;
+
+class PullMemberTest extends TestCase
+{
+    public $groupsResponse = '{"success":true,"data":[{"descriptor":"Group","name":"","representedClass":"de.iconcept.nami.entity.org.Gruppierung","id":103}],"responseType":"OK"}';
+
+    public function dataProvider() {
+        return [
+            'firstname' => ['firstname', ['Max', 'Jane']],
+            'lastname' => ['lastname', ['Nach1', 'Nach2']],
+            'nickname' => ['nickname', ['spitz1', null]],
+            'other_country' => ['other_country', ['deutsch', null]],
+            'address' => ['address', ['straße 1', 'straße 2']],
+            'further_address' => ['further_address', ['addrz', null]],
+            'zip' => ['zip', [12345, 5555]],
+            'location' => ['location', ['SG', 'Köln']],
+            'main_phone' => ['main_phone', ['+49888', '+49668']],
+            'mobile_phone' => ['mobile_phone', ['+49176', '+49172']],
+            'work_phone' => ['work_phone', ['+11111', '+22222']],
+            'fax' => ['fax', ['+55111', '+55222']],
+            'email' => ['email', ['test@example.com', 'test2@example.com']],
+            'email_parents' => ['email_parents', ['testp@example.com', 'test2p@example.com']],
+        ];
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function test_get_a_single_member($key, $values) {
+        Http::fake(array_merge($this->login(), [
+            'https://nami.dpsg.de/ica/rest/nami/gruppierungen/filtered-for-navigation/gruppierung/node/root' => Http::response($this->groupsResponse, 200),
+            'https://nami.dpsg.de/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/103/16' => Http::response($this->fakeJson('member-16.json'), 200),
+            'https://nami.dpsg.de/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/103/17' => Http::response($this->fakeJson('member-17.json'), 200)
+        ]));
+
+        $this->setCredentials();
+
+        Nami::login();
+
+        $group = Nami::group(103);
+
+        $this->assertEquals($values[0], $group->member(16)->{$key});
+        $this->assertEquals($values[1], $group->member(17)->{$key});
+
+        Http::assertSentCount(5);
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function test_get_attribute_of_overview($key, $values) {
+        Http::fake(array_merge($this->login(), [
+            'https://nami.dpsg.de/ica/rest/nami/gruppierungen/filtered-for-navigation/gruppierung/node/root' => Http::response($this->groupsResponse, 200),
+            'https://nami.dpsg.de/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/103/flist' => Http::response($this->fakeJson('member_overview.json'), 200),
+            'https://nami.dpsg.de/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/103/16' => Http::response($this->fakeJson('member-16.json'), 200),
+            'https://nami.dpsg.de/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/103/17' => Http::response($this->fakeJson('member-17.json'), 200)
+        ]));
+
+        $this->setCredentials();
+
+        Nami::login();
+
+        $this->assertEquals([
+            16 => $values[0],
+            17 => $values[1]
+        ], Nami::group(103)->members()->pluck($key, 'id')->toArray());
+
+        Http::assertSentCount(6);
+    }
+
+}
diff --git a/tests/json/member-16.json b/tests/json/member-16.json
new file mode 100644
index 0000000..fa08b5a
--- /dev/null
+++ b/tests/json/member-16.json
@@ -0,0 +1,76 @@
+{
+    "success": true,
+    "data":
+    {
+        "jungpfadfinder": null,
+        "mglType": "Mitglied",
+        "geschlecht": "männlich",
+        "staatsangehoerigkeit": "deutsch",
+        "ersteTaetigkeitId": null,
+        "ersteUntergliederung": "Wölfling",
+        "emailVertretungsberechtigter": "testp@example.com",
+        "lastUpdated": "2020-06-28 02:15:24",
+        "ersteTaetigkeit": null,
+        "nameZusatz": "addrz",
+        "id": 16,
+        "staatsangehoerigkeitId": 1054,
+        "version": 58,
+        "sonst01": false,
+        "sonst02": false,
+        "spitzname": "spitz1",
+        "landId": 1,
+        "staatsangehoerigkeitText": "deutsch",
+        "gruppierungId": 100105,
+        "mglTypeId": "MITGLIED",
+        "beitragsart": "Voller Beitrag",
+        "nachname": "Nach1",
+        "eintrittsdatum": "2005-05-01 00:00:00",
+        "rover": null,
+        "region": "Nordrhein-Westfalen (Deutschland)",
+        "status": "Aktiv",
+        "konfession": null,
+        "fixBeitrag": null,
+        "konfessionId": null,
+        "zeitschriftenversand": true,
+        "pfadfinder": null,
+        "telefon3": "+11111",
+        "kontoverbindung":
+        {
+            "id": null,
+            "institut": null,
+            "bankleitzahl": null,
+            "kontonummer": null,
+            "iban": null,
+            "bic": null,
+            "kontoinhaber": null,
+            "mitgliedsNummer": null,
+            "zahlungsKonditionId": null,
+            "zahlungsKondition": null
+        },
+        "geschlechtId": 19,
+        "land": "Deutschland",
+        "email": "test@example.com",
+        "telefon1": "+49888",
+        "woelfling": null,
+        "telefon2": "+49176",
+        "strasse": "straße 1",
+        "vorname": "Max",
+        "mitgliedsNummer": 90166,
+        "gruppierung": "Solingen-Wald, Silva 100105",
+        "austrittsDatum": "",
+        "ort": "SG",
+        "ersteUntergliederungId": null,
+        "wiederverwendenFlag": false,
+        "regionId": 10,
+        "geburtsDatum": "1991-06-20 00:00:00",
+        "stufe": "Wölfling",
+        "genericField1": "",
+        "genericField2": "",
+        "telefax": "+55111",
+        "beitragsartId": 1,
+        "plz": "12345"
+    },
+    "responseType": null,
+    "message": null,
+    "title": null
+}
diff --git a/tests/json/member-17.json b/tests/json/member-17.json
new file mode 100644
index 0000000..11a2c8b
--- /dev/null
+++ b/tests/json/member-17.json
@@ -0,0 +1,76 @@
+{
+    "success": true,
+    "data":
+    {
+        "jungpfadfinder": null,
+        "mglType": "Mitglied",
+        "geschlecht": "männlich",
+        "staatsangehoerigkeit": "deutsch",
+        "ersteTaetigkeitId": null,
+        "ersteUntergliederung": null,
+        "emailVertretungsberechtigter": "test2p@example.com",
+        "lastUpdated": "2015-02-03 15:20:07",
+        "ersteTaetigkeit": null,
+        "nameZusatz": "",
+        "id": 17,
+        "staatsangehoerigkeitId": 1054,
+        "version": 17,
+        "sonst01": false,
+        "sonst02": false,
+        "spitzname": "",
+        "landId": 1,
+        "staatsangehoerigkeitText": "",
+        "gruppierungId": 100105,
+        "mglTypeId": "MITGLIED",
+        "beitragsart": "Voller Beitrag",
+        "nachname": "Nach2",
+        "eintrittsdatum": "2003-11-17 00:00:00",
+        "rover": null,
+        "region": "Nordrhein-Westfalen (Deutschland)",
+        "status": "Aktiv",
+        "konfession": null,
+        "fixBeitrag": null,
+        "konfessionId": null,
+        "zeitschriftenversand": true,
+        "pfadfinder": null,
+        "telefon3": "+22222",
+        "kontoverbindung":
+        {
+            "id": null,
+            "institut": null,
+            "bankleitzahl": null,
+            "kontonummer": null,
+            "iban": null,
+            "bic": null,
+            "kontoinhaber": null,
+            "mitgliedsNummer": null,
+            "zahlungsKonditionId": null,
+            "zahlungsKondition": null
+        },
+        "geschlechtId": 19,
+        "land": "Deutschland",
+        "email": "test2@example.com",
+        "telefon1": "+49668",
+        "woelfling": null,
+        "telefon2": "+49172",
+        "strasse": "straße 2",
+        "vorname": "Jane",
+        "mitgliedsNummer": 90141,
+        "gruppierung": "Solingen-Wald, Silva 100105",
+        "austrittsDatum": "",
+        "ort": "Köln",
+        "ersteUntergliederungId": null,
+        "wiederverwendenFlag": false,
+        "regionId": 10,
+        "geburtsDatum": "1984-01-17 00:00:00",
+        "stufe": null,
+        "genericField1": null,
+        "genericField2": null,
+        "telefax": "+55222",
+        "beitragsartId": 1,
+        "plz": "5555"
+    },
+    "responseType": null,
+    "message": null,
+    "title": null
+}
diff --git a/tests/json/member_overview.json b/tests/json/member_overview.json
new file mode 100644
index 0000000..dc383ff
--- /dev/null
+++ b/tests/json/member_overview.json
@@ -0,0 +1,58 @@
+{
+    "success": true,
+    "data": [
+        {
+            "id": 16
+        },
+        {
+            "id": 17
+        }
+    ],
+    "responseType": "OK",
+    "totalEntries": 25,
+    "metaData": {
+        "totalProperty": "totalEntries",
+        "root": "data",
+        "id": "id",
+        "fields": [
+            {"name":"id","header":null,"hidden":false,"width":80},
+            {"name":"descriptor","header":null,"hidden":false,"flex":3},
+            {"name":"entries_geschlecht","header":null,"hidden":false,"flex":3},
+            {"name":"entries_staatangehoerigkeitText","header":null,"hidden":false,"flex":3},
+            {"name":"entries_lastUpdated","header":null,"hidden":false,"flex":3},
+            {"name":"entries_id","header":null,"hidden":true,"flex":3},
+            {"name":"entries_version","header":null,"hidden":false,"flex":3},
+            {"name":"entries_spitzname","header":null,"hidden":false,"flex":3},
+            {"name":"entries_nachname","header":null,"hidden":false,"flex":3},
+            {"name":"entries_eintrittsdatum","header":null,"hidden":false,"flex":3},
+            {"name":"entries_rover","header":null,"hidden":false,"flex":3},
+            {"name":"entries_status","header":null,"hidden":false,"flex":3},
+            {"name":"entries_fixBeitrag","header":null,"hidden":false,"flex":3},
+            {"name":"entries_pfadfinder","header":null,"hidden":false,"flex":3},
+            {"name":"entries_telefon3","header":null,"hidden":false,"flex":3},
+            {"name":"entries_kontoverbindung","header":null,"hidden":false,"flex":3},
+            {"name":"entries_email","header":null,"hidden":false,"flex":3},
+            {"name":"entries_telefon1","header":null,"hidden":false,"flex":3},
+            {"name":"entries_woelfling","header":null,"hidden":false,"flex":3},
+            {"name":"entries_telefon2","header":null,"hidden":false,"flex":3},
+            {"name":"entries_beitragsarten","header":null,"hidden":false,"flex":3},
+            {"name":"entries_austrittsDatum","header":null,"hidden":true,"flex":3},
+            {"name":"entries_stufe","header":null,"hidden":false,"flex":3},
+            {"name":"entries_genericField1","header":null,"hidden":true,"flex":3},
+            {"name":"entries_genericField2","header":null,"hidden":true,"flex":3},
+            {"name":"entries_jungpfadfinder","header":null,"hidden":false,"flex":3},
+            {"name":"entries_mglType","header":null,"hidden":false,"flex":3},
+            {"name":"entries_staatsangehoerigkeit","header":null,"hidden":false,"flex":3},
+            {"name":"entries_ersteTaetigkeitId","header":null,"hidden":false,"flex":3},
+            {"name":"entries_emailVertretungsberechtigter","header":null,"hidden":false,"flex":3},
+            {"name":"entries_konfession","header":null,"hidden":false,"flex":3},
+            {"name":"entries_rowCssClass","header":null,"hidden":false,"flex":3},
+            {"name":"entries_vorname","header":null,"hidden":false,"flex":3},
+            {"name":"entries_mitgliedsNummer","header":null,"hidden":false,"flex":3},
+            {"name":"entries_ersteUntergliederungId","header":null,"hidden":false,"flex":3},
+            {"name":"entries_wiederverwendenFlag","header":null,"hidden":false,"flex":3},
+            {"name":"entries_geburtsDatum","header":null,"hidden":false,"flex":3},
+            {"name":"entries_telefax","header":null,"hidden":false,"flex":3}
+        ]
+    }
+}